aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2017-08-11 16:12:11 -0400
committerKees Cook <keescook@chromium.org>2017-08-14 16:46:50 -0400
commit0466bdb99e8744bc9befa8d62a317f0fd7fd7421 (patch)
tree4707235470b155b9e4949ec35621814e5a873ce7
parent4d3b0b05aae9ee9ce0970dc4cc0fb3fad5e85945 (diff)
seccomp: Implement SECCOMP_RET_KILL_PROCESS action
Right now, SECCOMP_RET_KILL_THREAD (neƩ SECCOMP_RET_KILL) kills the current thread. There have been a few requests for this to kill the entire process (the thread group). This cannot be just changed (discovered when adding coredump support since coredumping kills the entire process) because there are userspace programs depending on the thread-kill behavior. Instead, implement SECCOMP_RET_KILL_PROCESS, which is 0x80000000, and can be processed as "-1" by the kernel, below the existing RET_KILL that is ABI-set to "0". For userspace, SECCOMP_RET_ACTION_FULL is added to expand the mask to the signed bit. Old userspace using the SECCOMP_RET_ACTION mask will see SECCOMP_RET_KILL_PROCESS as 0 still, but this would only be visible when examining the siginfo in a core dump from a RET_KILL_*, where it will think it was thread-killed instead of process-killed. Attempts to introduce this behavior via other ways (filter flags, seccomp struct flags, masked RET_DATA bits) all come with weird side-effects and baggage. This change preserves the central behavioral expectations of the seccomp filter engine without putting too great a burden on changes needed in userspace to use the new action. The new action is discoverable by userspace through either the new actions_avail sysctl or through the SECCOMP_GET_ACTION_AVAIL seccomp operation. If used without checking for availability, old kernels will treat RET_KILL_PROCESS as RET_KILL_THREAD (since the old mask will produce RET_KILL_THREAD). Cc: Paul Moore <paul@paul-moore.com> Cc: Fabricio Voznika <fvoznika@google.com> Signed-off-by: Kees Cook <keescook@chromium.org>
-rw-r--r--Documentation/userspace-api/seccomp_filter.rst7
-rw-r--r--include/uapi/linux/seccomp.h1
-rw-r--r--kernel/seccomp.c9
3 files changed, 14 insertions, 3 deletions
diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst
index d76396f2d8ed..099c412951d6 100644
--- a/Documentation/userspace-api/seccomp_filter.rst
+++ b/Documentation/userspace-api/seccomp_filter.rst
@@ -87,10 +87,15 @@ Return values
87A seccomp filter may return any of the following values. If multiple 87A seccomp filter may return any of the following values. If multiple
88filters exist, the return value for the evaluation of a given system 88filters exist, the return value for the evaluation of a given system
89call will always use the highest precedent value. (For example, 89call will always use the highest precedent value. (For example,
90``SECCOMP_RET_KILL_THREAD`` will always take precedence.) 90``SECCOMP_RET_KILL_PROCESS`` will always take precedence.)
91 91
92In precedence order, they are: 92In precedence order, they are:
93 93
94``SECCOMP_RET_KILL_PROCESS``:
95 Results in the entire process exiting immediately without executing
96 the system call. The exit status of the task (``status & 0x7f``)
97 will be ``SIGSYS``, not ``SIGKILL``.
98
94``SECCOMP_RET_KILL_THREAD``: 99``SECCOMP_RET_KILL_THREAD``:
95 Results in the task exiting immediately without executing the 100 Results in the task exiting immediately without executing the
96 system call. The exit status of the task (``status & 0x7f``) will 101 system call. The exit status of the task (``status & 0x7f``) will
diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h
index 7e77c92df78a..f6bc1dea3247 100644
--- a/include/uapi/linux/seccomp.h
+++ b/include/uapi/linux/seccomp.h
@@ -38,6 +38,7 @@
38#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ 38#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */
39 39
40/* Masks for the return value sections. */ 40/* Masks for the return value sections. */
41#define SECCOMP_RET_ACTION_FULL 0xffff0000U
41#define SECCOMP_RET_ACTION 0x7fff0000U 42#define SECCOMP_RET_ACTION 0x7fff0000U
42#define SECCOMP_RET_DATA 0x0000ffffU 43#define SECCOMP_RET_DATA 0x0000ffffU
43 44
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 5c7299b9d953..c24579dfa7a1 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -181,6 +181,7 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen)
181 * 181 *
182 * Returns valid seccomp BPF response codes. 182 * Returns valid seccomp BPF response codes.
183 */ 183 */
184#define ACTION_ONLY(ret) ((s32)((ret) & (SECCOMP_RET_ACTION_FULL)))
184static u32 seccomp_run_filters(const struct seccomp_data *sd, 185static u32 seccomp_run_filters(const struct seccomp_data *sd,
185 struct seccomp_filter **match) 186 struct seccomp_filter **match)
186{ 187{
@@ -206,7 +207,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
206 for (; f; f = f->prev) { 207 for (; f; f = f->prev) {
207 u32 cur_ret = BPF_PROG_RUN(f->prog, sd); 208 u32 cur_ret = BPF_PROG_RUN(f->prog, sd);
208 209
209 if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) { 210 if (ACTION_ONLY(cur_ret) < ACTION_ONLY(ret)) {
210 ret = cur_ret; 211 ret = cur_ret;
211 *match = f; 212 *match = f;
212 } 213 }
@@ -650,7 +651,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
650 651
651 filter_ret = seccomp_run_filters(sd, &match); 652 filter_ret = seccomp_run_filters(sd, &match);
652 data = filter_ret & SECCOMP_RET_DATA; 653 data = filter_ret & SECCOMP_RET_DATA;
653 action = filter_ret & SECCOMP_RET_ACTION; 654 action = filter_ret & SECCOMP_RET_ACTION_FULL;
654 655
655 switch (action) { 656 switch (action) {
656 case SECCOMP_RET_ERRNO: 657 case SECCOMP_RET_ERRNO:
@@ -890,6 +891,7 @@ static long seccomp_get_action_avail(const char __user *uaction)
890 return -EFAULT; 891 return -EFAULT;
891 892
892 switch (action) { 893 switch (action) {
894 case SECCOMP_RET_KILL_PROCESS:
893 case SECCOMP_RET_KILL_THREAD: 895 case SECCOMP_RET_KILL_THREAD:
894 case SECCOMP_RET_TRAP: 896 case SECCOMP_RET_TRAP:
895 case SECCOMP_RET_ERRNO: 897 case SECCOMP_RET_ERRNO:
@@ -1041,6 +1043,7 @@ out:
1041#ifdef CONFIG_SYSCTL 1043#ifdef CONFIG_SYSCTL
1042 1044
1043/* Human readable action names for friendly sysctl interaction */ 1045/* Human readable action names for friendly sysctl interaction */
1046#define SECCOMP_RET_KILL_PROCESS_NAME "kill_process"
1044#define SECCOMP_RET_KILL_THREAD_NAME "kill_thread" 1047#define SECCOMP_RET_KILL_THREAD_NAME "kill_thread"
1045#define SECCOMP_RET_TRAP_NAME "trap" 1048#define SECCOMP_RET_TRAP_NAME "trap"
1046#define SECCOMP_RET_ERRNO_NAME "errno" 1049#define SECCOMP_RET_ERRNO_NAME "errno"
@@ -1049,6 +1052,7 @@ out:
1049#define SECCOMP_RET_ALLOW_NAME "allow" 1052#define SECCOMP_RET_ALLOW_NAME "allow"
1050 1053
1051static const char seccomp_actions_avail[] = 1054static const char seccomp_actions_avail[] =
1055 SECCOMP_RET_KILL_PROCESS_NAME " "
1052 SECCOMP_RET_KILL_THREAD_NAME " " 1056 SECCOMP_RET_KILL_THREAD_NAME " "
1053 SECCOMP_RET_TRAP_NAME " " 1057 SECCOMP_RET_TRAP_NAME " "
1054 SECCOMP_RET_ERRNO_NAME " " 1058 SECCOMP_RET_ERRNO_NAME " "
@@ -1062,6 +1066,7 @@ struct seccomp_log_name {
1062}; 1066};
1063 1067
1064static const struct seccomp_log_name seccomp_log_names[] = { 1068static const struct seccomp_log_name seccomp_log_names[] = {
1069 { SECCOMP_LOG_KILL_PROCESS, SECCOMP_RET_KILL_PROCESS_NAME },
1065 { SECCOMP_LOG_KILL_THREAD, SECCOMP_RET_KILL_THREAD_NAME }, 1070 { SECCOMP_LOG_KILL_THREAD, SECCOMP_RET_KILL_THREAD_NAME },
1066 { SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME }, 1071 { SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
1067 { SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME }, 1072 { SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },