aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyler Hicks <tyhicks@canonical.com>2018-05-03 21:08:14 -0400
committerPaul Moore <paul@paul-moore.com>2018-05-08 02:03:28 -0400
commitea6eca778500b0aaf6e5f10dac4d2cd745c2a50b (patch)
treee958134f8b0c3453331a51214b80b51302b40559
parentbeb44acaf000c97d6c89de581f377df5757857f3 (diff)
seccomp: Audit attempts to modify the actions_logged sysctl
The decision to log a seccomp action will always be subject to the value of the kernel.seccomp.actions_logged sysctl, even for processes that are being inspected via the audit subsystem, in an upcoming patch. Therefore, we need to emit an audit record on attempts at writing to the actions_logged sysctl when auditing is enabled. This patch updates the write handler for the actions_logged sysctl to emit an audit record on attempts to write to the sysctl. Successful writes to the sysctl will result in a record that includes a normalized list of logged actions in the "actions" field and a "res" field equal to 1. Unsuccessful writes to the sysctl will result in a record that doesn't include the "actions" field and has a "res" field equal to 0. Not all unsuccessful writes to the sysctl are audited. For example, an audit record will not be emitted if an unprivileged process attempts to open the sysctl file for reading since that access control check is not part of the sysctl's write handler. Below are some example audit records when writing various strings to the actions_logged sysctl. Writing "not-a-real-action", when the kernel.seccomp.actions_logged sysctl previously was "kill_process kill_thread trap errno trace log", emits this audit record: type=CONFIG_CHANGE msg=audit(1525392371.454:120): op=seccomp-logging actions=? old-actions=kill_process,kill_thread,trap,errno,trace,log res=0 If you then write "kill_process kill_thread errno trace log", this audit record is emitted: type=CONFIG_CHANGE msg=audit(1525392401.645:126): op=seccomp-logging actions=kill_process,kill_thread,errno,trace,log old-actions=kill_process,kill_thread,trap,errno,trace,log res=1 If you then write "log log errno trace kill_process kill_thread", which is unordered and contains the log action twice, it results in the same actions value as the previous record: type=CONFIG_CHANGE msg=audit(1525392436.354:132): op=seccomp-logging actions=kill_process,kill_thread,errno,trace,log old-actions=kill_process,kill_thread,errno,trace,log res=1 If you then write an empty string to the sysctl, this audit record is emitted: type=CONFIG_CHANGE msg=audit(1525392494.413:138): op=seccomp-logging actions=(none) old-actions=kill_process,kill_thread,errno,trace,log res=1 No audit records are generated when reading the actions_logged sysctl. Suggested-by: Steve Grubb <sgrubb@redhat.com> Signed-off-by: Tyler Hicks <tyhicks@canonical.com> Acked-by: Kees Cook <keescook@chromium.org> Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--include/linux/audit.h5
-rw-r--r--kernel/auditsc.c20
-rw-r--r--kernel/seccomp.c58
3 files changed, 74 insertions, 9 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 75d5b031e802..d4e35e7a80c0 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -233,6 +233,8 @@ extern void __audit_inode_child(struct inode *parent,
233 const struct dentry *dentry, 233 const struct dentry *dentry,
234 const unsigned char type); 234 const unsigned char type);
235extern void __audit_seccomp(unsigned long syscall, long signr, int code); 235extern void __audit_seccomp(unsigned long syscall, long signr, int code);
236extern void audit_seccomp_actions_logged(const char *names,
237 const char *old_names, int res);
236extern void __audit_ptrace(struct task_struct *t); 238extern void __audit_ptrace(struct task_struct *t);
237 239
238static inline bool audit_dummy_context(void) 240static inline bool audit_dummy_context(void)
@@ -502,6 +504,9 @@ static inline void __audit_seccomp(unsigned long syscall, long signr, int code)
502{ } 504{ }
503static inline void audit_seccomp(unsigned long syscall, long signr, int code) 505static inline void audit_seccomp(unsigned long syscall, long signr, int code)
504{ } 506{ }
507static inline void audit_seccomp_actions_logged(const char *names,
508 const char *old_names, int res)
509{ }
505static inline int auditsc_get_stamp(struct audit_context *ctx, 510static inline int auditsc_get_stamp(struct audit_context *ctx,
506 struct timespec64 *t, unsigned int *serial) 511 struct timespec64 *t, unsigned int *serial)
507{ 512{
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 479c031ec54c..46ef2c23618d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2480,6 +2480,26 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
2480 audit_log_end(ab); 2480 audit_log_end(ab);
2481} 2481}
2482 2482
2483void audit_seccomp_actions_logged(const char *names, const char *old_names,
2484 int res)
2485{
2486 struct audit_buffer *ab;
2487
2488 if (!audit_enabled)
2489 return;
2490
2491 ab = audit_log_start(current->audit_context, GFP_KERNEL,
2492 AUDIT_CONFIG_CHANGE);
2493 if (unlikely(!ab))
2494 return;
2495
2496 audit_log_format(ab, "op=seccomp-logging");
2497 audit_log_format(ab, " actions=%s", names);
2498 audit_log_format(ab, " old-actions=%s", old_names);
2499 audit_log_format(ab, " res=%d", res);
2500 audit_log_end(ab);
2501}
2502
2483struct list_head *audit_killed_trees(void) 2503struct list_head *audit_killed_trees(void)
2484{ 2504{
2485 struct audit_context *ctx = current->audit_context; 2505 struct audit_context *ctx = current->audit_context;
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index b36ac1e0cd0e..f5630d1a88fe 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -1219,11 +1219,10 @@ static int read_actions_logged(struct ctl_table *ro_table, void __user *buffer,
1219} 1219}
1220 1220
1221static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer, 1221static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
1222 size_t *lenp, loff_t *ppos) 1222 size_t *lenp, loff_t *ppos, u32 *actions_logged)
1223{ 1223{
1224 char names[sizeof(seccomp_actions_avail)]; 1224 char names[sizeof(seccomp_actions_avail)];
1225 struct ctl_table table; 1225 struct ctl_table table;
1226 u32 actions_logged;
1227 int ret; 1226 int ret;
1228 1227
1229 if (!capable(CAP_SYS_ADMIN)) 1228 if (!capable(CAP_SYS_ADMIN))
@@ -1238,24 +1237,65 @@ static int write_actions_logged(struct ctl_table *ro_table, void __user *buffer,
1238 if (ret) 1237 if (ret)
1239 return ret; 1238 return ret;
1240 1239
1241 if (!seccomp_actions_logged_from_names(&actions_logged, table.data)) 1240 if (!seccomp_actions_logged_from_names(actions_logged, table.data))
1242 return -EINVAL; 1241 return -EINVAL;
1243 1242
1244 if (actions_logged & SECCOMP_LOG_ALLOW) 1243 if (*actions_logged & SECCOMP_LOG_ALLOW)
1245 return -EINVAL; 1244 return -EINVAL;
1246 1245
1247 seccomp_actions_logged = actions_logged; 1246 seccomp_actions_logged = *actions_logged;
1248 return 0; 1247 return 0;
1249} 1248}
1250 1249
1250static void audit_actions_logged(u32 actions_logged, u32 old_actions_logged,
1251 int ret)
1252{
1253 char names[sizeof(seccomp_actions_avail)];
1254 char old_names[sizeof(seccomp_actions_avail)];
1255 const char *new = names;
1256 const char *old = old_names;
1257
1258 if (!audit_enabled)
1259 return;
1260
1261 memset(names, 0, sizeof(names));
1262 memset(old_names, 0, sizeof(old_names));
1263
1264 if (ret)
1265 new = "?";
1266 else if (!actions_logged)
1267 new = "(none)";
1268 else if (!seccomp_names_from_actions_logged(names, sizeof(names),
1269 actions_logged, ","))
1270 new = "?";
1271
1272 if (!old_actions_logged)
1273 old = "(none)";
1274 else if (!seccomp_names_from_actions_logged(old_names,
1275 sizeof(old_names),
1276 old_actions_logged, ","))
1277 old = "?";
1278
1279 return audit_seccomp_actions_logged(new, old, !ret);
1280}
1281
1251static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write, 1282static int seccomp_actions_logged_handler(struct ctl_table *ro_table, int write,
1252 void __user *buffer, size_t *lenp, 1283 void __user *buffer, size_t *lenp,
1253 loff_t *ppos) 1284 loff_t *ppos)
1254{ 1285{
1255 if (write) 1286 int ret;
1256 return write_actions_logged(ro_table, buffer, lenp, ppos); 1287
1257 else 1288 if (write) {
1258 return read_actions_logged(ro_table, buffer, lenp, ppos); 1289 u32 actions_logged = 0;
1290 u32 old_actions_logged = seccomp_actions_logged;
1291
1292 ret = write_actions_logged(ro_table, buffer, lenp, ppos,
1293 &actions_logged);
1294 audit_actions_logged(actions_logged, old_actions_logged, ret);
1295 } else
1296 ret = read_actions_logged(ro_table, buffer, lenp, ppos);
1297
1298 return ret;
1259} 1299}
1260 1300
1261static struct ctl_path seccomp_sysctl_path[] = { 1301static struct ctl_path seccomp_sysctl_path[] = {