aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/Kconfig14
-rw-r--r--include/asm-generic/siginfo.h2
-rw-r--r--include/linux/seccomp.h1
-rw-r--r--kernel/seccomp.c26
4 files changed, 37 insertions, 6 deletions
diff --git a/arch/Kconfig b/arch/Kconfig
index beaab68c13b7..66aef13f6038 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -219,11 +219,15 @@ config ARCH_WANT_OLD_COMPAT_IPC
219config HAVE_ARCH_SECCOMP_FILTER 219config HAVE_ARCH_SECCOMP_FILTER
220 bool 220 bool
221 help 221 help
222 This symbol should be selected by an architecure if it provides 222 This symbol should be selected by an architecure if it provides:
223 asm/syscall.h, specifically syscall_get_arguments(), 223 asm/syscall.h:
224 syscall_get_arch(), and syscall_set_return_value(). Additionally, 224 - syscall_get_arch()
225 its system call entry path must respect a return value of -1 from 225 - syscall_get_arguments()
226 __secure_computing() and/or secure_computing(). 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
228config SECCOMP_FILTER 232config SECCOMP_FILTER
229 def_bool y 233 def_bool y
diff --git a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
index 31306f55eb02..af5d0350f84c 100644
--- a/include/asm-generic/siginfo.h
+++ b/include/asm-generic/siginfo.h
@@ -93,7 +93,7 @@ typedef struct siginfo {
93 93
94 /* SIGSYS */ 94 /* SIGSYS */
95 struct { 95 struct {
96 void __user *_call_addr; /* calling insn */ 96 void __user *_call_addr; /* calling user insn */
97 int _syscall; /* triggering system call number */ 97 int _syscall; /* triggering system call number */
98 unsigned int _arch; /* AUDIT_ARCH_* of syscall */ 98 unsigned int _arch; /* AUDIT_ARCH_* of syscall */
99 } _sigsys; 99 } _sigsys;
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index b4ce2c816e06..317ccb78cf40 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -19,6 +19,7 @@
19 * selects the least permissive choice. 19 * selects the least permissive choice.
20 */ 20 */
21#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ 21#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */
22#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */
22#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ 23#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */
23#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ 24#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
24 25
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 5f78fb6d2212..9c3830692a08 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -332,6 +332,26 @@ void put_seccomp_filter(struct task_struct *tsk)
332 kfree(freeme); 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 */
343static 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#endif /* CONFIG_SECCOMP_FILTER */ 355#endif /* CONFIG_SECCOMP_FILTER */
336 356
337/* 357/*
@@ -382,6 +402,12 @@ int __secure_computing(int this_syscall)
382 syscall_set_return_value(current, task_pt_regs(current), 402 syscall_set_return_value(current, task_pt_regs(current),
383 -data, 0); 403 -data, 0);
384 goto skip; 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 case SECCOMP_RET_ALLOW: 411 case SECCOMP_RET_ALLOW:
386 return 0; 412 return 0;
387 case SECCOMP_RET_KILL: 413 case SECCOMP_RET_KILL: