seccomp: Add SECCOMP_RET_TRAP
authorWill Drewry <wad@chromium.org>
Thu, 12 Apr 2012 21:48:01 +0000 (16:48 -0500)
committerJames Morris <james.l.morris@oracle.com>
Sat, 14 Apr 2012 01:13:21 +0000 (11:13 +1000)
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>
v18: - acked-by, rebase
     - don't mention secure_computing_int() anymore
v15: - use audit_seccomp/skip
     - pad out error spacing; clean up switch (indan@nul.nu)
v14: - n/a
v13: - rebase on to 88ebdda6159ffc15699f204c33feb3e431bf9bdc
v12: - rebase on to linux-next
v11: - clarify the comment (indan@nul.nu)
     - s/sigtrap/sigsys
v10: - use SIGSYS, syscall_get_arch, updates arch/Kconfig
       note suggested-by (though original suggestion had other behaviors)
v9:  - changes to SIGILL
v8:  - clean up based on changes to dependent patches
v7:  - introduction
Signed-off-by: James Morris <james.l.morris@oracle.com>
arch/Kconfig
include/asm-generic/siginfo.h
include/linux/seccomp.h
kernel/seccomp.c

index beaab68c13b73b7cfc5e19e83595992f0b8635eb..66aef13f6038c5da0ffd2d70c11b4e952bc55d10 100644 (file)
@@ -219,11 +219,15 @@ config ARCH_WANT_OLD_COMPAT_IPC
 config HAVE_ARCH_SECCOMP_FILTER
        bool
        help
-         This symbol should be selected by an architecure if it provides
-         asm/syscall.h, specifically syscall_get_arguments(),
-         syscall_get_arch(), and syscall_set_return_value().  Additionally,
-         its system call entry path must respect a return value of -1 from
-         __secure_computing() and/or secure_computing().
+         This symbol should be selected by an architecure if it provides:
+         asm/syscall.h:
+         - syscall_get_arch()
+         - syscall_get_arguments()
+         - syscall_rollback()
+         - syscall_set_return_value()
+         SIGSYS siginfo_t support must be implemented.
+         __secure_computing()/secure_computing()'s return value must be
+         checked, with -1 resulting in the syscall being skipped.
 
 config SECCOMP_FILTER
        def_bool y
index 31306f55eb0237cf83c4bde9a90ff433d49bcd65..af5d0350f84cc030070e656445ef908bb29648ac 100644 (file)
@@ -93,7 +93,7 @@ typedef struct siginfo {
 
                /* SIGSYS */
                struct {
-                       void __user *_call_addr; /* calling insn */
+                       void __user *_call_addr; /* calling user insn */
                        int _syscall;   /* triggering system call number */
                        unsigned int _arch;     /* AUDIT_ARCH_* of syscall */
                } _sigsys;
index b4ce2c816e0679fd2013922e36f84e24e93f4d29..317ccb78cf400fe92beff1c115bf7b330091e877 100644 (file)
@@ -19,6 +19,7 @@
  * selects the least permissive choice.
  */
 #define SECCOMP_RET_KILL       0x00000000U /* kill the task immediately */
+#define SECCOMP_RET_TRAP       0x00030000U /* disallow and force a SIGSYS */
 #define SECCOMP_RET_ERRNO      0x00050000U /* returns an errno */
 #define SECCOMP_RET_ALLOW      0x7fff0000U /* allow */
 
index 5f78fb6d2212da8e7c54e7fe736174e951e10c1b..9c3830692a0811ffc2de4cc4c8e81d8ce2ddc06e 100644 (file)
@@ -332,6 +332,26 @@ void put_seccomp_filter(struct task_struct *tsk)
                kfree(freeme);
        }
 }
+
+/**
+ * seccomp_send_sigsys - signals the task to allow in-process syscall emulation
+ * @syscall: syscall number to send to userland
+ * @reason: filter-supplied reason code to send to userland (via si_errno)
+ *
+ * Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info.
+ */
+static void seccomp_send_sigsys(int syscall, int reason)
+{
+       struct siginfo info;
+       memset(&info, 0, sizeof(info));
+       info.si_signo = SIGSYS;
+       info.si_code = SYS_SECCOMP;
+       info.si_call_addr = (void __user *)KSTK_EIP(current);
+       info.si_errno = reason;
+       info.si_arch = syscall_get_arch(current, task_pt_regs(current));
+       info.si_syscall = syscall;
+       force_sig_info(SIGSYS, &info, current);
+}
 #endif /* CONFIG_SECCOMP_FILTER */
 
 /*
@@ -382,6 +402,12 @@ int __secure_computing(int this_syscall)
                        syscall_set_return_value(current, task_pt_regs(current),
                                                 -data, 0);
                        goto skip;
+               case SECCOMP_RET_TRAP:
+                       /* Show the handler the original registers. */
+                       syscall_rollback(current, task_pt_regs(current));
+                       /* Let the filter pass back 16 bits of data. */
+                       seccomp_send_sigsys(this_syscall, data);
+                       goto skip;
                case SECCOMP_RET_ALLOW:
                        return 0;
                case SECCOMP_RET_KILL: