aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Morris <james.l.morris@oracle.com>2014-07-19 03:40:49 -0400
committerJames Morris <james.l.morris@oracle.com>2014-07-19 03:40:49 -0400
commitfd33c43677a7965624b46352a686a7c1e72ae4aa (patch)
tree10c2b8bfa4635b50d4cccd9c9453a9020a01e1a9
parent2ccf4661f315615d018686d91d030a94001d0cc6 (diff)
parentc2e1f2e30daa551db3c670c0ccfeab20a540b9e1 (diff)
Merge tag 'seccomp-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux into next
-rw-r--r--MAINTAINERS10
-rw-r--r--arch/Kconfig1
-rw-r--r--arch/arm/include/uapi/asm/unistd.h1
-rw-r--r--arch/arm/kernel/calls.S1
-rw-r--r--arch/mips/include/uapi/asm/unistd.h15
-rw-r--r--arch/mips/kernel/scall32-o32.S1
-rw-r--r--arch/mips/kernel/scall64-64.S1
-rw-r--r--arch/mips/kernel/scall64-n32.S1
-rw-r--r--arch/mips/kernel/scall64-o32.S1
-rw-r--r--arch/x86/syscalls/syscall_32.tbl1
-rw-r--r--arch/x86/syscalls/syscall_64.tbl1
-rw-r--r--fs/exec.c6
-rw-r--r--include/linux/sched.h18
-rw-r--r--include/linux/seccomp.h8
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/uapi/asm-generic/unistd.h4
-rw-r--r--include/uapi/linux/seccomp.h7
-rw-r--r--kernel/fork.c49
-rw-r--r--kernel/seccomp.c412
-rw-r--r--kernel/sys.c4
-rw-r--r--kernel/sys_ni.c3
-rw-r--r--security/apparmor/domain.c4
22 files changed, 471 insertions, 80 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index e31c87474739..55762cba8516 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7953,6 +7953,16 @@ S: Maintained
7953F: drivers/mmc/host/sdhci.* 7953F: drivers/mmc/host/sdhci.*
7954F: drivers/mmc/host/sdhci-pltfm.[ch] 7954F: drivers/mmc/host/sdhci-pltfm.[ch]
7955 7955
7956SECURE COMPUTING
7957M: Kees Cook <keescook@chromium.org>
7958T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git seccomp
7959S: Supported
7960F: kernel/seccomp.c
7961F: include/uapi/linux/seccomp.h
7962F: include/linux/seccomp.h
7963K: \bsecure_computing
7964K: \bTIF_SECCOMP\b
7965
7956SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF) 7966SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
7957M: Anton Vorontsov <anton@enomsg.org> 7967M: Anton Vorontsov <anton@enomsg.org>
7958L: linuxppc-dev@lists.ozlabs.org 7968L: linuxppc-dev@lists.ozlabs.org
diff --git a/arch/Kconfig b/arch/Kconfig
index 97ff872c7acc..0eae9df35b88 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
321 - secure_computing is called from a ptrace_event()-safe context 321 - secure_computing is called from a ptrace_event()-safe context
322 - secure_computing return value is checked and a return value of -1 322 - secure_computing return value is checked and a return value of -1
323 results in the system call being skipped immediately. 323 results in the system call being skipped immediately.
324 - seccomp syscall wired up
324 325
325config SECCOMP_FILTER 326config SECCOMP_FILTER
326 def_bool y 327 def_bool y
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h
index ba94446c72d9..e21b4a069701 100644
--- a/arch/arm/include/uapi/asm/unistd.h
+++ b/arch/arm/include/uapi/asm/unistd.h
@@ -409,6 +409,7 @@
409#define __NR_sched_setattr (__NR_SYSCALL_BASE+380) 409#define __NR_sched_setattr (__NR_SYSCALL_BASE+380)
410#define __NR_sched_getattr (__NR_SYSCALL_BASE+381) 410#define __NR_sched_getattr (__NR_SYSCALL_BASE+381)
411#define __NR_renameat2 (__NR_SYSCALL_BASE+382) 411#define __NR_renameat2 (__NR_SYSCALL_BASE+382)
412#define __NR_seccomp (__NR_SYSCALL_BASE+383)
412 413
413/* 414/*
414 * This may need to be greater than __NR_last_syscall+1 in order to 415 * This may need to be greater than __NR_last_syscall+1 in order to
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 8f51bdcdacbb..bea85f97f363 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -392,6 +392,7 @@
392/* 380 */ CALL(sys_sched_setattr) 392/* 380 */ CALL(sys_sched_setattr)
393 CALL(sys_sched_getattr) 393 CALL(sys_sched_getattr)
394 CALL(sys_renameat2) 394 CALL(sys_renameat2)
395 CALL(sys_seccomp)
395#ifndef syscalls_counted 396#ifndef syscalls_counted
396.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls 397.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
397#define syscalls_counted 398#define syscalls_counted
diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h
index 5805414777e0..9bc13eaf9d67 100644
--- a/arch/mips/include/uapi/asm/unistd.h
+++ b/arch/mips/include/uapi/asm/unistd.h
@@ -372,16 +372,17 @@
372#define __NR_sched_setattr (__NR_Linux + 349) 372#define __NR_sched_setattr (__NR_Linux + 349)
373#define __NR_sched_getattr (__NR_Linux + 350) 373#define __NR_sched_getattr (__NR_Linux + 350)
374#define __NR_renameat2 (__NR_Linux + 351) 374#define __NR_renameat2 (__NR_Linux + 351)
375#define __NR_seccomp (__NR_Linux + 352)
375 376
376/* 377/*
377 * Offset of the last Linux o32 flavoured syscall 378 * Offset of the last Linux o32 flavoured syscall
378 */ 379 */
379#define __NR_Linux_syscalls 351 380#define __NR_Linux_syscalls 352
380 381
381#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */ 382#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
382 383
383#define __NR_O32_Linux 4000 384#define __NR_O32_Linux 4000
384#define __NR_O32_Linux_syscalls 351 385#define __NR_O32_Linux_syscalls 352
385 386
386#if _MIPS_SIM == _MIPS_SIM_ABI64 387#if _MIPS_SIM == _MIPS_SIM_ABI64
387 388
@@ -701,16 +702,17 @@
701#define __NR_sched_setattr (__NR_Linux + 309) 702#define __NR_sched_setattr (__NR_Linux + 309)
702#define __NR_sched_getattr (__NR_Linux + 310) 703#define __NR_sched_getattr (__NR_Linux + 310)
703#define __NR_renameat2 (__NR_Linux + 311) 704#define __NR_renameat2 (__NR_Linux + 311)
705#define __NR_seccomp (__NR_Linux + 312)
704 706
705/* 707/*
706 * Offset of the last Linux 64-bit flavoured syscall 708 * Offset of the last Linux 64-bit flavoured syscall
707 */ 709 */
708#define __NR_Linux_syscalls 311 710#define __NR_Linux_syscalls 312
709 711
710#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */ 712#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
711 713
712#define __NR_64_Linux 5000 714#define __NR_64_Linux 5000
713#define __NR_64_Linux_syscalls 311 715#define __NR_64_Linux_syscalls 312
714 716
715#if _MIPS_SIM == _MIPS_SIM_NABI32 717#if _MIPS_SIM == _MIPS_SIM_NABI32
716 718
@@ -1034,15 +1036,16 @@
1034#define __NR_sched_setattr (__NR_Linux + 313) 1036#define __NR_sched_setattr (__NR_Linux + 313)
1035#define __NR_sched_getattr (__NR_Linux + 314) 1037#define __NR_sched_getattr (__NR_Linux + 314)
1036#define __NR_renameat2 (__NR_Linux + 315) 1038#define __NR_renameat2 (__NR_Linux + 315)
1039#define __NR_seccomp (__NR_Linux + 316)
1037 1040
1038/* 1041/*
1039 * Offset of the last N32 flavoured syscall 1042 * Offset of the last N32 flavoured syscall
1040 */ 1043 */
1041#define __NR_Linux_syscalls 315 1044#define __NR_Linux_syscalls 316
1042 1045
1043#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */ 1046#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
1044 1047
1045#define __NR_N32_Linux 6000 1048#define __NR_N32_Linux 6000
1046#define __NR_N32_Linux_syscalls 315 1049#define __NR_N32_Linux_syscalls 316
1047 1050
1048#endif /* _UAPI_ASM_UNISTD_H */ 1051#endif /* _UAPI_ASM_UNISTD_H */
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 3245474f19d5..ab02d14f1b5c 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -578,3 +578,4 @@ EXPORT(sys_call_table)
578 PTR sys_sched_setattr 578 PTR sys_sched_setattr
579 PTR sys_sched_getattr /* 4350 */ 579 PTR sys_sched_getattr /* 4350 */
580 PTR sys_renameat2 580 PTR sys_renameat2
581 PTR sys_seccomp
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index be2fedd4ae33..010dccf128ec 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -431,4 +431,5 @@ EXPORT(sys_call_table)
431 PTR sys_sched_setattr 431 PTR sys_sched_setattr
432 PTR sys_sched_getattr /* 5310 */ 432 PTR sys_sched_getattr /* 5310 */
433 PTR sys_renameat2 433 PTR sys_renameat2
434 PTR sys_seccomp
434 .size sys_call_table,.-sys_call_table 435 .size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index c1dbcda4b816..c3b3b6525df5 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -424,4 +424,5 @@ EXPORT(sysn32_call_table)
424 PTR sys_sched_setattr 424 PTR sys_sched_setattr
425 PTR sys_sched_getattr 425 PTR sys_sched_getattr
426 PTR sys_renameat2 /* 6315 */ 426 PTR sys_renameat2 /* 6315 */
427 PTR sys_seccomp
427 .size sysn32_call_table,.-sysn32_call_table 428 .size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index f1343ccd7ed7..bb1550b1f501 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -557,4 +557,5 @@ EXPORT(sys32_call_table)
557 PTR sys_sched_setattr 557 PTR sys_sched_setattr
558 PTR sys_sched_getattr /* 4350 */ 558 PTR sys_sched_getattr /* 4350 */
559 PTR sys_renameat2 559 PTR sys_renameat2
560 PTR sys_seccomp
560 .size sys32_call_table,.-sys32_call_table 561 .size sys32_call_table,.-sys32_call_table
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index d6b867921612..7527eac24122 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -360,3 +360,4 @@
360351 i386 sched_setattr sys_sched_setattr 360351 i386 sched_setattr sys_sched_setattr
361352 i386 sched_getattr sys_sched_getattr 361352 i386 sched_getattr sys_sched_getattr
362353 i386 renameat2 sys_renameat2 362353 i386 renameat2 sys_renameat2
363354 i386 seccomp sys_seccomp
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index ec255a1646d2..16272a6c12b7 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -323,6 +323,7 @@
323314 common sched_setattr sys_sched_setattr 323314 common sched_setattr sys_sched_setattr
324315 common sched_getattr sys_sched_getattr 324315 common sched_getattr sys_sched_getattr
325316 common renameat2 sys_renameat2 325316 common renameat2 sys_renameat2
326317 common seccomp sys_seccomp
326 327
327# 328#
328# x32-specific system call numbers start at 512 to avoid cache impact 329# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/exec.c b/fs/exec.c
index a3d33fe592d6..ab1f1200ce5d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1216,7 +1216,7 @@ EXPORT_SYMBOL(install_exec_creds);
1216/* 1216/*
1217 * determine how safe it is to execute the proposed program 1217 * determine how safe it is to execute the proposed program
1218 * - the caller must hold ->cred_guard_mutex to protect against 1218 * - the caller must hold ->cred_guard_mutex to protect against
1219 * PTRACE_ATTACH 1219 * PTRACE_ATTACH or seccomp thread-sync
1220 */ 1220 */
1221static void check_unsafe_exec(struct linux_binprm *bprm) 1221static void check_unsafe_exec(struct linux_binprm *bprm)
1222{ 1222{
@@ -1234,7 +1234,7 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
1234 * This isn't strictly necessary, but it makes it harder for LSMs to 1234 * This isn't strictly necessary, but it makes it harder for LSMs to
1235 * mess up. 1235 * mess up.
1236 */ 1236 */
1237 if (current->no_new_privs) 1237 if (task_no_new_privs(current))
1238 bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; 1238 bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
1239 1239
1240 t = p; 1240 t = p;
@@ -1272,7 +1272,7 @@ int prepare_binprm(struct linux_binprm *bprm)
1272 bprm->cred->egid = current_egid(); 1272 bprm->cred->egid = current_egid();
1273 1273
1274 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) && 1274 if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
1275 !current->no_new_privs && 1275 !task_no_new_privs(current) &&
1276 kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) && 1276 kuid_has_mapping(bprm->cred->user_ns, inode->i_uid) &&
1277 kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) { 1277 kgid_has_mapping(bprm->cred->user_ns, inode->i_gid)) {
1278 /* Set-uid? */ 1278 /* Set-uid? */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 306f4f0c987a..0fd19055bb64 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1307,13 +1307,12 @@ struct task_struct {
1307 * execve */ 1307 * execve */
1308 unsigned in_iowait:1; 1308 unsigned in_iowait:1;
1309 1309
1310 /* task may not gain privileges */
1311 unsigned no_new_privs:1;
1312
1313 /* Revert to default priority/policy when forking */ 1310 /* Revert to default priority/policy when forking */
1314 unsigned sched_reset_on_fork:1; 1311 unsigned sched_reset_on_fork:1;
1315 unsigned sched_contributes_to_load:1; 1312 unsigned sched_contributes_to_load:1;
1316 1313
1314 unsigned long atomic_flags; /* Flags needing atomic access. */
1315
1317 pid_t pid; 1316 pid_t pid;
1318 pid_t tgid; 1317 pid_t tgid;
1319 1318
@@ -1967,6 +1966,19 @@ static inline void memalloc_noio_restore(unsigned int flags)
1967 current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; 1966 current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags;
1968} 1967}
1969 1968
1969/* Per-process atomic flags. */
1970#define PFA_NO_NEW_PRIVS 0x00000001 /* May not gain new privileges. */
1971
1972static inline bool task_no_new_privs(struct task_struct *p)
1973{
1974 return test_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
1975}
1976
1977static inline void task_set_no_new_privs(struct task_struct *p)
1978{
1979 set_bit(PFA_NO_NEW_PRIVS, &p->atomic_flags);
1980}
1981
1970/* 1982/*
1971 * task->jobctl flags 1983 * task->jobctl flags
1972 */ 1984 */
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 4054b0994071..5d586a45a319 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -3,6 +3,8 @@
3 3
4#include <uapi/linux/seccomp.h> 4#include <uapi/linux/seccomp.h>
5 5
6#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC)
7
6#ifdef CONFIG_SECCOMP 8#ifdef CONFIG_SECCOMP
7 9
8#include <linux/thread_info.h> 10#include <linux/thread_info.h>
@@ -14,11 +16,11 @@ struct seccomp_filter;
14 * 16 *
15 * @mode: indicates one of the valid values above for controlled 17 * @mode: indicates one of the valid values above for controlled
16 * system calls available to a process. 18 * system calls available to a process.
17 * @filter: The metadata and ruleset for determining what system calls 19 * @filter: must always point to a valid seccomp-filter or NULL as it is
18 * are allowed for a task. 20 * accessed without locking during system call entry.
19 * 21 *
20 * @filter must only be accessed from the context of current as there 22 * @filter must only be accessed from the context of current as there
21 * is no locking. 23 * is no read locking.
22 */ 24 */
23struct seccomp { 25struct seccomp {
24 int mode; 26 int mode;
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index b0881a0ed322..1713977ee26f 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid,
866asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, 866asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
867 unsigned long idx1, unsigned long idx2); 867 unsigned long idx1, unsigned long idx2);
868asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); 868asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
869asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
870 const char __user *uargs);
869#endif 871#endif
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 333640608087..65acbf0e2867 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
699__SYSCALL(__NR_sched_getattr, sys_sched_getattr) 699__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
700#define __NR_renameat2 276 700#define __NR_renameat2 276
701__SYSCALL(__NR_renameat2, sys_renameat2) 701__SYSCALL(__NR_renameat2, sys_renameat2)
702#define __NR_seccomp 277
703__SYSCALL(__NR_seccomp, sys_seccomp)
702 704
703#undef __NR_syscalls 705#undef __NR_syscalls
704#define __NR_syscalls 277 706#define __NR_syscalls 278
705 707
706/* 708/*
707 * All syscalls below here should go away really, 709 * All syscalls below here should go away really,
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index ac2dc9f72973..0f238a43ff1e 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -10,6 +10,13 @@
10#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ 10#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */
11#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ 11#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
12 12
13/* Valid operations for seccomp syscall. */
14#define SECCOMP_SET_MODE_STRICT 0
15#define SECCOMP_SET_MODE_FILTER 1
16
17/* Valid flags for SECCOMP_SET_MODE_FILTER */
18#define SECCOMP_FILTER_FLAG_TSYNC 1
19
13/* 20/*
14 * All BPF programs must return a 32-bit value. 21 * All BPF programs must return a 32-bit value.
15 * The bottom 16-bits are for optional return data. 22 * The bottom 16-bits are for optional return data.
diff --git a/kernel/fork.c b/kernel/fork.c
index 6a13c46cd87d..ed4bc339c9dc 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -315,6 +315,15 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
315 goto free_ti; 315 goto free_ti;
316 316
317 tsk->stack = ti; 317 tsk->stack = ti;
318#ifdef CONFIG_SECCOMP
319 /*
320 * We must handle setting up seccomp filters once we're under
321 * the sighand lock in case orig has changed between now and
322 * then. Until then, filter must be NULL to avoid messing up
323 * the usage counts on the error path calling free_task.
324 */
325 tsk->seccomp.filter = NULL;
326#endif
318 327
319 setup_thread_stack(tsk, orig); 328 setup_thread_stack(tsk, orig);
320 clear_user_return_notifier(tsk); 329 clear_user_return_notifier(tsk);
@@ -1081,6 +1090,39 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
1081 return 0; 1090 return 0;
1082} 1091}
1083 1092
1093static void copy_seccomp(struct task_struct *p)
1094{
1095#ifdef CONFIG_SECCOMP
1096 /*
1097 * Must be called with sighand->lock held, which is common to
1098 * all threads in the group. Holding cred_guard_mutex is not
1099 * needed because this new task is not yet running and cannot
1100 * be racing exec.
1101 */
1102 BUG_ON(!spin_is_locked(&current->sighand->siglock));
1103
1104 /* Ref-count the new filter user, and assign it. */
1105 get_seccomp_filter(current);
1106 p->seccomp = current->seccomp;
1107
1108 /*
1109 * Explicitly enable no_new_privs here in case it got set
1110 * between the task_struct being duplicated and holding the
1111 * sighand lock. The seccomp state and nnp must be in sync.
1112 */
1113 if (task_no_new_privs(current))
1114 task_set_no_new_privs(p);
1115
1116 /*
1117 * If the parent gained a seccomp mode after copying thread
1118 * flags and between before we held the sighand lock, we have
1119 * to manually enable the seccomp thread flag here.
1120 */
1121 if (p->seccomp.mode != SECCOMP_MODE_DISABLED)
1122 set_tsk_thread_flag(p, TIF_SECCOMP);
1123#endif
1124}
1125
1084SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) 1126SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
1085{ 1127{
1086 current->clear_child_tid = tidptr; 1128 current->clear_child_tid = tidptr;
@@ -1196,7 +1238,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1196 goto fork_out; 1238 goto fork_out;
1197 1239
1198 ftrace_graph_init_task(p); 1240 ftrace_graph_init_task(p);
1199 get_seccomp_filter(p);
1200 1241
1201 rt_mutex_init_task(p); 1242 rt_mutex_init_task(p);
1202 1243
@@ -1437,6 +1478,12 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1437 spin_lock(&current->sighand->siglock); 1478 spin_lock(&current->sighand->siglock);
1438 1479
1439 /* 1480 /*
1481 * Copy seccomp details explicitly here, in case they were changed
1482 * before holding sighand lock.
1483 */
1484 copy_seccomp(p);
1485
1486 /*
1440 * Process group and session signals need to be delivered to just the 1487 * Process group and session signals need to be delivered to just the
1441 * parent before the fork or both the parent and the child after the 1488 * parent before the fork or both the parent and the child after the
1442 * fork. Restart if a signal comes in before we add the new process to 1489 * fork. Restart if a signal comes in before we add the new process to
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 301bbc24739c..74f460179171 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -18,15 +18,17 @@
18#include <linux/compat.h> 18#include <linux/compat.h>
19#include <linux/sched.h> 19#include <linux/sched.h>
20#include <linux/seccomp.h> 20#include <linux/seccomp.h>
21#include <linux/slab.h>
22#include <linux/syscalls.h>
21 23
22/* #define SECCOMP_DEBUG 1 */ 24/* #define SECCOMP_DEBUG 1 */
23 25
24#ifdef CONFIG_SECCOMP_FILTER 26#ifdef CONFIG_SECCOMP_FILTER
25#include <asm/syscall.h> 27#include <asm/syscall.h>
26#include <linux/filter.h> 28#include <linux/filter.h>
29#include <linux/pid.h>
27#include <linux/ptrace.h> 30#include <linux/ptrace.h>
28#include <linux/security.h> 31#include <linux/security.h>
29#include <linux/slab.h>
30#include <linux/tracehook.h> 32#include <linux/tracehook.h>
31#include <linux/uaccess.h> 33#include <linux/uaccess.h>
32 34
@@ -172,21 +174,24 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
172 */ 174 */
173static u32 seccomp_run_filters(int syscall) 175static u32 seccomp_run_filters(int syscall)
174{ 176{
175 struct seccomp_filter *f; 177 struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
176 struct seccomp_data sd; 178 struct seccomp_data sd;
177 u32 ret = SECCOMP_RET_ALLOW; 179 u32 ret = SECCOMP_RET_ALLOW;
178 180
179 /* Ensure unexpected behavior doesn't result in failing open. */ 181 /* Ensure unexpected behavior doesn't result in failing open. */
180 if (WARN_ON(current->seccomp.filter == NULL)) 182 if (unlikely(WARN_ON(f == NULL)))
181 return SECCOMP_RET_KILL; 183 return SECCOMP_RET_KILL;
182 184
185 /* Make sure cross-thread synced filter points somewhere sane. */
186 smp_read_barrier_depends();
187
183 populate_seccomp_data(&sd); 188 populate_seccomp_data(&sd);
184 189
185 /* 190 /*
186 * All filters in the list are evaluated and the lowest BPF return 191 * All filters in the list are evaluated and the lowest BPF return
187 * value always takes priority (ignoring the DATA). 192 * value always takes priority (ignoring the DATA).
188 */ 193 */
189 for (f = current->seccomp.filter; f; f = f->prev) { 194 for (; f; f = f->prev) {
190 u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); 195 u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd);
191 196
192 if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) 197 if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION))
@@ -194,29 +199,159 @@ static u32 seccomp_run_filters(int syscall)
194 } 199 }
195 return ret; 200 return ret;
196} 201}
202#endif /* CONFIG_SECCOMP_FILTER */
203
204static inline bool seccomp_may_assign_mode(unsigned long seccomp_mode)
205{
206 BUG_ON(!spin_is_locked(&current->sighand->siglock));
207
208 if (current->seccomp.mode && current->seccomp.mode != seccomp_mode)
209 return false;
210
211 return true;
212}
213
214static inline void seccomp_assign_mode(struct task_struct *task,
215 unsigned long seccomp_mode)
216{
217 BUG_ON(!spin_is_locked(&task->sighand->siglock));
218
219 task->seccomp.mode = seccomp_mode;
220 /*
221 * Make sure TIF_SECCOMP cannot be set before the mode (and
222 * filter) is set.
223 */
224 smp_mb__before_atomic();
225 set_tsk_thread_flag(task, TIF_SECCOMP);
226}
227
228#ifdef CONFIG_SECCOMP_FILTER
229/* Returns 1 if the parent is an ancestor of the child. */
230static int is_ancestor(struct seccomp_filter *parent,
231 struct seccomp_filter *child)
232{
233 /* NULL is the root ancestor. */
234 if (parent == NULL)
235 return 1;
236 for (; child; child = child->prev)
237 if (child == parent)
238 return 1;
239 return 0;
240}
197 241
198/** 242/**
199 * seccomp_attach_filter: Attaches a seccomp filter to current. 243 * seccomp_can_sync_threads: checks if all threads can be synchronized
244 *
245 * Expects sighand and cred_guard_mutex locks to be held.
246 *
247 * Returns 0 on success, -ve on error, or the pid of a thread which was
248 * either not in the correct seccomp mode or it did not have an ancestral
249 * seccomp filter.
250 */
251static inline pid_t seccomp_can_sync_threads(void)
252{
253 struct task_struct *thread, *caller;
254
255 BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
256 BUG_ON(!spin_is_locked(&current->sighand->siglock));
257
258 /* Validate all threads being eligible for synchronization. */
259 caller = current;
260 for_each_thread(caller, thread) {
261 pid_t failed;
262
263 /* Skip current, since it is initiating the sync. */
264 if (thread == caller)
265 continue;
266
267 if (thread->seccomp.mode == SECCOMP_MODE_DISABLED ||
268 (thread->seccomp.mode == SECCOMP_MODE_FILTER &&
269 is_ancestor(thread->seccomp.filter,
270 caller->seccomp.filter)))
271 continue;
272
273 /* Return the first thread that cannot be synchronized. */
274 failed = task_pid_vnr(thread);
275 /* If the pid cannot be resolved, then return -ESRCH */
276 if (unlikely(WARN_ON(failed == 0)))
277 failed = -ESRCH;
278 return failed;
279 }
280
281 return 0;
282}
283
284/**
285 * seccomp_sync_threads: sets all threads to use current's filter
286 *
287 * Expects sighand and cred_guard_mutex locks to be held, and for
288 * seccomp_can_sync_threads() to have returned success already
289 * without dropping the locks.
290 *
291 */
292static inline void seccomp_sync_threads(void)
293{
294 struct task_struct *thread, *caller;
295
296 BUG_ON(!mutex_is_locked(&current->signal->cred_guard_mutex));
297 BUG_ON(!spin_is_locked(&current->sighand->siglock));
298
299 /* Synchronize all threads. */
300 caller = current;
301 for_each_thread(caller, thread) {
302 /* Skip current, since it needs no changes. */
303 if (thread == caller)
304 continue;
305
306 /* Get a task reference for the new leaf node. */
307 get_seccomp_filter(caller);
308 /*
309 * Drop the task reference to the shared ancestor since
310 * current's path will hold a reference. (This also
311 * allows a put before the assignment.)
312 */
313 put_seccomp_filter(thread);
314 smp_store_release(&thread->seccomp.filter,
315 caller->seccomp.filter);
316 /*
317 * Opt the other thread into seccomp if needed.
318 * As threads are considered to be trust-realm
319 * equivalent (see ptrace_may_access), it is safe to
320 * allow one thread to transition the other.
321 */
322 if (thread->seccomp.mode == SECCOMP_MODE_DISABLED) {
323 /*
324 * Don't let an unprivileged task work around
325 * the no_new_privs restriction by creating
326 * a thread that sets it up, enters seccomp,
327 * then dies.
328 */
329 if (task_no_new_privs(caller))
330 task_set_no_new_privs(thread);
331
332 seccomp_assign_mode(thread, SECCOMP_MODE_FILTER);
333 }
334 }
335}
336
337/**
338 * seccomp_prepare_filter: Prepares a seccomp filter for use.
200 * @fprog: BPF program to install 339 * @fprog: BPF program to install
201 * 340 *
202 * Returns 0 on success or an errno on failure. 341 * Returns filter on success or an ERR_PTR on failure.
203 */ 342 */
204static long seccomp_attach_filter(struct sock_fprog *fprog) 343static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
205{ 344{
206 struct seccomp_filter *filter; 345 struct seccomp_filter *filter;
207 unsigned long fp_size = fprog->len * sizeof(struct sock_filter); 346 unsigned long fp_size;
208 unsigned long total_insns = fprog->len;
209 struct sock_filter *fp; 347 struct sock_filter *fp;
210 int new_len; 348 int new_len;
211 long ret; 349 long ret;
212 350
213 if (fprog->len == 0 || fprog->len > BPF_MAXINSNS) 351 if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
214 return -EINVAL; 352 return ERR_PTR(-EINVAL);
215 353 BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
216 for (filter = current->seccomp.filter; filter; filter = filter->prev) 354 fp_size = fprog->len * sizeof(struct sock_filter);
217 total_insns += filter->prog->len + 4; /* include a 4 instr penalty */
218 if (total_insns > MAX_INSNS_PER_PATH)
219 return -ENOMEM;
220 355
221 /* 356 /*
222 * Installing a seccomp filter requires that the task has 357 * Installing a seccomp filter requires that the task has
@@ -224,14 +359,14 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
224 * This avoids scenarios where unprivileged tasks can affect the 359 * This avoids scenarios where unprivileged tasks can affect the
225 * behavior of privileged children. 360 * behavior of privileged children.
226 */ 361 */
227 if (!current->no_new_privs && 362 if (!task_no_new_privs(current) &&
228 security_capable_noaudit(current_cred(), current_user_ns(), 363 security_capable_noaudit(current_cred(), current_user_ns(),
229 CAP_SYS_ADMIN) != 0) 364 CAP_SYS_ADMIN) != 0)
230 return -EACCES; 365 return ERR_PTR(-EACCES);
231 366
232 fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN); 367 fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
233 if (!fp) 368 if (!fp)
234 return -ENOMEM; 369 return ERR_PTR(-ENOMEM);
235 370
236 /* Copy the instructions from fprog. */ 371 /* Copy the instructions from fprog. */
237 ret = -EFAULT; 372 ret = -EFAULT;
@@ -275,13 +410,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
275 410
276 sk_filter_select_runtime(filter->prog); 411 sk_filter_select_runtime(filter->prog);
277 412
278 /* 413 return filter;
279 * If there is an existing filter, make it the prev and don't drop its
280 * task reference.
281 */
282 filter->prev = current->seccomp.filter;
283 current->seccomp.filter = filter;
284 return 0;
285 414
286free_filter_prog: 415free_filter_prog:
287 kfree(filter->prog); 416 kfree(filter->prog);
@@ -289,19 +418,20 @@ free_filter:
289 kfree(filter); 418 kfree(filter);
290free_prog: 419free_prog:
291 kfree(fp); 420 kfree(fp);
292 return ret; 421 return ERR_PTR(ret);
293} 422}
294 423
295/** 424/**
296 * seccomp_attach_user_filter - attaches a user-supplied sock_fprog 425 * seccomp_prepare_user_filter - prepares a user-supplied sock_fprog
297 * @user_filter: pointer to the user data containing a sock_fprog. 426 * @user_filter: pointer to the user data containing a sock_fprog.
298 * 427 *
299 * Returns 0 on success and non-zero otherwise. 428 * Returns 0 on success and non-zero otherwise.
300 */ 429 */
301static long seccomp_attach_user_filter(char __user *user_filter) 430static struct seccomp_filter *
431seccomp_prepare_user_filter(const char __user *user_filter)
302{ 432{
303 struct sock_fprog fprog; 433 struct sock_fprog fprog;
304 long ret = -EFAULT; 434 struct seccomp_filter *filter = ERR_PTR(-EFAULT);
305 435
306#ifdef CONFIG_COMPAT 436#ifdef CONFIG_COMPAT
307 if (is_compat_task()) { 437 if (is_compat_task()) {
@@ -314,9 +444,56 @@ static long seccomp_attach_user_filter(char __user *user_filter)
314#endif 444#endif
315 if (copy_from_user(&fprog, user_filter, sizeof(fprog))) 445 if (copy_from_user(&fprog, user_filter, sizeof(fprog)))
316 goto out; 446 goto out;
317 ret = seccomp_attach_filter(&fprog); 447 filter = seccomp_prepare_filter(&fprog);
318out: 448out:
319 return ret; 449 return filter;
450}
451
452/**
453 * seccomp_attach_filter: validate and attach filter
454 * @flags: flags to change filter behavior
455 * @filter: seccomp filter to add to the current process
456 *
457 * Caller must be holding current->sighand->siglock lock.
458 *
459 * Returns 0 on success, -ve on error.
460 */
461static long seccomp_attach_filter(unsigned int flags,
462 struct seccomp_filter *filter)
463{
464 unsigned long total_insns;
465 struct seccomp_filter *walker;
466
467 BUG_ON(!spin_is_locked(&current->sighand->siglock));
468
469 /* Validate resulting filter length. */
470 total_insns = filter->prog->len;
471 for (walker = current->seccomp.filter; walker; walker = walker->prev)
472 total_insns += walker->prog->len + 4; /* 4 instr penalty */
473 if (total_insns > MAX_INSNS_PER_PATH)
474 return -ENOMEM;
475
476 /* If thread sync has been requested, check that it is possible. */
477 if (flags & SECCOMP_FILTER_FLAG_TSYNC) {
478 int ret;
479
480 ret = seccomp_can_sync_threads();
481 if (ret)
482 return ret;
483 }
484
485 /*
486 * If there is an existing filter, make it the prev and don't drop its
487 * task reference.
488 */
489 filter->prev = current->seccomp.filter;
490 current->seccomp.filter = filter;
491
492 /* Now that the new filter is in place, synchronize to all threads. */
493 if (flags & SECCOMP_FILTER_FLAG_TSYNC)
494 seccomp_sync_threads();
495
496 return 0;
320} 497}
321 498
322/* get_seccomp_filter - increments the reference count of the filter on @tsk */ 499/* get_seccomp_filter - increments the reference count of the filter on @tsk */
@@ -329,6 +506,14 @@ void get_seccomp_filter(struct task_struct *tsk)
329 atomic_inc(&orig->usage); 506 atomic_inc(&orig->usage);
330} 507}
331 508
509static inline void seccomp_filter_free(struct seccomp_filter *filter)
510{
511 if (filter) {
512 sk_filter_free(filter->prog);
513 kfree(filter);
514 }
515}
516
332/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */ 517/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
333void put_seccomp_filter(struct task_struct *tsk) 518void put_seccomp_filter(struct task_struct *tsk)
334{ 519{
@@ -337,8 +522,7 @@ void put_seccomp_filter(struct task_struct *tsk)
337 while (orig && atomic_dec_and_test(&orig->usage)) { 522 while (orig && atomic_dec_and_test(&orig->usage)) {
338 struct seccomp_filter *freeme = orig; 523 struct seccomp_filter *freeme = orig;
339 orig = orig->prev; 524 orig = orig->prev;
340 sk_filter_free(freeme->prog); 525 seccomp_filter_free(freeme);
341 kfree(freeme);
342 } 526 }
343} 527}
344 528
@@ -382,12 +566,17 @@ static int mode1_syscalls_32[] = {
382 566
383int __secure_computing(int this_syscall) 567int __secure_computing(int this_syscall)
384{ 568{
385 int mode = current->seccomp.mode;
386 int exit_sig = 0; 569 int exit_sig = 0;
387 int *syscall; 570 int *syscall;
388 u32 ret; 571 u32 ret;
389 572
390 switch (mode) { 573 /*
574 * Make sure that any changes to mode from another thread have
575 * been seen after TIF_SECCOMP was seen.
576 */
577 rmb();
578
579 switch (current->seccomp.mode) {
391 case SECCOMP_MODE_STRICT: 580 case SECCOMP_MODE_STRICT:
392 syscall = mode1_syscalls; 581 syscall = mode1_syscalls;
393#ifdef CONFIG_COMPAT 582#ifdef CONFIG_COMPAT
@@ -473,47 +662,152 @@ long prctl_get_seccomp(void)
473} 662}
474 663
475/** 664/**
476 * prctl_set_seccomp: configures current->seccomp.mode 665 * seccomp_set_mode_strict: internal function for setting strict seccomp
477 * @seccomp_mode: requested mode to use
478 * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
479 * 666 *
480 * This function may be called repeatedly with a @seccomp_mode of 667 * Once current->seccomp.mode is non-zero, it may not be changed.
481 * SECCOMP_MODE_FILTER to install additional filters. Every filter 668 *
482 * successfully installed will be evaluated (in reverse order) for each system 669 * Returns 0 on success or -EINVAL on failure.
483 * call the task makes. 670 */
671static long seccomp_set_mode_strict(void)
672{
673 const unsigned long seccomp_mode = SECCOMP_MODE_STRICT;
674 long ret = -EINVAL;
675
676 spin_lock_irq(&current->sighand->siglock);
677
678 if (!seccomp_may_assign_mode(seccomp_mode))
679 goto out;
680
681#ifdef TIF_NOTSC
682 disable_TSC();
683#endif
684 seccomp_assign_mode(current, seccomp_mode);
685 ret = 0;
686
687out:
688 spin_unlock_irq(&current->sighand->siglock);
689
690 return ret;
691}
692
693#ifdef CONFIG_SECCOMP_FILTER
694/**
695 * seccomp_set_mode_filter: internal function for setting seccomp filter
696 * @flags: flags to change filter behavior
697 * @filter: struct sock_fprog containing filter
698 *
699 * This function may be called repeatedly to install additional filters.
700 * Every filter successfully installed will be evaluated (in reverse order)
701 * for each system call the task makes.
484 * 702 *
485 * Once current->seccomp.mode is non-zero, it may not be changed. 703 * Once current->seccomp.mode is non-zero, it may not be changed.
486 * 704 *
487 * Returns 0 on success or -EINVAL on failure. 705 * Returns 0 on success or -EINVAL on failure.
488 */ 706 */
489long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) 707static long seccomp_set_mode_filter(unsigned int flags,
708 const char __user *filter)
490{ 709{
710 const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
711 struct seccomp_filter *prepared = NULL;
491 long ret = -EINVAL; 712 long ret = -EINVAL;
492 713
493 if (current->seccomp.mode && 714 /* Validate flags. */
494 current->seccomp.mode != seccomp_mode) 715 if (flags & ~SECCOMP_FILTER_FLAG_MASK)
716 return -EINVAL;
717
718 /* Prepare the new filter before holding any locks. */
719 prepared = seccomp_prepare_user_filter(filter);
720 if (IS_ERR(prepared))
721 return PTR_ERR(prepared);
722
723 /*
724 * Make sure we cannot change seccomp or nnp state via TSYNC
725 * while another thread is in the middle of calling exec.
726 */
727 if (flags & SECCOMP_FILTER_FLAG_TSYNC &&
728 mutex_lock_killable(&current->signal->cred_guard_mutex))
729 goto out_free;
730
731 spin_lock_irq(&current->sighand->siglock);
732
733 if (!seccomp_may_assign_mode(seccomp_mode))
734 goto out;
735
736 ret = seccomp_attach_filter(flags, prepared);
737 if (ret)
495 goto out; 738 goto out;
739 /* Do not free the successfully attached filter. */
740 prepared = NULL;
741
742 seccomp_assign_mode(current, seccomp_mode);
743out:
744 spin_unlock_irq(&current->sighand->siglock);
745 if (flags & SECCOMP_FILTER_FLAG_TSYNC)
746 mutex_unlock(&current->signal->cred_guard_mutex);
747out_free:
748 seccomp_filter_free(prepared);
749 return ret;
750}
751#else
752static inline long seccomp_set_mode_filter(unsigned int flags,
753 const char __user *filter)
754{
755 return -EINVAL;
756}
757#endif
758
759/* Common entry point for both prctl and syscall. */
760static long do_seccomp(unsigned int op, unsigned int flags,
761 const char __user *uargs)
762{
763 switch (op) {
764 case SECCOMP_SET_MODE_STRICT:
765 if (flags != 0 || uargs != NULL)
766 return -EINVAL;
767 return seccomp_set_mode_strict();
768 case SECCOMP_SET_MODE_FILTER:
769 return seccomp_set_mode_filter(flags, uargs);
770 default:
771 return -EINVAL;
772 }
773}
774
775SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags,
776 const char __user *, uargs)
777{
778 return do_seccomp(op, flags, uargs);
779}
780
781/**
782 * prctl_set_seccomp: configures current->seccomp.mode
783 * @seccomp_mode: requested mode to use
784 * @filter: optional struct sock_fprog for use with SECCOMP_MODE_FILTER
785 *
786 * Returns 0 on success or -EINVAL on failure.
787 */
788long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
789{
790 unsigned int op;
791 char __user *uargs;
496 792
497 switch (seccomp_mode) { 793 switch (seccomp_mode) {
498 case SECCOMP_MODE_STRICT: 794 case SECCOMP_MODE_STRICT:
499 ret = 0; 795 op = SECCOMP_SET_MODE_STRICT;
500#ifdef TIF_NOTSC 796 /*
501 disable_TSC(); 797 * Setting strict mode through prctl always ignored filter,
502#endif 798 * so make sure it is always NULL here to pass the internal
799 * check in do_seccomp().
800 */
801 uargs = NULL;
503 break; 802 break;
504#ifdef CONFIG_SECCOMP_FILTER
505 case SECCOMP_MODE_FILTER: 803 case SECCOMP_MODE_FILTER:
506 ret = seccomp_attach_user_filter(filter); 804 op = SECCOMP_SET_MODE_FILTER;
507 if (ret) 805 uargs = filter;
508 goto out;
509 break; 806 break;
510#endif
511 default: 807 default:
512 goto out; 808 return -EINVAL;
513 } 809 }
514 810
515 current->seccomp.mode = seccomp_mode; 811 /* prctl interface doesn't have flags, so they are always zero. */
516 set_thread_flag(TIF_SECCOMP); 812 return do_seccomp(op, 0, uargs);
517out:
518 return ret;
519} 813}
diff --git a/kernel/sys.c b/kernel/sys.c
index 66a751ebf9d9..ce8129192a26 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1990,12 +1990,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
1990 if (arg2 != 1 || arg3 || arg4 || arg5) 1990 if (arg2 != 1 || arg3 || arg4 || arg5)
1991 return -EINVAL; 1991 return -EINVAL;
1992 1992
1993 current->no_new_privs = 1; 1993 task_set_no_new_privs(current);
1994 break; 1994 break;
1995 case PR_GET_NO_NEW_PRIVS: 1995 case PR_GET_NO_NEW_PRIVS:
1996 if (arg2 || arg3 || arg4 || arg5) 1996 if (arg2 || arg3 || arg4 || arg5)
1997 return -EINVAL; 1997 return -EINVAL;
1998 return current->no_new_privs ? 1 : 0; 1998 return task_no_new_privs(current) ? 1 : 0;
1999 case PR_GET_THP_DISABLE: 1999 case PR_GET_THP_DISABLE:
2000 if (arg2 || arg3 || arg4 || arg5) 2000 if (arg2 || arg3 || arg4 || arg5)
2001 return -EINVAL; 2001 return -EINVAL;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 36441b51b5df..2904a2105914 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);
213 213
214/* compare kernel pointers */ 214/* compare kernel pointers */
215cond_syscall(sys_kcmp); 215cond_syscall(sys_kcmp);
216
217/* operate on Secure Computing state */
218cond_syscall(sys_seccomp);
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 452567d3a08e..d97cba3e3849 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest)
621 * There is no exception for unconfined as change_hat is not 621 * There is no exception for unconfined as change_hat is not
622 * available. 622 * available.
623 */ 623 */
624 if (current->no_new_privs) 624 if (task_no_new_privs(current))
625 return -EPERM; 625 return -EPERM;
626 626
627 /* released below */ 627 /* released below */
@@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec,
776 * no_new_privs is set because this aways results in a reduction 776 * no_new_privs is set because this aways results in a reduction
777 * of permissions. 777 * of permissions.
778 */ 778 */
779 if (current->no_new_privs && !unconfined(profile)) { 779 if (task_no_new_privs(current) && !unconfined(profile)) {
780 put_cred(cred); 780 put_cred(cred);
781 return -EPERM; 781 return -EPERM;
782 } 782 }