Skip to content

Commit 0466bdb

Browse files
committed
seccomp: Implement SECCOMP_RET_KILL_PROCESS action
Right now, SECCOMP_RET_KILL_THREAD (neé SECCOMP_RET_KILL) kills the current thread. There have been a few requests for this to kill the entire process (the thread group). This cannot be just changed (discovered when adding coredump support since coredumping kills the entire process) because there are userspace programs depending on the thread-kill behavior. Instead, implement SECCOMP_RET_KILL_PROCESS, which is 0x80000000, and can be processed as "-1" by the kernel, below the existing RET_KILL that is ABI-set to "0". For userspace, SECCOMP_RET_ACTION_FULL is added to expand the mask to the signed bit. Old userspace using the SECCOMP_RET_ACTION mask will see SECCOMP_RET_KILL_PROCESS as 0 still, but this would only be visible when examining the siginfo in a core dump from a RET_KILL_*, where it will think it was thread-killed instead of process-killed. Attempts to introduce this behavior via other ways (filter flags, seccomp struct flags, masked RET_DATA bits) all come with weird side-effects and baggage. This change preserves the central behavioral expectations of the seccomp filter engine without putting too great a burden on changes needed in userspace to use the new action. The new action is discoverable by userspace through either the new actions_avail sysctl or through the SECCOMP_GET_ACTION_AVAIL seccomp operation. If used without checking for availability, old kernels will treat RET_KILL_PROCESS as RET_KILL_THREAD (since the old mask will produce RET_KILL_THREAD). Cc: Paul Moore <[email protected]> Cc: Fabricio Voznika <[email protected]> Signed-off-by: Kees Cook <[email protected]>
1 parent 4d3b0b0 commit 0466bdb

File tree

3 files changed

+14
-3
lines changed

3 files changed

+14
-3
lines changed

Documentation/userspace-api/seccomp_filter.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,15 @@ Return values
8787
A seccomp filter may return any of the following values. If multiple
8888
filters exist, the return value for the evaluation of a given system
8989
call will always use the highest precedent value. (For example,
90-
``SECCOMP_RET_KILL_THREAD`` will always take precedence.)
90+
``SECCOMP_RET_KILL_PROCESS`` will always take precedence.)
9191

9292
In precedence order, they are:
9393

94+
``SECCOMP_RET_KILL_PROCESS``:
95+
Results in the entire process exiting immediately without executing
96+
the system call. The exit status of the task (``status & 0x7f``)
97+
will be ``SIGSYS``, not ``SIGKILL``.
98+
9499
``SECCOMP_RET_KILL_THREAD``:
95100
Results in the task exiting immediately without executing the
96101
system call. The exit status of the task (``status & 0x7f``) will

include/uapi/linux/seccomp.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
3939

4040
/* Masks for the return value sections. */
41+
#define SECCOMP_RET_ACTION_FULL 0xffff0000U
4142
#define SECCOMP_RET_ACTION 0x7fff0000U
4243
#define SECCOMP_RET_DATA 0x0000ffffU
4344

kernel/seccomp.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
181181
*
182182
* Returns valid seccomp BPF response codes.
183183
*/
184+
#define ACTION_ONLY(ret) ((s32)((ret) & (SECCOMP_RET_ACTION_FULL)))
184185
static u32 seccomp_run_filters(const struct seccomp_data *sd,
185186
struct seccomp_filter **match)
186187
{
@@ -206,7 +207,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
206207
for (; f; f = f->prev) {
207208
u32 cur_ret = BPF_PROG_RUN(f->prog, sd);
208209

209-
if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) {
210+
if (ACTION_ONLY(cur_ret) < ACTION_ONLY(ret)) {
210211
ret = cur_ret;
211212
*match = f;
212213
}
@@ -650,7 +651,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
650651

651652
filter_ret = seccomp_run_filters(sd, &match);
652653
data = filter_ret & SECCOMP_RET_DATA;
653-
action = filter_ret & SECCOMP_RET_ACTION;
654+
action = filter_ret & SECCOMP_RET_ACTION_FULL;
654655

655656
switch (action) {
656657
case SECCOMP_RET_ERRNO:
@@ -890,6 +891,7 @@ static long seccomp_get_action_avail(const char __user *uaction)
890891
return -EFAULT;
891892

892893
switch (action) {
894+
case SECCOMP_RET_KILL_PROCESS:
893895
case SECCOMP_RET_KILL_THREAD:
894896
case SECCOMP_RET_TRAP:
895897
case SECCOMP_RET_ERRNO:
@@ -1041,6 +1043,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
10411043
#ifdef CONFIG_SYSCTL
10421044

10431045
/* Human readable action names for friendly sysctl interaction */
1046+
#define SECCOMP_RET_KILL_PROCESS_NAME "kill_process"
10441047
#define SECCOMP_RET_KILL_THREAD_NAME "kill_thread"
10451048
#define SECCOMP_RET_TRAP_NAME "trap"
10461049
#define SECCOMP_RET_ERRNO_NAME "errno"
@@ -1049,6 +1052,7 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
10491052
#define SECCOMP_RET_ALLOW_NAME "allow"
10501053

10511054
static const char seccomp_actions_avail[] =
1055+
SECCOMP_RET_KILL_PROCESS_NAME " "
10521056
SECCOMP_RET_KILL_THREAD_NAME " "
10531057
SECCOMP_RET_TRAP_NAME " "
10541058
SECCOMP_RET_ERRNO_NAME " "
@@ -1062,6 +1066,7 @@ struct seccomp_log_name {
10621066
};
10631067

10641068
static const struct seccomp_log_name seccomp_log_names[] = {
1069+
{ SECCOMP_LOG_KILL_PROCESS, SECCOMP_RET_KILL_PROCESS_NAME },
10651070
{ SECCOMP_LOG_KILL_THREAD, SECCOMP_RET_KILL_THREAD_NAME },
10661071
{ SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
10671072
{ SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },

0 commit comments

Comments
 (0)