Skip to content

Commit dc8af1f

Browse files
committed
Merge tag 'seccomp-v5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull seccomp updates from Kees Cook: - Rework USER_NOTIF notification ordering and kill logic (Sargun Dhillon) - Improved PTRACE_O_SUSPEND_SECCOMP selftest (Jann Horn) - Gracefully handle failed unshare() in selftests (Yang Guang) - Spelling fix (Colin Ian King) * tag 'seccomp-v5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: selftests/seccomp: Fix spelling mistake "Coud" -> "Could" selftests/seccomp: Add test for wait killable notifier selftests/seccomp: Refactor get_proc_stat to split out file reading code seccomp: Add wait_killable semantic to seccomp user notifier selftests/seccomp: Ensure that notifications come in FIFO order seccomp: Use FIFO semantics to order notifications selftests/seccomp: Add SKIP for failed unshare() selftests/seccomp: Test PTRACE_O_SUSPEND_SECCOMP without CAP_SYS_ADMIN
2 parents 0bf13a8 + 5e91d2a commit dc8af1f

6 files changed

Lines changed: 482 additions & 5 deletions

File tree

Documentation/userspace-api/seccomp_filter.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,16 @@ notifying process it will be replaced. The supervisor can also add an FD, and
271271
respond atomically by using the ``SECCOMP_ADDFD_FLAG_SEND`` flag and the return
272272
value will be the injected file descriptor number.
273273

274+
The notifying process can be preempted, resulting in the notification being
275+
aborted. This can be problematic when trying to take actions on behalf of the
276+
notifying process that are long-running and typically retryable (mounting a
277+
filesytem). Alternatively, at filter installation time, the
278+
``SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV`` flag can be set. This flag makes it
279+
such that when a user notification is received by the supervisor, the notifying
280+
process will ignore non-fatal signals until the response is sent. Signals that
281+
are sent prior to the notification being received by userspace are handled
282+
normally.
283+
274284
It is worth noting that ``struct seccomp_data`` contains the values of register
275285
arguments to the syscall, but does not contain pointers to memory. The task's
276286
memory is accessible to suitably privileged traces via ``ptrace()`` or

include/linux/seccomp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
SECCOMP_FILTER_FLAG_LOG | \
99
SECCOMP_FILTER_FLAG_SPEC_ALLOW | \
1010
SECCOMP_FILTER_FLAG_NEW_LISTENER | \
11-
SECCOMP_FILTER_FLAG_TSYNC_ESRCH)
11+
SECCOMP_FILTER_FLAG_TSYNC_ESRCH | \
12+
SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV)
1213

1314
/* sizeof() the first published struct seccomp_notif_addfd */
1415
#define SECCOMP_NOTIFY_ADDFD_SIZE_VER0 24

include/uapi/linux/seccomp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2)
2424
#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
2525
#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4)
26+
/* Received notifications wait in killable state (only respond to fatal signals) */
27+
#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5)
2628

