aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAmy Griffis <amy.griffis@hp.com>2006-06-14 18:45:21 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2006-07-01 05:43:06 -0400
commit5adc8a6adc91c4c85a64c75a70a619fffc924817 (patch)
treeace9af6bbc3cf711f43cfd88e834baeb6989ca3f /kernel
parent9262e9149f346a5443300f8c451b8e7631e81a42 (diff)
[PATCH] add rule filterkey
Add support for a rule key, which can be used to tie audit records to audit rules. This is useful when a watched file is accessed through a link or symlink, as well as for general audit log analysis. Because this patch uses a string key instead of an integer key, there is a bit of extra overhead to do the kstrdup() when a rule fires. However, we're also allocating memory for the audit record buffer, so it's probably not that significant. I went ahead with a string key because it seems more user-friendly. Note that the user must ensure that filterkeys are unique. The kernel only checks for duplicate rules. Signed-off-by: Amy Griffis <amy.griffis@hpd.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c95
-rw-r--r--kernel/auditsc.c15
3 files changed, 75 insertions, 36 deletions
diff --git a/kernel/audit.h b/kernel/audit.h
index 8323e4132a33..6aa33b848cf2 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -81,6 +81,7 @@ struct audit_krule {
81 u32 mask[AUDIT_BITMASK_SIZE]; 81 u32 mask[AUDIT_BITMASK_SIZE];
82 u32 buflen; /* for data alloc on list rules */ 82 u32 buflen; /* for data alloc on list rules */
83 u32 field_count; 83 u32 field_count;
84 char *filterkey; /* ties events to rules */
84 struct audit_field *fields; 85 struct audit_field *fields;
85 struct audit_field *inode_f; /* quick access to an inode field */ 86 struct audit_field *inode_f; /* quick access to an inode field */
86 struct audit_watch *watch; /* associated watch */ 87 struct audit_watch *watch; /* associated watch */
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 4c99d2c586ed..e98db08fc6df 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -141,6 +141,7 @@ static inline void audit_free_rule(struct audit_entry *e)
141 selinux_audit_rule_free(f->se_rule); 141 selinux_audit_rule_free(f->se_rule);
142 } 142 }
143 kfree(e->rule.fields); 143 kfree(e->rule.fields);
144 kfree(e->rule.filterkey);
144 kfree(e); 145 kfree(e);
145} 146}
146 147
@@ -511,6 +512,16 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
511 if (err) 512 if (err)
512 goto exit_free; 513 goto exit_free;
513 break; 514 break;
515 case AUDIT_FILTERKEY:
516 err = -EINVAL;
517 if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
518 goto exit_free;
519 str = audit_unpack_string(&bufp, &remain, f->val);
520 if (IS_ERR(str))
521 goto exit_free;
522 entry->rule.buflen += f->val;
523 entry->rule.filterkey = str;
524 break;
514 default: 525 default:
515 goto exit_free; 526 goto exit_free;
516 } 527 }
@@ -612,6 +623,10 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
612 data->buflen += data->values[i] = 623 data->buflen += data->values[i] =
613 audit_pack_string(&bufp, krule->watch->path); 624 audit_pack_string(&bufp, krule->watch->path);
614 break; 625 break;
626 case AUDIT_FILTERKEY:
627 data->buflen += data->values[i] =
628 audit_pack_string(&bufp, krule->filterkey);
629 break;
615 default: 630 default:
616 data->values[i] = f->val; 631 data->values[i] = f->val;
617 } 632 }
@@ -651,6 +666,11 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
651 if (strcmp(a->watch->path, b->watch->path)) 666 if (strcmp(a->watch->path, b->watch->path))
652 return 1; 667 return 1;
653 break; 668 break;
669 case AUDIT_FILTERKEY:
670 /* both filterkeys exist based on above type compare */
671 if (strcmp(a->filterkey, b->filterkey))
672 return 1;
673 break;
654 default: 674 default:
655 if (a->fields[i].val != b->fields[i].val) 675 if (a->fields[i].val != b->fields[i].val)
656 return 1; 676 return 1;
@@ -730,6 +750,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
730 u32 fcount = old->field_count; 750 u32 fcount = old->field_count;
731 struct audit_entry *entry; 751 struct audit_entry *entry;
732 struct audit_krule *new; 752 struct audit_krule *new;
753 char *fk;
733 int i, err = 0; 754 int i, err = 0;
734 755
735 entry = audit_init_entry(fcount); 756 entry = audit_init_entry(fcount);
@@ -760,6 +781,13 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
760 case AUDIT_SE_CLR: 781 case AUDIT_SE_CLR:
761 err = audit_dupe_selinux_field(&new->fields[i], 782 err = audit_dupe_selinux_field(&new->fields[i],
762 &old->fields[i]); 783 &old->fields[i]);
784 break;
785 case AUDIT_FILTERKEY:
786 fk = kstrdup(old->filterkey, GFP_KERNEL);
787 if (unlikely(!fk))
788 err = -ENOMEM;
789 else
790 new->filterkey = fk;
763 } 791 }
764 if (err) { 792 if (err) {
765 audit_free_rule(entry); 793 audit_free_rule(entry);
@@ -1245,6 +1273,34 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
1245 skb_queue_tail(q, skb); 1273 skb_queue_tail(q, skb);
1246} 1274}
1247 1275
1276/* Log rule additions and removals */
1277static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
1278 struct audit_krule *rule, int res)
1279{
1280 struct audit_buffer *ab;
1281
1282 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
1283 if (!ab)
1284 return;
1285 audit_log_format(ab, "auid=%u", loginuid);
1286 if (sid) {
1287 char *ctx = NULL;
1288 u32 len;
1289 if (selinux_ctxid_to_string(sid, &ctx, &len))
1290 audit_log_format(ab, " ssid=%u", sid);
1291 else
1292 audit_log_format(ab, " subj=%s", ctx);
1293 kfree(ctx);
1294 }
1295 audit_log_format(ab, " %s rule key=", action);
1296 if (rule->filterkey)
1297 audit_log_untrustedstring(ab, rule->filterkey);
1298 else
1299 audit_log_format(ab, "(null)");
1300 audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
1301 audit_log_end(ab);
1302}
1303
1248/** 1304/**
1249 * audit_receive_filter - apply all rules to the specified message type 1305 * audit_receive_filter - apply all rules to the specified message type
1250 * @type: audit message type 1306 * @type: audit message type
@@ -1304,24 +1360,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
1304 1360
1305 err = audit_add_rule(entry, 1361 err = audit_add_rule(entry,
1306 &audit_filter_list[entry->rule.listnr]); 1362 &audit_filter_list[entry->rule.listnr]);
1307 1363 audit_log_rule_change(loginuid, sid, "add", &entry->rule, !err);
1308 if (sid) {
1309 char *ctx = NULL;
1310 u32 len;
1311 if (selinux_ctxid_to_string(sid, &ctx, &len)) {
1312 /* Maybe call audit_panic? */
1313 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1314 "auid=%u ssid=%u add rule to list=%d res=%d",
1315 loginuid, sid, entry->rule.listnr, !err);
1316 } else
1317 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1318 "auid=%u subj=%s add rule to list=%d res=%d",
1319 loginuid, ctx, entry->rule.listnr, !err);
1320 kfree(ctx);
1321 } else
1322 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1323 "auid=%u add rule to list=%d res=%d",
1324 loginuid, entry->rule.listnr, !err);
1325 1364
1326 if (err) 1365 if (err)
1327 audit_free_rule(entry); 1366 audit_free_rule(entry);
@@ -1337,24 +1376,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
1337 1376
1338 err = audit_del_rule(entry, 1377 err = audit_del_rule(entry,
1339 &audit_filter_list[entry->rule.listnr]); 1378 &audit_filter_list[entry->rule.listnr]);
1340 1379 audit_log_rule_change(loginuid, sid, "remove", &entry->rule,
1341 if (sid) { 1380 !err);
1342 char *ctx = NULL;
1343 u32 len;
1344 if (selinux_ctxid_to_string(sid, &ctx, &len)) {
1345 /* Maybe call audit_panic? */
1346 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1347 "auid=%u ssid=%u remove rule from list=%d res=%d",
1348 loginuid, sid, entry->rule.listnr, !err);
1349 } else
1350 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1351 "auid=%u subj=%s remove rule from list=%d res=%d",
1352 loginuid, ctx, entry->rule.listnr, !err);
1353 kfree(ctx);
1354 } else
1355 audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
1356 "auid=%u remove rule from list=%d res=%d",
1357 loginuid, entry->rule.listnr, !err);
1358 1381
1359 audit_free_rule(entry); 1382 audit_free_rule(entry);
1360 break; 1383 break;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index dc5e3f01efe7..316657855165 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -186,6 +186,7 @@ struct audit_context {
186 int auditable; /* 1 if record should be written */ 186 int auditable; /* 1 if record should be written */
187 int name_count; 187 int name_count;
188 struct audit_names names[AUDIT_NAMES]; 188 struct audit_names names[AUDIT_NAMES];
189 char * filterkey; /* key for rule that triggered record */
189 struct dentry * pwd; 190 struct dentry * pwd;
190 struct vfsmount * pwdmnt; 191 struct vfsmount * pwdmnt;
191 struct audit_context *previous; /* For nested syscalls */ 192 struct audit_context *previous; /* For nested syscalls */
@@ -348,11 +349,17 @@ static int audit_filter_rules(struct task_struct *tsk,
348 if (ctx) 349 if (ctx)
349 result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val); 350 result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
350 break; 351 break;
352 case AUDIT_FILTERKEY:
353 /* ignore this field for filtering */
354 result = 1;
355 break;
351 } 356 }
352 357
353 if (!result) 358 if (!result)
354 return 0; 359 return 0;
355 } 360 }
361 if (rule->filterkey)
362 ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
356 switch (rule->action) { 363 switch (rule->action) {
357 case AUDIT_NEVER: *state = AUDIT_DISABLED; break; 364 case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
358 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; 365 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
@@ -627,6 +634,7 @@ static inline void audit_free_context(struct audit_context *context)
627 } 634 }
628 audit_free_names(context); 635 audit_free_names(context);
629 audit_free_aux(context); 636 audit_free_aux(context);
637 kfree(context->filterkey);
630 kfree(context); 638 kfree(context);
631 context = previous; 639 context = previous;
632 } while (context); 640 } while (context);
@@ -735,6 +743,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
735 context->euid, context->suid, context->fsuid, 743 context->euid, context->suid, context->fsuid,
736 context->egid, context->sgid, context->fsgid, tty); 744 context->egid, context->sgid, context->fsgid, tty);
737 audit_log_task_info(ab, tsk); 745 audit_log_task_info(ab, tsk);
746 if (context->filterkey) {
747 audit_log_format(ab, " key=");
748 audit_log_untrustedstring(ab, context->filterkey);
749 } else
750 audit_log_format(ab, " key=(null)");
738 audit_log_end(ab); 751 audit_log_end(ab);
739 752
740 for (aux = context->aux; aux; aux = aux->next) { 753 for (aux = context->aux; aux; aux = aux->next) {
@@ -1060,6 +1073,8 @@ void audit_syscall_exit(int valid, long return_code)
1060 } else { 1073 } else {
1061 audit_free_names(context); 1074 audit_free_names(context);
1062 audit_free_aux(context); 1075 audit_free_aux(context);
1076 kfree(context->filterkey);
1077 context->filterkey = NULL;
1063 tsk->audit_context = context; 1078 tsk->audit_context = context;
1064 } 1079 }
1065} 1080}