Skip to content

Commit

Permalink
seccomp: add "seccomp" syscall
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Oleg Nesterov <[email protected]>
Reviewed-by: Andy Lutomirski <[email protected]>
  • Loading branch information
kees committed Jul 18, 2014
1 parent 3b23dd1 commit 48dc92b
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 6 deletions.
1 change: 1 addition & 0 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ config HAVE_ARCH_SECCOMP_FILTER
- secure_computing is called from a ptrace_event()-safe context
- secure_computing return value is checked and a return value of -1
results in the system call being skipped immediately.
- seccomp syscall wired up

config SECCOMP_FILTER
def_bool y
Expand Down
1 change: 1 addition & 0 deletions arch/x86/syscalls/syscall_32.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,4 @@
351 i386 sched_setattr sys_sched_setattr
352 i386 sched_getattr sys_sched_getattr
353 i386 renameat2 sys_renameat2
354 i386 seccomp sys_seccomp
1 change: 1 addition & 0 deletions arch/x86/syscalls/syscall_64.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
314 common sched_setattr sys_sched_setattr
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp

#
# x32-specific system call numbers start at 512 to avoid cache impact
Expand Down
2 changes: 2 additions & 0 deletions include/linux/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
unsigned long idx1, unsigned long idx2);
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
4 changes: 3 additions & 1 deletion include/uapi/asm-generic/unistd.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
#define __NR_renameat2 276
__SYSCALL(__NR_renameat2, sys_renameat2)
#define __NR_seccomp 277
__SYSCALL(__NR_seccomp, sys_seccomp)

#undef __NR_syscalls
#define __NR_syscalls 277
#define __NR_syscalls 278

/*
* All syscalls below here should go away really,
Expand Down
4 changes: 4 additions & 0 deletions include/uapi/linux/seccomp.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#define SECCOMP_MODE_STRICT 1 /* uses hard-coded 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.
* The bottom 16-bits are for optional return data.
Expand Down
55 changes: 50 additions & 5 deletions kernel/seccomp.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <linux/compat.h>
#include <linux/sched.h>
#include <linux/seccomp.h>
#include <linux/syscalls.h>

/* #define SECCOMP_DEBUG 1 */

Expand Down Expand Up @@ -314,7 +315,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog)
*
* 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;
long ret = -EFAULT;
Expand Down Expand Up @@ -517,6 +518,7 @@ static long seccomp_set_mode_strict(void)
#ifdef CONFIG_SECCOMP_FILTER
/**
* seccomp_set_mode_filter: internal function for setting seccomp filter
* @flags: flags to change filter behavior
* @filter: struct sock_fprog containing filter
*
* This function may be called repeatedly to install additional filters.
Expand All @@ -527,11 +529,16 @@ static long seccomp_set_mode_strict(void)
*
* 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;
long ret = -EINVAL;

/* Validate flags. */
if (flags != 0)
goto out;

if (!seccomp_may_assign_mode(seccomp_mode))
goto out;

Expand All @@ -544,12 +551,35 @@ static long seccomp_set_mode_filter(char __user *filter)
return ret;
}
#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;
}
#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
* @seccomp_mode: requested mode to use
Expand All @@ -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)
{
unsigned int op;
char __user *uargs;

switch (seccomp_mode) {
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:
return seccomp_set_mode_filter(filter);
op = SECCOMP_SET_MODE_FILTER;
uargs = filter;
break;
default:
return -EINVAL;
}

/* prctl interface doesn't have flags, so they are always zero. */
return do_seccomp(op, 0, uargs);
}
3 changes: 3 additions & 0 deletions kernel/sys_ni.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,6 @@ cond_syscall(compat_sys_open_by_handle_at);

/* compare kernel pointers */
cond_syscall(sys_kcmp);

/* operate on Secure Computing state */
cond_syscall(sys_seccomp);

0 comments on commit 48dc92b

Please sign in to comment.