2729
/*
2830
* All BPF programs must return a 32-bit value.

kernel/seccomp.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ static inline void seccomp_cache_prepare(struct seccomp_filter *sfilter)
200200
* the filter can be freed.
201201
* @cache: cache of arch/syscall mappings to actions
202202
* @log: true if all actions except for SECCOMP_RET_ALLOW should be logged
203+
* @wait_killable_recv: Put notifying process in killable state once the
204+
* notification is received by the userspace listener.
203205
* @prev: points to a previously installed, or inherited, filter
204206
* @prog: the BPF program to evaluate
205207
* @notif: the struct that holds all notification related information
@@ -220,6 +222,7 @@ struct seccomp_filter {
220222
refcount_t refs;
221223
refcount_t users;
222224
bool log;
225+
bool wait_killable_recv;
223226
struct action_cache cache;
224227
struct seccomp_filter *prev;
225228
struct bpf_prog *prog;
@@ -893,6 +896,10 @@ static long seccomp_attach_filter(unsigned int flags,
893896
if (flags & SECCOMP_FILTER_FLAG_LOG)
894897
filter->log = true;
895898

899+
/* Set wait killable flag, if present. */
900+
if (flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV)
901+
filter->wait_killable_recv = true;
902+
896903
/*
897904
* If there is an existing filter, make it the prev and don't drop its
898905
* task reference.
@@ -1080,6 +1087,12 @@ static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_kn
10801087
complete(&addfd->completion);
10811088
}
10821089

1090+
static bool should_sleep_killable(struct seccomp_filter *match,
1091+
struct seccomp_knotif *n)
1092+
{
1093+
return match->wait_killable_recv && n->state == SECCOMP_NOTIFY_SENT;
1094+
}
1095+
10831096
static int seccomp_do_user_notification(int this_syscall,
10841097
struct seccomp_filter *match,
10851098
const struct seccomp_data *sd)
@@ -1100,7 +1113,7 @@ static int seccomp_do_user_notification(int this_syscall,
11001113
n.data = sd;
11011114
n.id = seccomp_next_notify_id(match);
11021115
init_completion(&n.ready);
1103-
list_add(&n.list, &match->notif->notifications);
1116+
list_add_tail(&n.list, &match->notif->notifications);
11041117
INIT_LIST_HEAD(&n.addfd);
11051118

11061119
up(&match->notif->request);
@@ -1110,11 +1123,25 @@ static int seccomp_do_user_notification(int this_syscall,
11101123
* This is where we wait for a reply from userspace.
11111124
*/
11121125
do {
1126+
bool wait_killable = should_sleep_killable(match, &n);
1127+
11131128
mutex_unlock(&match->notify_lock);
1114-
err = wait_for_completion_interruptible(&n.ready);
1129+
if (wait_killable)
1130+
err = wait_for_completion_killable(&n.ready);
1131+
else
1132+
err = wait_for_completion_interruptible(&n.ready);
11151133
mutex_lock(&match->notify_lock);
1116-
if (err != 0)
1134+
1135+
if (err != 0) {
1136+
/*
1137+
* Check to see if the notifcation got picked up and
1138+
* whether we should switch to wait killable.
1139+
*/
1140+
if (!wait_killable && should_sleep_killable(match, &n))
1141+
continue;
1142+
11171143
goto interrupted;
1144+
}
11181145

11191146
addfd = list_first_entry_or_null(&n.addfd,
11201147
struct seccomp_kaddfd, list);
@@ -1484,6 +1511,9 @@ static long seccomp_notify_recv(struct seccomp_filter *filter,
14841511
mutex_lock(&filter->notify_lock);
14851512
knotif = find_notification(filter, unotif.id);
14861513
if (knotif) {
1514+
/* Reset the process to make sure it's not stuck */
1515+
if (should_sleep_killable(filter, knotif))
1516+
complete(&knotif->ready);
14871517
knotif->state = SECCOMP_NOTIFY_INIT;
14881518
up(&filter->notif->request);
14891519
}
@@ -1829,6 +1859,14 @@ static long seccomp_set_mode_filter(unsigned int flags,
18291859
((flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 0))
18301860
return -EINVAL;
18311861

1862+
/*
1863+
* The SECCOMP_FILTER_FLAG_WAIT_KILLABLE_SENT flag doesn't make sense
1864+
* without the SECCOMP_FILTER_FLAG_NEW_LISTENER flag.
1865+
*/
1866+
if ((flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) &&
1867+
((flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) == 0))
1868+
return -EINVAL;
1869+
18321870
/* Prepare the new filter before holding any locks. */
18331871
prepared = seccomp_prepare_user_filter(filter);
18341872
if (IS_ERR(prepared))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22
CFLAGS += -Wl,-no-as-needed -Wall -isystem ../../../../usr/include/
33
LDFLAGS += -lpthread
4+
LDLIBS += -lcap
45

56
TEST_GEN_PROGS := seccomp_bpf seccomp_benchmark
67
include ../lib.mk

0 commit comments

Comments
 (0)