Commit 48dc92b9 authored by Kees Cook's avatar Kees Cook

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: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarOleg Nesterov <oleg@redhat.com>
Reviewed-by: default avatarAndy Lutomirski <luto@amacapital.net>
parent 3b23dd12
...@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER ...@@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
- secure_computing is called from a ptrace_event()-safe context - secure_computing is called from a ptrace_event()-safe context
- secure_computing return value is checked and a return value of -1 - secure_computing return value is checked and a return value of -1
results in the system call being skipped immediately. results in the system call being skipped immediately.
- seccomp syscall wired up
config SECCOMP_FILTER config SECCOMP_FILTER
def_bool y def_bool y
......
...@@ -360,3 +360,4 @@ ...@@ -360,3 +360,4 @@
351 i386 sched_setattr sys_sched_setattr 351 i386 sched_setattr sys_sched_setattr
352 i386 sched_getattr sys_sched_getattr 352 i386 sched_getattr sys_sched_getattr
353 i386 renameat2 sys_renameat2 353 i386 renameat2 sys_renameat2
354 i386 seccomp sys_seccomp
...@@ -323,6 +323,7 @@ ...@@ -323,6 +323,7 @@
314 common sched_setattr sys_sched_setattr 314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr 315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2 316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
# #
# x32-specific system call numbers start at 512 to avoid cache impact # x32-specific system call numbers start at 512 to avoid cache impact
......
...@@ -866,4 +866,6 @@ asmlinkage long sys_process_vm_writev(pid_t pid, ...@@ -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, asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2); unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); 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 #endif
...@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) ...@@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
__SYSCALL(__NR_sched_getattr, sys_sched_getattr) __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
#define __NR_renameat2 276 #define __NR_renameat2 276
__SYSCALL(__NR_renameat2, sys_renameat2) __SYSCALL(__NR_renameat2, sys_renameat2)
#define __NR_seccomp 277
__SYSCALL(__NR_seccomp, sys_seccomp)
#undef __NR_syscalls #undef __NR_syscalls
#define __NR_syscalls 277 #define __NR_syscalls 278
/* /*
* All syscalls below here should go away really, * All syscalls below here should go away really,
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ #define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */
#define SECCOMP_MODE_FILTER 2 /* uses user-supplied 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
/* /*
* All BPF programs must return a 32-bit value. * All BPF programs must return a 32-bit value.
* The bottom 16-bits are for optional return data. * The bottom 16-bits are for optional return data.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/compat.h> #include <linux/compat.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/syscalls.h>
/* #define SECCOMP_DEBUG 1 */ /* #define SECCOMP_DEBUG 1 */
...@@ -314,7 +315,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) ...@@ -314,7 +315,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
* *
* Returns 0 on success and non-zero otherwise. * Returns 0 on success and non-zero otherwise.
*/ */
static long seccomp_attach_user_filter(char __user *user_filter) static long seccomp_attach_user_filter(const char __user *user_filter)
{ {
struct sock_fprog fprog; struct sock_fprog fprog;
long ret = -EFAULT; long ret = -EFAULT;
...@@ -517,6 +518,7 @@ static long seccomp_set_mode_strict(void) ...@@ -517,6 +518,7 @@ static long seccomp_set_mode_strict(void)
#ifdef CONFIG_SECCOMP_FILTER #ifdef CONFIG_SECCOMP_FILTER
/** /**
* seccomp_set_mode_filter: internal function for setting seccomp filter * seccomp_set_mode_filter: internal function for setting seccomp filter
* @flags: flags to change filter behavior
* @filter: struct sock_fprog containing filter * @filter: struct sock_fprog containing filter
* *
* This function may be called repeatedly to install additional filters. * This function may be called repeatedly to install additional filters.
...@@ -527,11 +529,16 @@ static long seccomp_set_mode_strict(void) ...@@ -527,11 +529,16 @@ static long seccomp_set_mode_strict(void)
* *
* Returns 0 on success or -EINVAL on failure. * Returns 0 on success or -EINVAL on failure.
*/ */
static long seccomp_set_mode_filter(char __user *filter) static long seccomp_set_mode_filter(unsigned int flags,
const char __user *filter)
{ {
const unsigned long seccomp_mode = SECCOMP_MODE_FILTER; const unsigned long seccomp_mode = SECCOMP_MODE_FILTER;
long ret = -EINVAL; long ret = -EINVAL;
/* Validate flags. */
if (flags != 0)
goto out;
if (!seccomp_may_assign_mode(seccomp_mode)) if (!seccomp_may_assign_mode(seccomp_mode))
goto out; goto out;
...@@ -544,12 +551,35 @@ static long seccomp_set_mode_filter(char __user *filter) ...@@ -544,12 +551,35 @@ static long seccomp_set_mode_filter(char __user *filter)
return ret; return ret;
} }
#else #else
static inline long seccomp_set_mode_filter(char __user *filter) static inline long seccomp_set_mode_filter(unsigned int flags,
const char __user *filter)
{ {
return -EINVAL; return -EINVAL;
} }
#endif #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:
return -EINVAL;
}
}
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 * prctl_set_seccomp: configures current->seccomp.mode
* @seccomp_mode: requested mode to use * @seccomp_mode: requested mode to use
...@@ -559,12 +589,27 @@ static inline long seccomp_set_mode_filter(char __user *filter) ...@@ -559,12 +589,27 @@ static inline long seccomp_set_mode_filter(char __user *filter)
*/ */
long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter) long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
{ {
unsigned int op;
char __user *uargs;
switch (seccomp_mode) { switch (seccomp_mode) {
case SECCOMP_MODE_STRICT: case SECCOMP_MODE_STRICT:
return seccomp_set_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: case SECCOMP_MODE_FILTER:
return seccomp_set_mode_filter(filter); op = SECCOMP_SET_MODE_FILTER;
uargs = filter;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
/* prctl interface doesn't have flags, so they are always zero. */
return do_seccomp(op, 0, uargs);
} }
...@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at); ...@@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);
/* compare kernel pointers */ /* compare kernel pointers */
cond_syscall(sys_kcmp); cond_syscall(sys_kcmp);
/* operate on Secure Computing state */
cond_syscall(sys_seccomp);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment