diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index fcb3eb9825e5..3b6cc376fff5 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -10,7 +10,8 @@ SECCOMP_FILTER_FLAG_SPEC_ALLOW | \ SECCOMP_FILTER_FLAG_NEW_LISTENER | \ SECCOMP_FILTER_FLAG_TSYNC_ESRCH | \ - SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV | \ + SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV) /* sizeof() the first published struct seccomp_notif_addfd */ #define SECCOMP_NOTIFY_ADDFD_SIZE_VER0 24 diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index dbfc9b37fcae..30b76aa48355 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -25,6 +25,7 @@ #define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) /* Received notifications wait in killable state (only respond to fatal signals) */ #define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV (1UL << 6) /* * All BPF programs must return a 32-bit value. diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 94c7ba80a8f7..5fc0d8988ce5 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -205,6 +205,7 @@ static inline void seccomp_cache_prepare(struct seccomp_filter *sfilter) * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged * @wait_killable_recv: Put notifying process in killable state once the * notification is received by the userspace listener. + * @restart_before_recv: Restart interrupted syscalls before notification receipt. * @prev: points to a previously installed, or inherited, filter * @prog: the BPF program to evaluate * @notif: the struct that holds all notification related information @@ -226,6 +227,7 @@ struct seccomp_filter { refcount_t users; bool log; bool wait_killable_recv; + bool restart_before_recv; struct action_cache cache; struct seccomp_filter *prev; struct bpf_prog *prog; @@ -953,6 +955,8 @@ static long seccomp_attach_filter(unsigned int flags, /* Set wait killable flag, if present. */ if (flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) filter->wait_killable_recv = true; + if (flags & SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV) + filter->restart_before_recv = true; /* * If there is an existing filter, make it the prev and don't drop its @@ -1208,8 +1212,12 @@ static int seccomp_do_user_notification(int this_syscall, * Check to see whether we should switch to wait * killable. Only return the interrupted error if not. */ - if (!(!wait_killable && should_sleep_killable(match, &n))) + if (!(!wait_killable && should_sleep_killable(match, &n))) { + if (err == -ERESTARTSYS && match->restart_before_recv && + n.state == SECCOMP_NOTIFY_INIT) + err = -ERESTARTNOINTR; goto interrupted; + } } addfd = list_first_entry_or_null(&n.addfd, @@ -1980,10 +1988,10 @@ static long seccomp_set_mode_filter(unsigned int flags, return -EINVAL; /* - * The SECCOMP_FILTER_FLAG_WAIT_KILLABLE_SENT flag doesn't make sense - * without the SECCOMP_FILTER_FLAG_NEW_LISTENER flag. + * Notification wait flags require a userspace listener. */ - if ((flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) && + if ((flags & (SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV | + SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV)) && ((flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) == 0)) return -EINVAL; diff --git a/tools/include/uapi/linux/seccomp.h b/tools/include/uapi/linux/seccomp.h index dbfc9b37fcae..30b76aa48355 100644 --- a/tools/include/uapi/linux/seccomp.h +++ b/tools/include/uapi/linux/seccomp.h @@ -25,6 +25,7 @@ #define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) /* Received notifications wait in killable state (only respond to fatal signals) */ #define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_RESTART_BEFORE_RECV (1UL << 6) /* * All BPF programs must return a 32-bit value.