seccomp: Operation for checking if an action is available
Userspace code that needs to check if the kernel supports a given action may not be able to use the /proc/sys/kernel/seccomp/actions_avail sysctl. The process may be running in a sandbox and, therefore, sufficient filesystem access may not be available. This patch adds an operation to the seccomp(2) syscall that allows userspace code to ask the kernel if a given action is available. If the action is supported by the kernel, 0 is returned. If the action is not supported by the kernel, -1 is returned with errno set to -EOPNOTSUPP. If this check is attempted on a kernel that doesn't support this new operation, -1 is returned with errno set to -EINVAL meaning that userspace code will have the ability to differentiate between the two error cases. Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Suggested-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Kees Cook <keescook@chromium.org>
This commit is contained in:
parent
8e5f1ad116
commit
d612b1fd80
|
@ -11,8 +11,9 @@
|
|||
#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
|
||||
#define SECCOMP_SET_MODE_STRICT 0
|
||||
#define SECCOMP_SET_MODE_FILTER 1
|
||||
#define SECCOMP_GET_ACTION_AVAIL 2
|
||||
|
||||
/* Valid flags for SECCOMP_SET_MODE_FILTER */
|
||||
#define SECCOMP_FILTER_FLAG_TSYNC 1
|
||||
|
|
|
@ -808,6 +808,27 @@ static inline long seccomp_set_mode_filter(unsigned int flags,
|
|||
}
|
||||
#endif
|
||||
|
||||
static long seccomp_get_action_avail(const char __user *uaction)
|
||||
{
|
||||
u32 action;
|
||||
|
||||
if (copy_from_user(&action, uaction, sizeof(action)))
|
||||
return -EFAULT;
|
||||
|
||||
switch (action) {
|
||||
case SECCOMP_RET_KILL:
|
||||
case SECCOMP_RET_TRAP:
|
||||
case SECCOMP_RET_ERRNO:
|
||||
case SECCOMP_RET_TRACE:
|
||||
case SECCOMP_RET_ALLOW:
|
||||
break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Common entry point for both prctl and syscall. */
|
||||
static long do_seccomp(unsigned int op, unsigned int flags,
|
||||
const char __user *uargs)
|
||||
|
@ -819,6 +840,11 @@ static long do_seccomp(unsigned int op, unsigned int flags,
|
|||
return seccomp_set_mode_strict();
|
||||
case SECCOMP_SET_MODE_FILTER:
|
||||
return seccomp_set_mode_filter(flags, uargs);
|
||||
case SECCOMP_GET_ACTION_AVAIL:
|
||||
if (flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return seccomp_get_action_avail(uargs);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -1731,6 +1731,10 @@ TEST_F_SIGNAL(TRACE_syscall, kill_after_ptrace, SIGSYS)
|
|||
#define SECCOMP_SET_MODE_FILTER 1
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_GET_ACTION_AVAIL
|
||||
#define SECCOMP_GET_ACTION_AVAIL 2
|
||||
#endif
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_TSYNC
|
||||
#define SECCOMP_FILTER_FLAG_TSYNC 1
|
||||
#endif
|
||||
|
@ -2469,6 +2473,38 @@ TEST(syscall_restart)
|
|||
_metadata->passed = 0;
|
||||
}
|
||||
|
||||
TEST(get_action_avail)
|
||||
{
|
||||
__u32 actions[] = { SECCOMP_RET_KILL, SECCOMP_RET_TRAP,
|
||||
SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE,
|
||||
SECCOMP_RET_ALLOW };
|
||||
__u32 unknown_action = 0x10000000U;
|
||||
int i;
|
||||
long ret;
|
||||
|
||||
ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[0]);
|
||||
ASSERT_NE(ENOSYS, errno) {
|
||||
TH_LOG("Kernel does not support seccomp syscall!");
|
||||
}
|
||||
ASSERT_NE(EINVAL, errno) {
|
||||
TH_LOG("Kernel does not support SECCOMP_GET_ACTION_AVAIL operation!");
|
||||
}
|
||||
EXPECT_EQ(ret, 0);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(actions); i++) {
|
||||
ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &actions[i]);
|
||||
EXPECT_EQ(ret, 0) {
|
||||
TH_LOG("Expected action (0x%X) not available!",
|
||||
actions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that an unknown action is handled properly (EOPNOTSUPP) */
|
||||
ret = seccomp(SECCOMP_GET_ACTION_AVAIL, 0, &unknown_action);
|
||||
EXPECT_EQ(ret, -1);
|
||||
EXPECT_EQ(errno, EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - add microbenchmarks
|
||||
|
|
Loading…
Reference in New Issue