]> Pileus Git - ~andy/linux/blobdiff - kernel/seccomp.c
seccomp: Add SECCOMP_RET_TRAP
[~andy/linux] / kernel / seccomp.c
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: