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>
This commit is contained in:
parent
3b23dd1284
commit
48dc92b9fc
@ -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 @@
|
|||||||
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 @@
|
|||||||
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,
|
|||||||
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)
|
|||||||
__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 @@
|
|||||||
#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 @@
|
|||||||
#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 @@ free_prog:
|
|||||||
*
|
*
|
||||||
* 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 @@ out:
|
|||||||
#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 @@ out:
|
|||||||
*
|
*
|
||||||
* 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 @@ out:
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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);
|
|||||||
|
|
||||||
/* compare kernel pointers */
|
/* compare kernel pointers */
|
||||||
cond_syscall(sys_kcmp);
|
cond_syscall(sys_kcmp);
|
||||||
|
|
||||||
|
/* operate on Secure Computing state */
|
||||||
|
cond_syscall(sys_seccomp);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user