aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2014-06-25 19:08:24 -0400
committerKees Cook <keescook@chromium.org>2014-07-18 15:13:37 -0400
commit48dc92b9fc3926844257316e75ba11eb5c742b2c (patch)
tree2f35355b95a7c1473fd8d361b4f15a9f368999b4
parent3b23dd12846215eff4afb073366b80c0c4d7543e (diff)
seccomp: add "seccomp" syscall
This adds the new "seccomp" syscall with both an "operation" and "flags" parameter for future expansion. The third argument is a pointer value, used with the SECCOMP_SET_MODE_FILTER operation. Currently, flags must be 0. This is functionally equivalent to prctl(PR_SET_SECCOMP, ...). In addition to the TSYNC flag later in this patch series, there is a non-zero chance that this syscall could be used for configuring a fixed argument area for seccomp-tracer-aware processes to pass syscall arguments in the future. Hence, the use of "seccomp" not simply "seccomp_add_filter" for this syscall. Additionally, this syscall uses operation, flags, and user pointer for arguments because strictly passing arguments via a user pointer would mean seccomp itself would be unable to trivially filter the seccomp syscall itself. Signed-off-by: Kees Cook <keescook@chromium.org> Reviewed-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Andy Lutomirski <luto@amacapital.net>
-rw-r--r--arch/Kconfig1
-rw-r--r--arch/x86/syscalls/syscall_32.tbl1
-rw-r--r--arch/x86/syscalls/syscall_64.tbl1
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/uapi/asm-generic/unistd.h4
-rw-r--r--include/uapi/linux/seccomp.h4
-rw-r--r--kernel/seccomp.c55
-rw-r--r--kernel/sys_ni.c3
8 files changed, 65 insertions, 6 deletions
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/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/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..b258878ba754 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -10,6 +10,10 @@
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
13/* 17/*
14 * All BPF programs must return a 32-bit value. 18 * All BPF programs must return a 32-bit value.
15 * The bottom 16-bits are for optional return data. 19 * The bottom 16-bits are for optional return data.
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 05cac2c2eca1..f0652578af75 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -18,6 +18,7 @@
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/syscalls.h>
21 22
22/* #define SECCOMP_DEBUG 1 */ 23/* #define SECCOMP_DEBUG 1 */
23 24
@@ -314,7 +315,7 @@ free_prog:
314 * 315 *
315 * Returns 0 on success and non-zero otherwise. 316 * Returns 0 on success and non-zero otherwise.
316 */ 317 */
317static long seccomp_attach_user_filter(char __user *user_filter) 318static long seccomp_attach_user_filter(const char __user *user_filter)
318{ 319{
319 struct sock_fprog fprog; 320 struct sock_fprog fprog;
320 long ret = -EFAULT; 321 long ret = -EFAULT;
@@ -517,6 +518,7 @@ out:
517#ifdef CONFIG_SECCOMP_FILTER 518#ifdef CONFIG_SECCOMP_FILTER
518/** 519/**
519 * seccomp_set_mode_filter: internal function for setting seccomp filter 520 * seccomp_set_mode_filter: internal function for setting seccomp filter
521 * @flags: flags to change filter behavior
520 * @filter: struct sock_fprog containing filter 522 * @filter: struct sock_fprog containing filter
521 * 523 *
522 * This function may be called repeatedly to install additional filters. 524 * This function may be called repeatedly to install additional filters.
@@ -527,11 +529,16 @@ out:
527 * 529 *
528 * Returns 0 on success or -EINVAL on failure. 530 * Returns 0 on success or -EINVAL on failure.
529 */ 531 */
530static long seccomp_set_mode_filter(char __user *filter) 532static long seccomp_set_mode_filter(unsigned int flags,
533 const char __user *filter)
531{ 534{
532 const unsigned long seccomp_mode = SECCOMP_MODE_FILTER; 535 const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
533 long ret = -EINVAL; 536 long ret = -EINVAL;
534 537
538 /* Validate flags. */
539 if (flags != 0)
540 goto out;
541
535 if (!seccomp_may_assign_mode(seccomp_mode)) 542 if (!seccomp_may_assign_mode(seccomp_mode))
536 goto out; 543 goto out;
537 544
@@ -544,12 +551,35 @@ out:
544 return ret; 551 return ret;
545} 552}
546#else 553#else
547static inline long seccomp_set_mode_filter(char __user *filter) 554static inline long seccomp_set_mode_filter(unsigned int flags,
555 const char __user *filter)
548{ 556{
549 return -EINVAL; 557 return -EINVAL;
550} 558}
551#endif 559#endif
552 560
561/* Common entry point for both prctl and syscall. */
562static long do_seccomp(unsigned int op, unsigned int flags,
563 const char __user *uargs)
564{
565 switch (op) {
566 case SECCOMP_SET_MODE_STRICT:
567 if (flags != 0 || uargs != NULL)
568 return -EINVAL;
569 return seccomp_set_mode_strict();
570 case SECCOMP_SET_MODE_FILTER:
571 return seccomp_set_mode_filter(flags, uargs);
572 default:
573 return -EINVAL;
574 }
575}
576
577SYSCALL_DEFINE3(seccomp, unsigned int, op, unsigned int, flags,
578 const char __user *, uargs)
579{
580 return do_seccomp(op, flags, uargs);
581}
582
553/** 583/**
554 * prctl_set_seccomp: configures current->seccomp.mode 584 * prctl_set_seccomp: configures current->seccomp.mode
555 * @seccomp_mode: requested mode to use 585 * @seccomp_mode: requested mode to use
@@ -559,12 +589,27 @@ static inline long seccomp_set_mode_filter(char __user *filter)
559 */ 589 */
560long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) 590long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
561{ 591{
592 unsigned int op;
593 char __user *uargs;
594
562 switch (seccomp_mode) { 595 switch (seccomp_mode) {
563 case SECCOMP_MODE_STRICT: 596 case SECCOMP_MODE_STRICT:
564 return seccomp_set_mode_strict(); 597 op = SECCOMP_SET_MODE_STRICT;
598 /*
599 * Setting strict mode through prctl always ignored filter,
600 * so make sure it is always NULL here to pass the internal
601 * check in do_seccomp().
602 */
603 uargs = NULL;
604 break;
565 case SECCOMP_MODE_FILTER: 605 case SECCOMP_MODE_FILTER:
566 return seccomp_set_mode_filter(filter); 606 op = SECCOMP_SET_MODE_FILTER;
607 uargs = filter;
608 break;
567 default: 609 default:
568 return -EINVAL; 610 return -EINVAL;
569 } 611 }
612
613 /* prctl interface doesn't have flags, so they are always zero. */
614 return do_seccomp(op, 0, uargs);
570} 615}
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);