diff options
author | Kees Cook <keescook@chromium.org> | 2014-06-25 19:08:24 -0400 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2014-07-18 15:13:37 -0400 |
commit | 48dc92b9fc3926844257316e75ba11eb5c742b2c (patch) | |
tree | 2f35355b95a7c1473fd8d361b4f15a9f368999b4 /kernel | |
parent | 3b23dd12846215eff4afb073366b80c0c4d7543e (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>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/seccomp.c | 55 | ||||
-rw-r--r-- | kernel/sys_ni.c | 3 |
2 files changed, 53 insertions, 5 deletions
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 | */ |
317 | static long seccomp_attach_user_filter(char __user *user_filter) | 318 | static 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 | */ |
530 | static long seccomp_set_mode_filter(char __user *filter) | 532 | static 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 |
547 | static inline long seccomp_set_mode_filter(char __user *filter) | 554 | static 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. */ | ||
562 | static 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 | |||
577 | SYSCALL_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 | */ |
560 | long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) | 590 | long 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 */ |
215 | cond_syscall(sys_kcmp); | 215 | cond_syscall(sys_kcmp); |
216 | |||
217 | /* operate on Secure Computing state */ | ||
218 | cond_syscall(sys_seccomp); | ||