Adds a new return value to seccomp filters that triggers a SIGSYS to be delivered with the new SYS_SECCOMP si_code. This allows in-process system call emulation, including just specifying an errno or cleanly dumping core, rather than just dying. Suggested-by: Markus Gutschke <markus@chromium.org> Suggested-by: Julien Tinnes <jln@chromium.org> Signed-off-by: Will Drewry <wad@chromium.org> Acked-by: Eric Paris <eparis@redhat.com>
Unified · Split
| @@ -219,11 +219,15 @@ config ARCH_WANT_OLD_COMPAT_IPC · 218 unmodified lines | ||
| 219 | 219 | config HAVE_ARCH_SECCOMP_FILTER |
| 220 | 220 | bool |
| 221 | 221 | help |
| 222 | − This symbol should be selected by an architecure if it provides | |
| 223 | − asm/syscall.h, specifically syscall_get_arguments(), | |
| 224 | − syscall_get_arch(), and syscall_set_return_value(). Additionally, | |
| 225 | − its system call entry path must respect a return value of -1 from | |
| 226 | − __secure_computing() and/or secure_computing(). | |
| 222 | + This symbol should be selected by an architecure if it provides: | |
| 223 | + asm/syscall.h: | |
| 224 | + - syscall_get_arch() | |
| 225 | + - syscall_get_arguments() | |
| 226 | + - syscall_rollback() | |
| 227 | + - syscall_set_return_value() | |
| 228 | + SIGSYS siginfo_t support must be implemented. | |
| 229 | + __secure_computing()/secure_computing()'s return value must be | |
| 230 | + checked, with -1 resulting in the syscall being skipped. | |
| 227 | 231 | |
| 228 | 232 | config SECCOMP_FILTER |
| 229 | 233 | def_bool y |
| @@ -93,7 +93,7 @@ typedef struct siginfo { · 92 unmodified lines | ||
| 93 | 93 | |
| 94 | 94 | /* SIGSYS */ |
| 95 | 95 | struct { |
| 96 | − void __user *_call_addr; /* calling insn */ | |
| 96 | + void __user *_call_addr; /* calling user insn */ | |
| 97 | 97 | int _syscall; /* triggering system call number */ |
| 98 | 98 | unsigned int _arch; /* AUDIT_ARCH_* of syscall */ |
| 99 | 99 | } _sigsys; |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | * selects the least permissive choice. |
| 20 | 20 | */ |
| 21 | 21 | #define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ |
| 22 | +#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ | |
| 22 | 23 | #define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ |
| 23 | 24 | #define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ |
| 24 | 25 | |
| @@ -332,6 +332,26 @@ void put_seccomp_filter(struct task_struct *tsk) · 331 unmodified lines | ||
| 332 | 332 | kfree(freeme); |
| 333 | 333 | } |
| 334 | 334 | } |
| 335 | + | |
| 336 | +/** | |
| 337 | + * seccomp_send_sigsys - signals the task to allow in-process syscall emulation | |
| 338 | + * @syscall: syscall number to send to userland | |
| 339 | + * @reason: filter-supplied reason code to send to userland (via si_errno) | |
| 340 | + * | |
| 341 | + * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info. | |
| 342 | + */ | |
| 343 | +static void seccomp_send_sigsys(int syscall, int reason) | |
| 344 | +{ | |
| 345 | + struct siginfo info; | |
| 346 | + memset(&info, 0, sizeof(info)); | |
| 347 | + info.si_signo = SIGSYS; | |
| 348 | + info.si_code = SYS_SECCOMP; | |
| 349 | + info.si_call_addr = (void __user *)KSTK_EIP(current); | |
| 350 | + info.si_errno = reason; | |
| 351 | + info.si_arch = syscall_get_arch(current, task_pt_regs(current)); | |
| 352 | + info.si_syscall = syscall; | |
| 353 | + force_sig_info(SIGSYS, &info, current); | |
| 354 | +} | |
| 335 | 355 | #endif /* CONFIG_SECCOMP_FILTER */ |
| 336 | 356 | |
| 337 | 357 | /* |
| @@ -382,6 +402,12 @@ int __secure_computing(int this_syscall) · 44 unmodified lines | ||
| 382 | 402 | syscall_set_return_value(current, task_pt_regs(current), |
| 383 | 403 | -data, 0); |
| 384 | 404 | goto skip; |
| 405 | + case SECCOMP_RET_TRAP: | |
| 406 | + /* Show the handler the original registers. */ | |
| 407 | + syscall_rollback(current, task_pt_regs(current)); | |
| 408 | + /* Let the filter pass back 16 bits of data. */ | |
| 409 | + seccomp_send_sigsys(this_syscall, data); | |
| 410 | + goto skip; | |
| 385 | 411 | case SECCOMP_RET_ALLOW: |
| 386 | 412 | return 0; |
| 387 | 413 | case SECCOMP_RET_KILL: |