Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
cloud-kernel
提交
fd33c436
cloud-kernel
项目概览
openanolis
/
cloud-kernel
大约 1 年 前同步成功
通知
158
Star
36
Fork
7
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
10
列表
看板
标记
里程碑
合并请求
2
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
cloud-kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
10
Issue
10
列表
看板
标记
里程碑
合并请求
2
合并请求
2
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
fd33c436
编写于
7月 19, 2014
作者:
J
James Morris
浏览文件
操作
浏览文件
下载
差异文件
Merge tag 'seccomp-3.17' of
git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
into next
上级
2ccf4661
c2e1f2e3
变更
22
显示空白变更内容
内联
并排
Showing
22 changed file
with
471 addition
and
80 deletion
+471
-80
MAINTAINERS
MAINTAINERS
+10
-0
arch/Kconfig
arch/Kconfig
+1
-0
arch/arm/include/uapi/asm/unistd.h
arch/arm/include/uapi/asm/unistd.h
+1
-0
arch/arm/kernel/calls.S
arch/arm/kernel/calls.S
+1
-0
arch/mips/include/uapi/asm/unistd.h
arch/mips/include/uapi/asm/unistd.h
+9
-6
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall32-o32.S
+1
-0
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-64.S
+1
-0
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-n32.S
+1
-0
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/scall64-o32.S
+1
-0
arch/x86/syscalls/syscall_32.tbl
arch/x86/syscalls/syscall_32.tbl
+1
-0
arch/x86/syscalls/syscall_64.tbl
arch/x86/syscalls/syscall_64.tbl
+1
-0
fs/exec.c
fs/exec.c
+3
-3
include/linux/sched.h
include/linux/sched.h
+15
-3
include/linux/seccomp.h
include/linux/seccomp.h
+5
-3
include/linux/syscalls.h
include/linux/syscalls.h
+2
-0
include/uapi/asm-generic/unistd.h
include/uapi/asm-generic/unistd.h
+3
-1
include/uapi/linux/seccomp.h
include/uapi/linux/seccomp.h
+7
-0
kernel/fork.c
kernel/fork.c
+48
-1
kernel/seccomp.c
kernel/seccomp.c
+353
-59
kernel/sys.c
kernel/sys.c
+2
-2
kernel/sys_ni.c
kernel/sys_ni.c
+3
-0
security/apparmor/domain.c
security/apparmor/domain.c
+2
-2
未找到文件。
MAINTAINERS
浏览文件 @
fd33c436
...
...
@@ -7953,6 +7953,16 @@ S: Maintained
F: drivers/mmc/host/sdhci.*
F: drivers/mmc/host/sdhci-pltfm.[ch]
SECURE COMPUTING
M: Kees Cook <keescook@chromium.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
S: Supported
F: kernel/seccomp.c
F: include/uapi/linux/seccomp.h
F: include/linux/seccomp.h
K: \bsecure_computing
K: \bTIF_SECCOMP\b
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
M: Anton Vorontsov <anton@enomsg.org>
L: linuxppc-dev@lists.ozlabs.org
...
...
arch/Kconfig
浏览文件 @
fd33c436
...
...
@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
- secure_computing is called from a ptrace_event()-safe context
- secure_computing return value is checked and a return value of -1
results in the system call being skipped immediately.
- seccomp syscall wired up
config SECCOMP_FILTER
def_bool y
...
...
arch/arm/include/uapi/asm/unistd.h
浏览文件 @
fd33c436
...
...
@@ -409,6 +409,7 @@
#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
#define __NR_seccomp (__NR_SYSCALL_BASE+383)
/*
* This may need to be greater than __NR_last_syscall+1 in order to
...
...
arch/arm/kernel/calls.S
浏览文件 @
fd33c436
...
...
@@ -392,6 +392,7 @@
/*
380
*/
CALL
(
sys_sched_setattr
)
CALL
(
sys_sched_getattr
)
CALL
(
sys_renameat2
)
CALL
(
sys_seccomp
)
#ifndef syscalls_counted
.
equ
syscalls_padding
,
((
NR_syscalls
+
3
)
&
~
3
)
-
NR_syscalls
#define syscalls_counted
...
...
arch/mips/include/uapi/asm/unistd.h
浏览文件 @
fd33c436
...
...
@@ -372,16 +372,17 @@
#define __NR_sched_setattr (__NR_Linux + 349)
#define __NR_sched_getattr (__NR_Linux + 350)
#define __NR_renameat2 (__NR_Linux + 351)
#define __NR_seccomp (__NR_Linux + 352)
/*
* Offset of the last Linux o32 flavoured syscall
*/
#define __NR_Linux_syscalls 35
1
#define __NR_Linux_syscalls 35
2
#endif
/* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000
#define __NR_O32_Linux_syscalls 35
1
#define __NR_O32_Linux_syscalls 35
2
#if _MIPS_SIM == _MIPS_SIM_ABI64
...
...
@@ -701,16 +702,17 @@
#define __NR_sched_setattr (__NR_Linux + 309)
#define __NR_sched_getattr (__NR_Linux + 310)
#define __NR_renameat2 (__NR_Linux + 311)
#define __NR_seccomp (__NR_Linux + 312)
/*
* Offset of the last Linux 64-bit flavoured syscall
*/
#define __NR_Linux_syscalls 31
1
#define __NR_Linux_syscalls 31
2
#endif
/* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000
#define __NR_64_Linux_syscalls 31
1
#define __NR_64_Linux_syscalls 31
2
#if _MIPS_SIM == _MIPS_SIM_NABI32
...
...
@@ -1034,15 +1036,16 @@
#define __NR_sched_setattr (__NR_Linux + 313)
#define __NR_sched_getattr (__NR_Linux + 314)
#define __NR_renameat2 (__NR_Linux + 315)
#define __NR_seccomp (__NR_Linux + 316)
/*
* Offset of the last N32 flavoured syscall
*/
#define __NR_Linux_syscalls 31
5
#define __NR_Linux_syscalls 31
6
#endif
/* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
#define __NR_N32_Linux_syscalls 31
5
#define __NR_N32_Linux_syscalls 31
6
#endif
/* _UAPI_ASM_UNISTD_H */
arch/mips/kernel/scall32-o32.S
浏览文件 @
fd33c436
...
...
@@ -578,3 +578,4 @@ EXPORT(sys_call_table)
PTR
sys_sched_setattr
PTR
sys_sched_getattr
/*
4350
*/
PTR
sys_renameat2
PTR
sys_seccomp
arch/mips/kernel/scall64-64.S
浏览文件 @
fd33c436
...
...
@@ -431,4 +431,5 @@ EXPORT(sys_call_table)
PTR
sys_sched_setattr
PTR
sys_sched_getattr
/*
5310
*/
PTR
sys_renameat2
PTR
sys_seccomp
.
size
sys_call_table
,
.
-
sys_call_table
arch/mips/kernel/scall64-n32.S
浏览文件 @
fd33c436
...
...
@@ -424,4 +424,5 @@ EXPORT(sysn32_call_table)
PTR
sys_sched_setattr
PTR
sys_sched_getattr
PTR
sys_renameat2
/*
6315
*/
PTR
sys_seccomp
.
size
sysn32_call_table
,
.
-
sysn32_call_table
arch/mips/kernel/scall64-o32.S
浏览文件 @
fd33c436
...
...
@@ -557,4 +557,5 @@ EXPORT(sys32_call_table)
PTR
sys_sched_setattr
PTR
sys_sched_getattr
/*
4350
*/
PTR
sys_renameat2
PTR
sys_seccomp
.
size
sys32_call_table
,
.
-
sys32_call_table
arch/x86/syscalls/syscall_32.tbl
浏览文件 @
fd33c436
...
...
@@ -360,3 +360,4 @@
351 i386 sched_setattr sys_sched_setattr
352 i386 sched_getattr sys_sched_getattr
353 i386 renameat2 sys_renameat2
354 i386 seccomp sys_seccomp
arch/x86/syscalls/syscall_64.tbl
浏览文件 @
fd33c436
...
...
@@ -323,6 +323,7 @@
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
#
# x32-specific system call numbers start at 512 to avoid cache impact
...
...
fs/exec.c
浏览文件 @
fd33c436
...
...
@@ -1216,7 +1216,7 @@ EXPORT_SYMBOL(install_exec_creds);
/*
* determine how safe it is to execute the proposed program
* - the caller must hold ->cred_guard_mutex to protect against
* PTRACE_ATTACH
* PTRACE_ATTACH
or seccomp thread-sync
*/
static
void
check_unsafe_exec
(
struct
linux_binprm
*
bprm
)
{
...
...
@@ -1234,7 +1234,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
* This isn't strictly necessary, but it makes it harder for LSMs to
* mess up.
*/
if
(
current
->
no_new_privs
)
if
(
task_no_new_privs
(
current
)
)
bprm
->
unsafe
|=
LSM_UNSAFE_NO_NEW_PRIVS
;
t
=
p
;
...
...
@@ -1272,7 +1272,7 @@ int prepare_binprm(struct linux_binprm *bprm)
bprm
->
cred
->
egid
=
current_egid
();
if
(
!
(
bprm
->
file
->
f_path
.
mnt
->
mnt_flags
&
MNT_NOSUID
)
&&
!
current
->
no_new_privs
&&
!
task_no_new_privs
(
current
)
&&
kuid_has_mapping
(
bprm
->
cred
->
user_ns
,
inode
->
i_uid
)
&&
kgid_has_mapping
(
bprm
->
cred
->
user_ns
,
inode
->
i_gid
))
{
/* Set-uid? */
...
...
include/linux/sched.h
浏览文件 @
fd33c436
...
...
@@ -1307,13 +1307,12 @@ struct task_struct {
* execve */
unsigned
in_iowait
:
1
;
/* task may not gain privileges */
unsigned
no_new_privs
:
1
;
/* Revert to default priority/policy when forking */
unsigned
sched_reset_on_fork
:
1
;
unsigned
sched_contributes_to_load
:
1
;
unsigned
long
atomic_flags
;
/* Flags needing atomic access. */
pid_t
pid
;
pid_t
tgid
;
...
...
@@ -1967,6 +1966,19 @@ static inline void memalloc_noio_restore(unsigned int flags)
current
->
flags
=
(
current
->
flags
&
~
PF_MEMALLOC_NOIO
)
|
flags
;
}
/* Per-process atomic flags. */
#define PFA_NO_NEW_PRIVS 0x00000001
/* May not gain new privileges. */
static
inline
bool
task_no_new_privs
(
struct
task_struct
*
p
)
{
return
test_bit
(
PFA_NO_NEW_PRIVS
,
&
p
->
atomic_flags
);
}
static
inline
void
task_set_no_new_privs
(
struct
task_struct
*
p
)
{
set_bit
(
PFA_NO_NEW_PRIVS
,
&
p
->
atomic_flags
);
}
/*
* task->jobctl flags
*/
...
...
include/linux/seccomp.h
浏览文件 @
fd33c436
...
...
@@ -3,6 +3,8 @@
#include <uapi/linux/seccomp.h>
#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC)
#ifdef CONFIG_SECCOMP
#include <linux/thread_info.h>
...
...
@@ -14,11 +16,11 @@ struct seccomp_filter;
*
* @mode: indicates one of the valid values above for controlled
* system calls available to a process.
* @filter:
The metadata and ruleset for determining what system call
s
* a
re allowed for a task
.
* @filter:
must always point to a valid seccomp-filter or NULL as it i
s
* a
ccessed without locking during system call entry
.
*
* @filter must only be accessed from the context of current as there
* is no locking.
* is no
read
locking.
*/
struct
seccomp
{
int
mode
;
...
...
include/linux/syscalls.h
浏览文件 @
fd33c436
...
...
@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
asmlinkage
long
sys_kcmp
(
pid_t
pid1
,
pid_t
pid2
,
int
type
,
unsigned
long
idx1
,
unsigned
long
idx2
);
asmlinkage
long
sys_finit_module
(
int
fd
,
const
char
__user
*
uargs
,
int
flags
);
asmlinkage
long
sys_seccomp
(
unsigned
int
op
,
unsigned
int
flags
,
const
char
__user
*
uargs
);
#endif
include/uapi/asm-generic/unistd.h
浏览文件 @
fd33c436
...
...
@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
__SYSCALL
(
__NR_sched_getattr
,
sys_sched_getattr
)
#define __NR_renameat2 276
__SYSCALL
(
__NR_renameat2
,
sys_renameat2
)
#define __NR_seccomp 277
__SYSCALL
(
__NR_seccomp
,
sys_seccomp
)
#undef __NR_syscalls
#define __NR_syscalls 27
7
#define __NR_syscalls 27
8
/*
* All syscalls below here should go away really,
...
...
include/uapi/linux/seccomp.h
浏览文件 @
fd33c436
...
...
@@ -10,6 +10,13 @@
#define SECCOMP_MODE_STRICT 1
/* uses hard-coded filter. */
#define SECCOMP_MODE_FILTER 2
/* uses user-supplied filter. */
/* Valid operations for seccomp syscall. */
#define SECCOMP_SET_MODE_STRICT 0
#define SECCOMP_SET_MODE_FILTER 1
/* Valid flags for SECCOMP_SET_MODE_FILTER */
#define SECCOMP_FILTER_FLAG_TSYNC 1
/*
* All BPF programs must return a 32-bit value.
* The bottom 16-bits are for optional return data.
...
...
kernel/fork.c
浏览文件 @
fd33c436
...
...
@@ -315,6 +315,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
goto
free_ti
;
tsk
->
stack
=
ti
;
#ifdef CONFIG_SECCOMP
/*
* We must handle setting up seccomp filters once we're under
* the sighand lock in case orig has changed between now and
* then. Until then, filter must be NULL to avoid messing up
* the usage counts on the error path calling free_task.
*/
tsk
->
seccomp
.
filter
=
NULL
;
#endif
setup_thread_stack
(
tsk
,
orig
);
clear_user_return_notifier
(
tsk
);
...
...
@@ -1081,6 +1090,39 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
return
0
;
}
static
void
copy_seccomp
(
struct
task_struct
*
p
)
{
#ifdef CONFIG_SECCOMP
/*
* Must be called with sighand->lock held, which is common to
* all threads in the group. Holding cred_guard_mutex is not
* needed because this new task is not yet running and cannot
* be racing exec.
*/
BUG_ON
(
!
spin_is_locked
(
&
current
->
sighand
->
siglock
));
/* Ref-count the new filter user, and assign it. */
get_seccomp_filter
(
current
);
p
->
seccomp
=
current
->
seccomp
;
/*
* Explicitly enable no_new_privs here in case it got set
* between the task_struct being duplicated and holding the
* sighand lock. The seccomp state and nnp must be in sync.
*/
if
(
task_no_new_privs
(
current
))
task_set_no_new_privs
(
p
);
/*
* If the parent gained a seccomp mode after copying thread
* flags and between before we held the sighand lock, we have
* to manually enable the seccomp thread flag here.
*/
if
(
p
->
seccomp
.
mode
!=
SECCOMP_MODE_DISABLED
)
set_tsk_thread_flag
(
p
,
TIF_SECCOMP
);
#endif
}
SYSCALL_DEFINE1
(
set_tid_address
,
int
__user
*
,
tidptr
)
{
current
->
clear_child_tid
=
tidptr
;
...
...
@@ -1196,7 +1238,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto
fork_out
;
ftrace_graph_init_task
(
p
);
get_seccomp_filter
(
p
);
rt_mutex_init_task
(
p
);
...
...
@@ -1436,6 +1477,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
spin_lock
(
&
current
->
sighand
->
siglock
);
/*
* Copy seccomp details explicitly here, in case they were changed
* before holding sighand lock.
*/
copy_seccomp
(
p
);
/*
* Process group and session signals need to be delivered to just the
* parent before the fork or both the parent and the child after the
...
...
kernel/seccomp.c
浏览文件 @
fd33c436
...
...
@@ -18,15 +18,17 @@
#include <linux/compat.h>
#include <linux/sched.h>
#include <linux/seccomp.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
/* #define SECCOMP_DEBUG 1 */
#ifdef CONFIG_SECCOMP_FILTER
#include <asm/syscall.h>
#include <linux/filter.h>
#include <linux/pid.h>
#include <linux/ptrace.h>
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/tracehook.h>
#include <linux/uaccess.h>
...
...
@@ -172,21 +174,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
*/
static
u32
seccomp_run_filters
(
int
syscall
)
{
struct
seccomp_filter
*
f
;
struct
seccomp_filter
*
f
=
ACCESS_ONCE
(
current
->
seccomp
.
filter
)
;
struct
seccomp_data
sd
;
u32
ret
=
SECCOMP_RET_ALLOW
;
/* Ensure unexpected behavior doesn't result in failing open. */
if
(
WARN_ON
(
current
->
seccomp
.
filter
==
NULL
))
if
(
unlikely
(
WARN_ON
(
f
==
NULL
)
))
return
SECCOMP_RET_KILL
;
/* Make sure cross-thread synced filter points somewhere sane. */
smp_read_barrier_depends
();
populate_seccomp_data
(
&
sd
);
/*
* All filters in the list are evaluated and the lowest BPF return
* value always takes priority (ignoring the DATA).
*/
for
(
f
=
current
->
seccomp
.
filter
;
f
;
f
=
f
->
prev
)
{
for
(;
f
;
f
=
f
->
prev
)
{
u32
cur_ret
=
SK_RUN_FILTER
(
f
->
prog
,
(
void
*
)
&
sd
);
if
((
cur_ret
&
SECCOMP_RET_ACTION
)
<
(
ret
&
SECCOMP_RET_ACTION
))
...
...
@@ -194,29 +199,159 @@ static u32 seccomp_run_filters(int syscall)
}
return
ret
;
}
#endif
/* CONFIG_SECCOMP_FILTER */
static
inline
bool
seccomp_may_assign_mode
(
unsigned
long
seccomp_mode
)
{
BUG_ON
(
!
spin_is_locked
(
&
current
->
sighand
->
siglock
));
if
(
current
->
seccomp
.
mode
&&
current
->
seccomp
.
mode
!=
seccomp_mode
)
return
false
;
return
true
;
}
static
inline
void
seccomp_assign_mode
(
struct
task_struct
*
task
,
unsigned
long
seccomp_mode
)
{
BUG_ON
(
!
spin_is_locked
(
&
task
->
sighand
->
siglock
));
task
->
seccomp
.
mode
=
seccomp_mode
;
/*
* Make sure TIF_SECCOMP cannot be set before the mode (and
* filter) is set.
*/
smp_mb__before_atomic
();
set_tsk_thread_flag
(
task
,
TIF_SECCOMP
);
}
#ifdef CONFIG_SECCOMP_FILTER
/* Returns 1 if the parent is an ancestor of the child. */
static
int
is_ancestor
(
struct
seccomp_filter
*
parent
,
struct
seccomp_filter
*
child
)
{
/* NULL is the root ancestor. */
if
(
parent
==
NULL
)
return
1
;
for
(;
child
;
child
=
child
->
prev
)
if
(
child
==
parent
)
return
1
;
return
0
;
}
/**
* seccomp_can_sync_threads: checks if all threads can be synchronized
*
* Expects sighand and cred_guard_mutex locks to be held.
*
* Returns 0 on success, -ve on error, or the pid of a thread which was
* either not in the correct seccomp mode or it did not have an ancestral
* seccomp filter.
*/
static
inline
pid_t
seccomp_can_sync_threads
(
void
)
{
struct
task_struct
*
thread
,
*
caller
;
BUG_ON
(
!
mutex_is_locked
(
&
current
->
signal
->
cred_guard_mutex
));
BUG_ON
(
!
spin_is_locked
(
&
current
->
sighand
->
siglock
));
/* Validate all threads being eligible for synchronization. */
caller
=
current
;
for_each_thread
(
caller
,
thread
)
{
pid_t
failed
;
/* Skip current, since it is initiating the sync. */
if
(
thread
==
caller
)
continue
;
if
(
thread
->
seccomp
.
mode
==
SECCOMP_MODE_DISABLED
||
(
thread
->
seccomp
.
mode
==
SECCOMP_MODE_FILTER
&&
is_ancestor
(
thread
->
seccomp
.
filter
,
caller
->
seccomp
.
filter
)))
continue
;
/* Return the first thread that cannot be synchronized. */
failed
=
task_pid_vnr
(
thread
);
/* If the pid cannot be resolved, then return -ESRCH */
if
(
unlikely
(
WARN_ON
(
failed
==
0
)))
failed
=
-
ESRCH
;
return
failed
;
}
return
0
;
}
/**
* seccomp_sync_threads: sets all threads to use current's filter
*
* Expects sighand and cred_guard_mutex locks to be held, and for
* seccomp_can_sync_threads() to have returned success already
* without dropping the locks.
*
*/
static
inline
void
seccomp_sync_threads
(
void
)
{
struct
task_struct
*
thread
,
*
caller
;
BUG_ON
(
!
mutex_is_locked
(
&
current
->
signal
->
cred_guard_mutex
));
BUG_ON
(
!
spin_is_locked
(
&
current
->
sighand
->
siglock
));
/* Synchronize all threads. */
caller
=
current
;
for_each_thread
(
caller
,
thread
)
{
/* Skip current, since it needs no changes. */
if
(
thread
==
caller
)
continue
;
/* Get a task reference for the new leaf node. */
get_seccomp_filter
(
caller
);
/*
* Drop the task reference to the shared ancestor since
* current's path will hold a reference. (This also
* allows a put before the assignment.)
*/
put_seccomp_filter
(
thread
);
smp_store_release
(
&
thread
->
seccomp
.
filter
,
caller
->
seccomp
.
filter
);
/*
* Opt the other thread into seccomp if needed.
* As threads are considered to be trust-realm
* equivalent (see ptrace_may_access), it is safe to
* allow one thread to transition the other.
*/
if
(
thread
->
seccomp
.
mode
==
SECCOMP_MODE_DISABLED
)
{
/*
* Don't let an unprivileged task work around
* the no_new_privs restriction by creating
* a thread that sets it up, enters seccomp,
* then dies.
*/
if
(
task_no_new_privs
(
caller
))
task_set_no_new_privs
(
thread
);
seccomp_assign_mode
(
thread
,
SECCOMP_MODE_FILTER
);
}
}
}
/**
* seccomp_
attach_filter: Attaches a seccomp filter to current
.
* seccomp_
prepare_filter: Prepares a seccomp filter for use
.
* @fprog: BPF program to install
*
* Returns
0 on success or an errno
on failure.
* Returns
filter on success or an ERR_PTR
on failure.
*/
static
long
seccomp_attach
_filter
(
struct
sock_fprog
*
fprog
)
static
struct
seccomp_filter
*
seccomp_prepare
_filter
(
struct
sock_fprog
*
fprog
)
{
struct
seccomp_filter
*
filter
;
unsigned
long
fp_size
=
fprog
->
len
*
sizeof
(
struct
sock_filter
);
unsigned
long
total_insns
=
fprog
->
len
;
unsigned
long
fp_size
;
struct
sock_filter
*
fp
;
int
new_len
;
long
ret
;
if
(
fprog
->
len
==
0
||
fprog
->
len
>
BPF_MAXINSNS
)
return
-
EINVAL
;
for
(
filter
=
current
->
seccomp
.
filter
;
filter
;
filter
=
filter
->
prev
)
total_insns
+=
filter
->
prog
->
len
+
4
;
/* include a 4 instr penalty */
if
(
total_insns
>
MAX_INSNS_PER_PATH
)
return
-
ENOMEM
;
return
ERR_PTR
(
-
EINVAL
);
BUG_ON
(
INT_MAX
/
fprog
->
len
<
sizeof
(
struct
sock_filter
));
fp_size
=
fprog
->
len
*
sizeof
(
struct
sock_filter
);
/*
* Installing a seccomp filter requires that the task has
...
...
@@ -224,14 +359,14 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
* This avoids scenarios where unprivileged tasks can affect the
* behavior of privileged children.
*/
if
(
!
current
->
no_new_privs
&&
if
(
!
task_no_new_privs
(
current
)
&&
security_capable_noaudit
(
current_cred
(),
current_user_ns
(),
CAP_SYS_ADMIN
)
!=
0
)
return
-
EACCES
;
return
ERR_PTR
(
-
EACCES
)
;
fp
=
kzalloc
(
fp_size
,
GFP_KERNEL
|
__GFP_NOWARN
);
if
(
!
fp
)
return
-
ENOMEM
;
return
ERR_PTR
(
-
ENOMEM
)
;
/* Copy the instructions from fprog. */
ret
=
-
EFAULT
;
...
...
@@ -275,13 +410,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
sk_filter_select_runtime
(
filter
->
prog
);
/*
* If there is an existing filter, make it the prev and don't drop its
* task reference.
*/
filter
->
prev
=
current
->
seccomp
.
filter
;
current
->
seccomp
.
filter
=
filter
;
return
0
;
return
filter
;
free_filter_prog:
kfree
(
filter
->
prog
);
...
...
@@ -289,19 +418,20 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
kfree
(
filter
);
free_prog:
kfree
(
fp
);
return
ret
;
return
ERR_PTR
(
ret
)
;
}
/**
* seccomp_
attach_user_filter - attach
es a user-supplied sock_fprog
* seccomp_
prepare_user_filter - prepar
es a user-supplied sock_fprog
* @user_filter: pointer to the user data containing a sock_fprog.
*
* Returns 0 on success and non-zero otherwise.
*/
static
long
seccomp_attach_user_filter
(
char
__user
*
user_filter
)
static
struct
seccomp_filter
*
seccomp_prepare_user_filter
(
const
char
__user
*
user_filter
)
{
struct
sock_fprog
fprog
;
long
ret
=
-
EFAULT
;
struct
seccomp_filter
*
filter
=
ERR_PTR
(
-
EFAULT
)
;
#ifdef CONFIG_COMPAT
if
(
is_compat_task
())
{
...
...
@@ -314,9 +444,56 @@ static long seccomp_attach_user_filter(char __user *user_filter)
#endif
if
(
copy_from_user
(
&
fprog
,
user_filter
,
sizeof
(
fprog
)))
goto
out
;
ret
=
seccomp_attach
_filter
(
&
fprog
);
filter
=
seccomp_prepare
_filter
(
&
fprog
);
out:
return
filter
;
}
/**
* seccomp_attach_filter: validate and attach filter
* @flags: flags to change filter behavior
* @filter: seccomp filter to add to the current process
*
* Caller must be holding current->sighand->siglock lock.
*
* Returns 0 on success, -ve on error.
*/
static
long
seccomp_attach_filter
(
unsigned
int
flags
,
struct
seccomp_filter
*
filter
)
{
unsigned
long
total_insns
;
struct
seccomp_filter
*
walker
;
BUG_ON
(
!
spin_is_locked
(
&
current
->
sighand
->
siglock
));
/* Validate resulting filter length. */
total_insns
=
filter
->
prog
->
len
;
for
(
walker
=
current
->
seccomp
.
filter
;
walker
;
walker
=
walker
->
prev
)
total_insns
+=
walker
->
prog
->
len
+
4
;
/* 4 instr penalty */
if
(
total_insns
>
MAX_INSNS_PER_PATH
)
return
-
ENOMEM
;
/* If thread sync has been requested, check that it is possible. */
if
(
flags
&
SECCOMP_FILTER_FLAG_TSYNC
)
{
int
ret
;
ret
=
seccomp_can_sync_threads
();
if
(
ret
)
return
ret
;
}
/*
* If there is an existing filter, make it the prev and don't drop its
* task reference.
*/
filter
->
prev
=
current
->
seccomp
.
filter
;
current
->
seccomp
.
filter
=
filter
;
/* Now that the new filter is in place, synchronize to all threads. */
if
(
flags
&
SECCOMP_FILTER_FLAG_TSYNC
)
seccomp_sync_threads
();
return
0
;
}
/* get_seccomp_filter - increments the reference count of the filter on @tsk */
...
...
@@ -329,6 +506,14 @@ void get_seccomp_filter(struct task_struct *tsk)
atomic_inc
(
&
orig
->
usage
);
}
static
inline
void
seccomp_filter_free
(
struct
seccomp_filter
*
filter
)
{
if
(
filter
)
{
sk_filter_free
(
filter
->
prog
);
kfree
(
filter
);
}
}
/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
void
put_seccomp_filter
(
struct
task_struct
*
tsk
)
{
...
...
@@ -337,8 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk)
while
(
orig
&&
atomic_dec_and_test
(
&
orig
->
usage
))
{
struct
seccomp_filter
*
freeme
=
orig
;
orig
=
orig
->
prev
;
sk_filter_free
(
freeme
->
prog
);
kfree
(
freeme
);
seccomp_filter_free
(
freeme
);
}
}
...
...
@@ -382,12 +566,17 @@ static int mode1_syscalls_32[] = {
int
__secure_computing
(
int
this_syscall
)
{
int
mode
=
current
->
seccomp
.
mode
;
int
exit_sig
=
0
;
int
*
syscall
;
u32
ret
;
switch
(
mode
)
{
/*
* Make sure that any changes to mode from another thread have
* been seen after TIF_SECCOMP was seen.
*/
rmb
();
switch
(
current
->
seccomp
.
mode
)
{
case
SECCOMP_MODE_STRICT
:
syscall
=
mode1_syscalls
;
#ifdef CONFIG_COMPAT
...
...
@@ -473,47 +662,152 @@ long prctl_get_seccomp(void)
}
/**
* prctl_set_seccomp: configures current->seccomp.mode
* @seccomp_mode: requested mode to use
* @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
*
* This function may be called repeatedly with a @seccomp_mode of
* SECCOMP_MODE_FILTER to install additional filters. Every filter
* successfully installed will be evaluated (in reverse order) for each system
* call the task makes.
* seccomp_set_mode_strict: internal function for setting strict seccomp
*
* Once current->seccomp.mode is non-zero, it may not be changed.
*
* Returns 0 on success or -EINVAL on failure.
*/
long
prctl_set_seccomp
(
unsigned
long
seccomp_mode
,
char
__user
*
filter
)
static
long
seccomp_set_mode_strict
(
void
)
{
const
unsigned
long
seccomp_mode
=
SECCOMP_MODE_STRICT
;
long
ret
=
-
EINVAL
;
if
(
current
->
seccomp
.
mode
&&
current
->
seccomp
.
mode
!=
seccomp_mode
)
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
if
(
!
seccomp_may_assign_mode
(
seccomp_mode
))
goto
out
;
switch
(
seccomp_mode
)
{
case
SECCOMP_MODE_STRICT
:
ret
=
0
;
#ifdef TIF_NOTSC
disable_TSC
();
#endif
break
;
seccomp_assign_mode
(
current
,
seccomp_mode
);
ret
=
0
;
out:
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
return
ret
;
}
#ifdef CONFIG_SECCOMP_FILTER
case
SECCOMP_MODE_FILTER
:
ret
=
seccomp_attach_user_filter
(
filter
);
/**
* seccomp_set_mode_filter: internal function for setting seccomp filter
* @flags: flags to change filter behavior
* @filter: struct sock_fprog containing filter
*
* This function may be called repeatedly to install additional filters.
* Every filter successfully installed will be evaluated (in reverse order)
* for each system call the task makes.
*
* Once current->seccomp.mode is non-zero, it may not be changed.
*
* Returns 0 on success or -EINVAL on failure.
*/
static
long
seccomp_set_mode_filter
(
unsigned
int
flags
,
const
char
__user
*
filter
)
{
const
unsigned
long
seccomp_mode
=
SECCOMP_MODE_FILTER
;
struct
seccomp_filter
*
prepared
=
NULL
;
long
ret
=
-
EINVAL
;
/* Validate flags. */
if
(
flags
&
~
SECCOMP_FILTER_FLAG_MASK
)
return
-
EINVAL
;
/* Prepare the new filter before holding any locks. */
prepared
=
seccomp_prepare_user_filter
(
filter
);
if
(
IS_ERR
(
prepared
))
return
PTR_ERR
(
prepared
);
/*
* Make sure we cannot change seccomp or nnp state via TSYNC
* while another thread is in the middle of calling exec.
*/
if
(
flags
&
SECCOMP_FILTER_FLAG_TSYNC
&&
mutex_lock_killable
(
&
current
->
signal
->
cred_guard_mutex
))
goto
out_free
;
spin_lock_irq
(
&
current
->
sighand
->
siglock
);
if
(
!
seccomp_may_assign_mode
(
seccomp_mode
))
goto
out
;
ret
=
seccomp_attach_filter
(
flags
,
prepared
);
if
(
ret
)
goto
out
;
break
;
/* Do not free the successfully attached filter. */
prepared
=
NULL
;
seccomp_assign_mode
(
current
,
seccomp_mode
);
out:
spin_unlock_irq
(
&
current
->
sighand
->
siglock
);
if
(
flags
&
SECCOMP_FILTER_FLAG_TSYNC
)
mutex_unlock
(
&
current
->
signal
->
cred_guard_mutex
);
out_free:
seccomp_filter_free
(
prepared
);
return
ret
;
}
#else
static
inline
long
seccomp_set_mode_filter
(
unsigned
int
flags
,
const
char
__user
*
filter
)
{
return
-
EINVAL
;
}
#endif
/* Common entry point for both prctl and syscall. */
static
long
do_seccomp
(
unsigned
int
op
,
unsigned
int
flags
,
const
char
__user
*
uargs
)
{
switch
(
op
)
{
case
SECCOMP_SET_MODE_STRICT
:
if
(
flags
!=
0
||
uargs
!=
NULL
)
return
-
EINVAL
;
return
seccomp_set_mode_strict
();
case
SECCOMP_SET_MODE_FILTER
:
return
seccomp_set_mode_filter
(
flags
,
uargs
);
default:
goto
out
;
return
-
EINVAL
;
}
}
current
->
seccomp
.
mode
=
seccomp_mode
;
set_thread_flag
(
TIF_SECCOMP
);
out:
return
ret
;
SYSCALL_DEFINE3
(
seccomp
,
unsigned
int
,
op
,
unsigned
int
,
flags
,
const
char
__user
*
,
uargs
)
{
return
do_seccomp
(
op
,
flags
,
uargs
);
}
/**
* prctl_set_seccomp: configures current->seccomp.mode
* @seccomp_mode: requested mode to use
* @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
*
* Returns 0 on success or -EINVAL on failure.
*/
long
prctl_set_seccomp
(
unsigned
long
seccomp_mode
,
char
__user
*
filter
)
{
unsigned
int
op
;
char
__user
*
uargs
;
switch
(
seccomp_mode
)
{
case
SECCOMP_MODE_STRICT
:
op
=
SECCOMP_SET_MODE_STRICT
;
/*
* Setting strict mode through prctl always ignored filter,
* so make sure it is always NULL here to pass the internal
* check in do_seccomp().
*/
uargs
=
NULL
;
break
;
case
SECCOMP_MODE_FILTER
:
op
=
SECCOMP_SET_MODE_FILTER
;
uargs
=
filter
;
break
;
default:
return
-
EINVAL
;
}
/* prctl interface doesn't have flags, so they are always zero. */
return
do_seccomp
(
op
,
0
,
uargs
);
}
kernel/sys.c
浏览文件 @
fd33c436
...
...
@@ -1990,12 +1990,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
if
(
arg2
!=
1
||
arg3
||
arg4
||
arg5
)
return
-
EINVAL
;
current
->
no_new_privs
=
1
;
task_set_no_new_privs
(
current
)
;
break
;
case
PR_GET_NO_NEW_PRIVS
:
if
(
arg2
||
arg3
||
arg4
||
arg5
)
return
-
EINVAL
;
return
current
->
no_new_privs
?
1
:
0
;
return
task_no_new_privs
(
current
)
?
1
:
0
;
case
PR_GET_THP_DISABLE
:
if
(
arg2
||
arg3
||
arg4
||
arg5
)
return
-
EINVAL
;
...
...
kernel/sys_ni.c
浏览文件 @
fd33c436
...
...
@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);
/* compare kernel pointers */
cond_syscall
(
sys_kcmp
);
/* operate on Secure Computing state */
cond_syscall
(
sys_seccomp
);
security/apparmor/domain.c
浏览文件 @
fd33c436
...
...
@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
* There is no exception for unconfined as change_hat is not
* available.
*/
if
(
current
->
no_new_privs
)
if
(
task_no_new_privs
(
current
)
)
return
-
EPERM
;
/* released below */
...
...
@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
* no_new_privs is set because this aways results in a reduction
* of permissions.
*/
if
(
current
->
no_new_privs
&&
!
unconfined
(
profile
))
{
if
(
task_no_new_privs
(
current
)
&&
!
unconfined
(
profile
))
{
put_cred
(
cred
);
return
-
EPERM
;
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录