UBUNTU: SAUCE: SECCOMP: seccomp: Add SECCOMP_RET_TRAP
authorWill Drewry <wad@chromium.org>
Thu, 9 Feb 2012 18:01:37 +0000 (12:01 -0600)
committerLeann Ogasawara <leann.ogasawara@canonical.com>
Mon, 2 Apr 2012 20:23:06 +0000 (13:23 -0700)
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.

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

Suggested-by: Markus Gutschke <markus@chromium.org>
Suggested-by: Julien Tinnes <jln@chromium.org>
Signed-off-by: Will Drewry <wad@chromium.org>
Signed-off-by: Kees Cook <kees@ubuntu.com>

arch/Kconfig
include/asm-generic/siginfo.h
include/linux/seccomp.h
kernel/seccomp.c

index aded1e6..6a86341 100644 (file)
@@ -184,11 +184,15 @@ config ARCH_HAVE_NMI_SAFE_CMPXCHG
 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_int() 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_int()/secure_computing()'s return value must be
+         checked, with -1 resulting in the syscall being skipped.
 
 config SECCOMP_FILTER
        def_bool y
index 31306f5..af5d035 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 12bb2e3..a5078fb 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 4293396..d760ab8 100644 (file)
@@ -329,6 +329,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 */
 
 /*
@@ -386,6 +406,12 @@ int __secure_computing_int(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: