aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@canonical.com>2017-08-11 00:33:54 -0400
committerKees Cook <keescook@chromium.org>2017-08-14 16:46:45 -0400
commit0ddec0fc8900201c0897b87b762b7c420436662f (patch)
treed860565f915e9adcd57e113befc3d3bba7b3c085
parentd612b1fd8010d0d67b5287fe146b8b55bcbb8655 (diff)
seccomp: Sysctl to configure actions that are allowed to be logged
Adminstrators can write to this sysctl to set the seccomp actions that are allowed to be logged. Any actions not found in this sysctl will not be logged. For example, all SECCOMP_RET_KILL, SECCOMP_RET_TRAP, and SECCOMP_RET_ERRNO actions would be loggable if "kill trap errno" were written to the sysctl. SECCOMP_RET_TRACE actions would not be logged since its string representation ("trace") wasn't present in the sysctl value. The path to the sysctl is: /proc/sys/kernel/seccomp/actions_logged The actions_avail sysctl can be read to discover the valid action names that can be written to the actions_logged sysctl with the exception of "allow". SECCOMP_RET_ALLOW actions cannot be configured for logging. The default setting for the sysctl is to allow all actions to be logged except SECCOMP_RET_ALLOW. While only SECCOMP_RET_KILL actions are currently logged, an upcoming patch will allow applications to request additional actions to be logged. There's one important exception to this sysctl. If a task is specifically being audited, meaning that an audit context has been allocated for the task, seccomp will log all actions other than SECCOMP_RET_ALLOW despite the value of actions_logged. This exception preserves the existing auditing behavior of tasks with an allocated audit context. With this patch, the logic for deciding if an action will be logged is: if action == RET_ALLOW: do not log else if action == RET_KILL && RET_KILL in actions_logged: log else if audit_enabled && task-is-being-audited: log else: do not log Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Signed-off-by: Kees Cook <keescook@chromium.org>
-rw-r--r--Documentation/userspace-api/seccomp_filter.rst18
-rw-r--r--include/linux/audit.h6
-rw-r--r--kernel/seccomp.c171
3 files changed, 187 insertions, 8 deletions
diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation/userspace-api/seccomp_filter.rst
index 35fc7cbf1d95..2d1d8ab04ac5 100644
--- a/Documentation/userspace-api/seccomp_filter.rst
+++ b/Documentation/userspace-api/seccomp_filter.rst
@@ -187,6 +187,24 @@ directory. Here's a description of each file in that directory:
187 program was built, differs from the set of actions actually 187 program was built, differs from the set of actions actually
188 supported in the current running kernel. 188 supported in the current running kernel.
189 189
190``actions_logged``:
191 A read-write ordered list of seccomp return values (refer to the
192 ``SECCOMP_RET_*`` macros above) that are allowed to be logged. Writes
193 to the file do not need to be in ordered form but reads from the file
194 will be ordered in the same way as the actions_avail sysctl.
195
196 It is important to note that the value of ``actions_logged`` does not
197 prevent certain actions from being logged when the audit subsystem is
198 configured to audit a task. If the action is not found in
199 ``actions_logged`` list, the final decision on whether to audit the
200 action for that task is ultimately left up to the audit subsystem to
201 decide for all seccomp return values other than ``SECCOMP_RET_ALLOW``.
202
203 The ``allow`` string is not accepted in the ``actions_logged`` sysctl
204 as it is not possible to log ``SECCOMP_RET_ALLOW`` actions. Attempting
205 to write ``allow`` to the sysctl will result in an EINVAL being
206 returned.
207
190Adding architecture support 208Adding architecture support
191=========================== 209===========================
192 210
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 2150bdccfbab..8c30f06d639d 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -314,11 +314,7 @@ void audit_core_dumps(long signr);
314 314
315static inline void audit_seccomp(unsigned long syscall, long signr, int code) 315static inline void audit_seccomp(unsigned long syscall, long signr, int code)
316{ 316{
317 if (!audit_enabled) 317 if (audit_enabled && unlikely(!audit_dummy_context()))
318 return;
319
320 /* Force a record to be reported if a signal was delivered. */
321 if (signr || unlikely(!audit_dummy_context()))
322 __audit_seccomp(syscall, signr, code); 318 __audit_seccomp(syscall, signr, code);
323} 319}
324 320
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 7a6089f66fed..54357e361aea 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -522,6 +522,45 @@ static void seccomp_send_sigsys(int syscall, int reason)
522} 522}
523#endif /* CONFIG_SECCOMP_FILTER */ 523#endif /* CONFIG_SECCOMP_FILTER */
524 524
525/* For use with seccomp_actions_logged */
526#define SECCOMP_LOG_KILL (1 << 0)
527#define SECCOMP_LOG_TRAP (1 << 2)
528#define SECCOMP_LOG_ERRNO (1 << 3)
529#define SECCOMP_LOG_TRACE (1 << 4)
530#define SECCOMP_LOG_ALLOW (1 << 5)
531
532static u32 seccomp_actions_logged = SECCOMP_LOG_KILL | SECCOMP_LOG_TRAP |
533 SECCOMP_LOG_ERRNO | SECCOMP_LOG_TRACE;
534
535static inline void seccomp_log(unsigned long syscall, long signr, u32 action)
536{
537 bool log = false;
538
539 switch (action) {
540 case SECCOMP_RET_ALLOW:
541 case SECCOMP_RET_TRAP:
542 case SECCOMP_RET_ERRNO:
543 case SECCOMP_RET_TRACE:
544 break;
545 case SECCOMP_RET_KILL:
546 default:
547 log = seccomp_actions_logged & SECCOMP_LOG_KILL;
548 }
549
550 /*
551 * Force an audit message to be emitted when the action is RET_KILL and
552 * the action is allowed to be logged by the admin.
553 */
554 if (log)
555 return __audit_seccomp(syscall, signr, action);
556
557 /*
558 * Let the audit subsystem decide if the action should be audited based
559 * on whether the current task itself is being audited.
560 */
561 return audit_seccomp(syscall, signr, action);
562}
563
525/* 564/*
526 * Secure computing mode 1 allows only read/write/exit/sigreturn. 565 * Secure computing mode 1 allows only read/write/exit/sigreturn.
527 * To be fully secure this must be combined with rlimit 566 * To be fully secure this must be combined with rlimit
@@ -547,7 +586,7 @@ static void __secure_computing_strict(int this_syscall)
547#ifdef SECCOMP_DEBUG 586#ifdef SECCOMP_DEBUG
548 dump_stack(); 587 dump_stack();
549#endif 588#endif
550 audit_seccomp(this_syscall, SIGKILL, SECCOMP_RET_KILL); 589 seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL);
551 do_exit(SIGKILL); 590 do_exit(SIGKILL);
552} 591}
553 592
@@ -656,7 +695,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
656 695
657 case SECCOMP_RET_KILL: 696 case SECCOMP_RET_KILL:
658 default: 697 default:
659 audit_seccomp(this_syscall, SIGSYS, action); 698 seccomp_log(this_syscall, SIGSYS, action);
660 /* Dump core only if this is the last remaining thread. */ 699 /* Dump core only if this is the last remaining thread. */
661 if (get_nr_threads(current) == 1) { 700 if (get_nr_threads(current) == 1) {
662 siginfo_t info; 701 siginfo_t info;
@@ -673,7 +712,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
673 unreachable(); 712 unreachable();
674 713
675skip: 714skip:
676 audit_seccomp(this_syscall, 0, action); 715 seccomp_log(this_syscall, 0, action);
677 return -1; 716 return -1;
678} 717}
679#else 718#else
@@ -978,6 +1017,127 @@ static const char seccomp_actions_avail[] = SECCOMP_RET_KILL_NAME " "
978 SECCOMP_RET_TRACE_NAME " " 1017 SECCOMP_RET_TRACE_NAME " "
979 SECCOMP_RET_ALLOW_NAME; 1018 SECCOMP_RET_ALLOW_NAME;
980 1019
1020struct seccomp_log_name {
1021 u32 log;
1022 const char *name;
1023};
1024
1025static const struct seccomp_log_name seccomp_log_names[] = {
1026 { SECCOMP_LOG_KILL, SECCOMP_RET_KILL_NAME },
1027 { SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
1028 { SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },
1029 { SECCOMP_LOG_TRACE, SECCOMP_RET_TRACE_NAME },
1030 { SECCOMP_LOG_ALLOW, SECCOMP_RET_ALLOW_NAME },
1031 { }
1032};
1033
1034static bool seccomp_names_from_actions_logged(char *names, size_t size,
1035 u32 actions_logged)
1036{
1037 const struct seccomp_log_name *cur;
1038 bool append_space = false;
1039
1040 for (cur = seccomp_log_names; cur->name && size; cur++) {
1041 ssize_t ret;
1042
1043 if (!(actions_logged & cur->log))
1044 continue;
1045
1046 if (append_space) {
1047 ret = strscpy(names, " ", size);
1048 if (ret < 0)
1049 return false;
1050
1051 names += ret;
1052 size -= ret;
1053 } else
1054 append_space = true;
1055
1056 ret = strscpy(names, cur->name, size);
1057 if (ret < 0)
1058 return false;
1059
1060 names += ret;
1061 size -= ret;
1062 }
1063
1064 return true;
1065}
1066
1067static bool seccomp_action_logged_from_name(u32 *action_logged,
1068 const char *name)
1069{
1070 const struct seccomp_log_name *cur;
1071
1072 for (cur = seccomp_log_names; cur->name; cur++) {
1073 if (!strcmp(cur->name, name)) {
1074 *action_logged = cur->log;
1075 return true;
1076 }
1077 }
1078
1079 return false;
1080}
1081
1082static bool seccomp_actions_logged_from_names(u32 *actions_logged, char *names)
1083{
1084 char *name;
1085
1086 *actions_logged = 0;
1087 while ((name = strsep(&names, " ")) && *name) {
1088 u32 action_logged = 0;
1089
1090 if (!seccomp_action_logged_from_name(&action_logged, name))
1091 return false;
1092
1093 *actions_logged |= action_logged;
1094 }
1095
1096 return true;
1097}
1098
1099static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
1100 void __user *buffer, size_t *lenp,
1101 loff_t *ppos)
1102{
1103 char names[sizeof(seccomp_actions_avail)];
1104 struct ctl_table table;
1105 int ret;
1106
1107 if (write && !capable(CAP_SYS_ADMIN))
1108 return -EPERM;
1109
1110 memset(names, 0, sizeof(names));
1111
1112 if (!write) {
1113 if (!seccomp_names_from_actions_logged(names, sizeof(names),
1114 seccomp_actions_logged))
1115 return -EINVAL;
1116 }
1117
1118 table = *ro_table;
1119 table.data = names;
1120 table.maxlen = sizeof(names);
1121 ret = proc_dostring(&table, write, buffer, lenp, ppos);
1122 if (ret)
1123 return ret;
1124
1125 if (write) {
1126 u32 actions_logged;
1127
1128 if (!seccomp_actions_logged_from_names(&actions_logged,
1129 table.data))
1130 return -EINVAL;
1131
1132 if (actions_logged & SECCOMP_LOG_ALLOW)
1133 return -EINVAL;
1134
1135 seccomp_actions_logged = actions_logged;
1136 }
1137
1138 return 0;
1139}
1140
981static struct ctl_path seccomp_sysctl_path[] = { 1141static struct ctl_path seccomp_sysctl_path[] = {
982 { .procname = "kernel", }, 1142 { .procname = "kernel", },
983 { .procname = "seccomp", }, 1143 { .procname = "seccomp", },
@@ -992,6 +1152,11 @@ static struct ctl_table seccomp_sysctl_table[] = {
992 .mode = 0444, 1152 .mode = 0444,
993 .proc_handler = proc_dostring, 1153 .proc_handler = proc_dostring,
994 }, 1154 },
1155 {
1156 .procname = "actions_logged",
1157 .mode = 0644,
1158 .proc_handler = seccomp_actions_logged_handler,
1159 },
995 { } 1160 { }
996}; 1161};
997 1162