Skip to content

Commit b94ae8a

Browse files
committed
Merge tag 'seccomp-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux
Pull seccomp updates from Kees Cook: "Mostly this is implementing the new flag SECCOMP_USER_NOTIF_FLAG_CONTINUE, but there are cleanups as well. - implement SECCOMP_USER_NOTIF_FLAG_CONTINUE (Christian Brauner) - fixes to selftests (Christian Brauner) - remove secure_computing() argument (Christian Brauner)" * tag 'seccomp-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: seccomp: rework define for SECCOMP_USER_NOTIF_FLAG_CONTINUE seccomp: fix SECCOMP_USER_NOTIF_FLAG_CONTINUE test seccomp: simplify secure_computing() seccomp: test SECCOMP_USER_NOTIF_FLAG_CONTINUE seccomp: add SECCOMP_USER_NOTIF_FLAG_CONTINUE seccomp: avoid overflow in implicit constant conversion
2 parents 3b805ca + 23b2c96 commit b94ae8a

File tree

11 files changed

+170
-17
lines changed

11 files changed

+170
-17
lines changed

arch/arm/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -923,7 +923,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
923923

924924
/* Do seccomp after ptrace; syscall may have changed. */
925925
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
926-
if (secure_computing(NULL) == -1)
926+
if (secure_computing() == -1)
927927
return -1;
928928
#else
929929
/* XXX: remove this once OABI gets fixed */

arch/arm64/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ int syscall_trace_enter(struct pt_regs *regs)
18161816
}
18171817

18181818
/* Do the secure computing after ptrace; failures should be fast. */
1819-
if (secure_computing(NULL) == -1)
1819+
if (secure_computing() == -1)
18201820
return -1;
18211821

18221822
if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))

arch/parisc/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ long do_syscall_trace_enter(struct pt_regs *regs)
342342
}
343343

344344
/* Do the secure computing check after ptrace. */
345-
if (secure_computing(NULL) == -1)
345+
if (secure_computing() == -1)
346346
return -1;
347347

348348
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS

arch/riscv/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ __visible void do_syscall_trace_enter(struct pt_regs *regs)
159159
* If this fails we might have return value in a0 from seccomp
160160
* (via SECCOMP_RET_ERRNO/TRACE).
161161
*/
162-
if (secure_computing(NULL) == -1) {
162+
if (secure_computing() == -1) {
163163
syscall_set_nr(current, regs, -1);
164164
return;
165165
}

arch/s390/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
856856
}
857857

858858
/* Do the secure computing check after ptrace. */
859-
if (secure_computing(NULL)) {
859+
if (secure_computing()) {
860860
/* seccomp failures shouldn't expose any additional code. */
861861
return -1;
862862
}

arch/um/kernel/skas/syscall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void handle_syscall(struct uml_pt_regs *r)
3535
goto out;
3636

3737
/* Do the seccomp check after ptrace; failures should be fast. */
38-
if (secure_computing(NULL) == -1)
38+
if (secure_computing() == -1)
3939
goto out;
4040

4141
syscall = UPT_SYSCALL_NR(r);

arch/x86/entry/vsyscall/vsyscall_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ bool emulate_vsyscall(unsigned long error_code,
222222
*/
223223
regs->orig_ax = syscall_nr;
224224
regs->ax = -ENOSYS;
225-
tmp = secure_computing(NULL);
225+
tmp = secure_computing();
226226
if ((!tmp && regs->orig_ax != syscall_nr) || regs->ip != address) {
227227
warn_bad_vsyscall(KERN_DEBUG, regs,
228228
"seccomp tried to change syscall nr or ip");

include/linux/seccomp.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@ struct seccomp {
3333

3434
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
3535
extern int __secure_computing(const struct seccomp_data *sd);
36-
static inline int secure_computing(const struct seccomp_data *sd)
36+
static inline int secure_computing(void)
3737
{
3838
if (unlikely(test_thread_flag(TIF_SECCOMP)))
39-
return __secure_computing(sd);
39+
return __secure_computing(NULL);
4040
return 0;
4141
}
4242
#else
@@ -59,7 +59,7 @@ struct seccomp { };
5959
struct seccomp_filter { };
6060

6161
#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
62-
static inline int secure_computing(struct seccomp_data *sd) { return 0; }
62+
static inline int secure_computing(void) { return 0; }
6363
#else
6464
static inline void secure_computing_strict(int this_syscall) { return; }
6565
#endif

include/uapi/linux/seccomp.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,35 @@ struct seccomp_notif {
7676
struct seccomp_data data;
7777
};
7878

79+
/*
80+
* Valid flags for struct seccomp_notif_resp
81+
*
82+
* Note, the SECCOMP_USER_NOTIF_FLAG_CONTINUE flag must be used with caution!
83+
* If set by the process supervising the syscalls of another process the
84+
* syscall will continue. This is problematic because of an inherent TOCTOU.
85+
* An attacker can exploit the time while the supervised process is waiting on
86+
* a response from the supervising process to rewrite syscall arguments which
87+
* are passed as pointers of the intercepted syscall.
88+
* It should be absolutely clear that this means that the seccomp notifier
89+
* _cannot_ be used to implement a security policy! It should only ever be used
90+
* in scenarios where a more privileged process supervises the syscalls of a
91+
* lesser privileged process to get around kernel-enforced security
92+
* restrictions when the privileged process deems this safe. In other words,
93+
* in order to continue a syscall the supervising process should be sure that
94+
* another security mechanism or the kernel itself will sufficiently block
95+
* syscalls if arguments are rewritten to something unsafe.
96+
*
97+
* Similar precautions should be applied when stacking SECCOMP_RET_USER_NOTIF
98+
* or SECCOMP_RET_TRACE. For SECCOMP_RET_USER_NOTIF filters acting on the
99+
* same syscall, the most recently added filter takes precedence. This means
100+
* that the new SECCOMP_RET_USER_NOTIF filter can override any
101+
* SECCOMP_IOCTL_NOTIF_SEND from earlier filters, essentially allowing all
102+
* such filtered syscalls to be executed by sending the response
103+
* SECCOMP_USER_NOTIF_FLAG_CONTINUE. Note that SECCOMP_RET_TRACE can equally
104+
* be overriden by SECCOMP_USER_NOTIF_FLAG_CONTINUE.
105+
*/
106+
#define SECCOMP_USER_NOTIF_FLAG_CONTINUE (1UL << 0)
107+
79108
struct seccomp_notif_resp {
80109
__u64 id;
81110
__s64 val;

kernel/seccomp.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct seccomp_knotif {
7575
/* The return values, only valid when in SECCOMP_NOTIFY_REPLIED */
7676
int error;
7777
long val;
78+
u32 flags;
7879

7980
/* Signals when this has entered SECCOMP_NOTIFY_REPLIED */
8081
struct completion ready;
@@ -732,11 +733,12 @@ static u64 seccomp_next_notify_id(struct seccomp_filter *filter)
732733
return filter->notif->next_id++;
733734
}
734735

735-
static void seccomp_do_user_notification(int this_syscall,
736-
struct seccomp_filter *match,
737-
const struct seccomp_data *sd)
736+
static int seccomp_do_user_notification(int this_syscall,
737+
struct seccomp_filter *match,
738+
const struct seccomp_data *sd)
738739
{
739740
int err;
741+
u32 flags = 0;
740742
long ret = 0;
741743
struct seccomp_knotif n = {};
742744

@@ -764,6 +766,7 @@ static void seccomp_do_user_notification(int this_syscall,
764766
if (err == 0) {
765767
ret = n.val;
766768
err = n.error;
769+
flags = n.flags;
767770
}
768771

769772
/*
@@ -780,8 +783,14 @@ static void seccomp_do_user_notification(int this_syscall,
780783
list_del(&n.list);
781784
out:
782785
mutex_unlock(&match->notify_lock);
786+
787+
/* Userspace requests to continue the syscall. */
788+
if (flags & SECCOMP_USER_NOTIF_FLAG_CONTINUE)
789+
return 0;
790+
783791
syscall_set_return_value(current, task_pt_regs(current),
784792
err, ret);
793+
return -1;
785794
}
786795

787796
static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
@@ -867,8 +876,10 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
867876
return 0;
868877

869878
case SECCOMP_RET_USER_NOTIF:
870-
seccomp_do_user_notification(this_syscall, match, sd);
871-
goto skip;
879+
if (seccomp_do_user_notification(this_syscall, match, sd))
880+
goto skip;
881+
882+
return 0;
872883

873884
case SECCOMP_RET_LOG:
874885
seccomp_log(this_syscall, 0, action, true);
@@ -1087,7 +1098,11 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
10871098
if (copy_from_user(&resp, buf, sizeof(resp)))
10881099
return -EFAULT;
10891100

1090-
if (resp.flags)
1101+
if (resp.flags & ~SECCOMP_USER_NOTIF_FLAG_CONTINUE)
1102+
return -EINVAL;
1103+
1104+
if ((resp.flags & SECCOMP_USER_NOTIF_FLAG_CONTINUE) &&
1105+
(resp.error || resp.val))
10911106
return -EINVAL;
10921107

10931108
ret = mutex_lock_interruptible(&filter->notify_lock);
@@ -1116,6 +1131,7 @@ static long seccomp_notify_send(struct seccomp_filter *filter,
11161131
knotif->state = SECCOMP_NOTIFY_REPLIED;
11171132
knotif->error = resp.error;
11181133
knotif->val = resp.val;
1134+
knotif->flags = resp.flags;
11191135
complete(&knotif->ready);
11201136
out:
11211137
mutex_unlock(&filter->notify_lock);

0 commit comments

Comments
 (0)