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>
Showing the changes to kernel (1 of 4 files). Show all
Unified · Split
| @@ -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: |