aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c209
-rw-r--r--kernel/auditsc.c65
3 files changed, 209 insertions, 66 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..5b4e16276ca0 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
@@ -278,6 +279,29 @@ static int audit_to_watch(struct audit_krule *krule, char *path, int len,
278 return 0; 279 return 0;
279} 280}
280 281
282static __u32 *classes[AUDIT_SYSCALL_CLASSES];
283
284int __init audit_register_class(int class, unsigned *list)
285{
286 __u32 *p = kzalloc(AUDIT_BITMASK_SIZE * sizeof(__u32), GFP_KERNEL);
287 if (!p)
288 return -ENOMEM;
289 while (*list != ~0U) {
290 unsigned n = *list++;
291 if (n >= AUDIT_BITMASK_SIZE * 32 - AUDIT_SYSCALL_CLASSES) {
292 kfree(p);
293 return -EINVAL;
294 }
295 p[AUDIT_WORD(n)] |= AUDIT_BIT(n);
296 }
297 if (class >= AUDIT_SYSCALL_CLASSES || classes[class]) {
298 kfree(p);
299 return -EINVAL;
300 }
301 classes[class] = p;
302 return 0;
303}
304
281/* Common user-space to kernel rule translation. */ 305/* Common user-space to kernel rule translation. */
282static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) 306static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
283{ 307{
@@ -321,6 +345,22 @@ static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
321 for (i = 0; i < AUDIT_BITMASK_SIZE; i++) 345 for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
322 entry->rule.mask[i] = rule->mask[i]; 346 entry->rule.mask[i] = rule->mask[i];
323 347
348 for (i = 0; i < AUDIT_SYSCALL_CLASSES; i++) {
349 int bit = AUDIT_BITMASK_SIZE * 32 - i - 1;
350 __u32 *p = &entry->rule.mask[AUDIT_WORD(bit)];
351 __u32 *class;
352
353 if (!(*p & AUDIT_BIT(bit)))
354 continue;
355 *p &= ~AUDIT_BIT(bit);
356 class = classes[i];
357 if (class) {
358 int j;
359 for (j = 0; j < AUDIT_BITMASK_SIZE; j++)
360 entry->rule.mask[j] |= class[j];
361 }
362 }
363
324 return entry; 364 return entry;
325 365
326exit_err: 366exit_err:
@@ -469,11 +509,16 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
469 case AUDIT_ARG2: 509 case AUDIT_ARG2:
470 case AUDIT_ARG3: 510 case AUDIT_ARG3:
471 break; 511 break;
472 case AUDIT_SE_USER: 512 case AUDIT_SUBJ_USER:
473 case AUDIT_SE_ROLE: 513 case AUDIT_SUBJ_ROLE:
474 case AUDIT_SE_TYPE: 514 case AUDIT_SUBJ_TYPE:
475 case AUDIT_SE_SEN: 515 case AUDIT_SUBJ_SEN:
476 case AUDIT_SE_CLR: 516 case AUDIT_SUBJ_CLR:
517 case AUDIT_OBJ_USER:
518 case AUDIT_OBJ_ROLE:
519 case AUDIT_OBJ_TYPE:
520 case AUDIT_OBJ_LEV_LOW:
521 case AUDIT_OBJ_LEV_HIGH:
477 str = audit_unpack_string(&bufp, &remain, f->val); 522 str = audit_unpack_string(&bufp, &remain, f->val);
478 if (IS_ERR(str)) 523 if (IS_ERR(str))
479 goto exit_free; 524 goto exit_free;
@@ -511,6 +556,16 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
511 if (err) 556 if (err)
512 goto exit_free; 557 goto exit_free;
513 break; 558 break;
559 case AUDIT_FILTERKEY:
560 err = -EINVAL;
561 if (entry->rule.filterkey || f->val > AUDIT_MAX_KEY_LEN)
562 goto exit_free;
563 str = audit_unpack_string(&bufp, &remain, f->val);
564 if (IS_ERR(str))
565 goto exit_free;
566 entry->rule.buflen += f->val;
567 entry->rule.filterkey = str;
568 break;
514 default: 569 default:
515 goto exit_free; 570 goto exit_free;
516 } 571 }
@@ -600,11 +655,16 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
600 data->fields[i] = f->type; 655 data->fields[i] = f->type;
601 data->fieldflags[i] = f->op; 656 data->fieldflags[i] = f->op;
602 switch(f->type) { 657 switch(f->type) {
603 case AUDIT_SE_USER: 658 case AUDIT_SUBJ_USER:
604 case AUDIT_SE_ROLE: 659 case AUDIT_SUBJ_ROLE:
605 case AUDIT_SE_TYPE: 660 case AUDIT_SUBJ_TYPE:
606 case AUDIT_SE_SEN: 661 case AUDIT_SUBJ_SEN:
607 case AUDIT_SE_CLR: 662 case AUDIT_SUBJ_CLR:
663 case AUDIT_OBJ_USER:
664 case AUDIT_OBJ_ROLE:
665 case AUDIT_OBJ_TYPE:
666 case AUDIT_OBJ_LEV_LOW:
667 case AUDIT_OBJ_LEV_HIGH:
608 data->buflen += data->values[i] = 668 data->buflen += data->values[i] =
609 audit_pack_string(&bufp, f->se_str); 669 audit_pack_string(&bufp, f->se_str);
610 break; 670 break;
@@ -612,6 +672,10 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
612 data->buflen += data->values[i] = 672 data->buflen += data->values[i] =
613 audit_pack_string(&bufp, krule->watch->path); 673 audit_pack_string(&bufp, krule->watch->path);
614 break; 674 break;
675 case AUDIT_FILTERKEY:
676 data->buflen += data->values[i] =
677 audit_pack_string(&bufp, krule->filterkey);
678 break;
615 default: 679 default:
616 data->values[i] = f->val; 680 data->values[i] = f->val;
617 } 681 }
@@ -639,11 +703,16 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
639 return 1; 703 return 1;
640 704
641 switch(a->fields[i].type) { 705 switch(a->fields[i].type) {
642 case AUDIT_SE_USER: 706 case AUDIT_SUBJ_USER:
643 case AUDIT_SE_ROLE: 707 case AUDIT_SUBJ_ROLE:
644 case AUDIT_SE_TYPE: 708 case AUDIT_SUBJ_TYPE:
645 case AUDIT_SE_SEN: 709 case AUDIT_SUBJ_SEN:
646 case AUDIT_SE_CLR: 710 case AUDIT_SUBJ_CLR:
711 case AUDIT_OBJ_USER:
712 case AUDIT_OBJ_ROLE:
713 case AUDIT_OBJ_TYPE:
714 case AUDIT_OBJ_LEV_LOW:
715 case AUDIT_OBJ_LEV_HIGH:
647 if (strcmp(a->fields[i].se_str, b->fields[i].se_str)) 716 if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
648 return 1; 717 return 1;
649 break; 718 break;
@@ -651,6 +720,11 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
651 if (strcmp(a->watch->path, b->watch->path)) 720 if (strcmp(a->watch->path, b->watch->path))
652 return 1; 721 return 1;
653 break; 722 break;
723 case AUDIT_FILTERKEY:
724 /* both filterkeys exist based on above type compare */
725 if (strcmp(a->filterkey, b->filterkey))
726 return 1;
727 break;
654 default: 728 default:
655 if (a->fields[i].val != b->fields[i].val) 729 if (a->fields[i].val != b->fields[i].val)
656 return 1; 730 return 1;
@@ -730,6 +804,7 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
730 u32 fcount = old->field_count; 804 u32 fcount = old->field_count;
731 struct audit_entry *entry; 805 struct audit_entry *entry;
732 struct audit_krule *new; 806 struct audit_krule *new;
807 char *fk;
733 int i, err = 0; 808 int i, err = 0;
734 809
735 entry = audit_init_entry(fcount); 810 entry = audit_init_entry(fcount);
@@ -753,13 +828,25 @@ static struct audit_entry *audit_dupe_rule(struct audit_krule *old,
753 * the originals will all be freed when the old rule is freed. */ 828 * the originals will all be freed when the old rule is freed. */
754 for (i = 0; i < fcount; i++) { 829 for (i = 0; i < fcount; i++) {
755 switch (new->fields[i].type) { 830 switch (new->fields[i].type) {
756 case AUDIT_SE_USER: 831 case AUDIT_SUBJ_USER:
757 case AUDIT_SE_ROLE: 832 case AUDIT_SUBJ_ROLE:
758 case AUDIT_SE_TYPE: 833 case AUDIT_SUBJ_TYPE:
759 case AUDIT_SE_SEN: 834 case AUDIT_SUBJ_SEN:
760 case AUDIT_SE_CLR: 835 case AUDIT_SUBJ_CLR:
836 case AUDIT_OBJ_USER:
837 case AUDIT_OBJ_ROLE:
838 case AUDIT_OBJ_TYPE:
839 case AUDIT_OBJ_LEV_LOW:
840 case AUDIT_OBJ_LEV_HIGH:
761 err = audit_dupe_selinux_field(&new->fields[i], 841 err = audit_dupe_selinux_field(&new->fields[i],
762 &old->fields[i]); 842 &old->fields[i]);
843 break;
844 case AUDIT_FILTERKEY:
845 fk = kstrdup(old->filterkey, GFP_KERNEL);
846 if (unlikely(!fk))
847 err = -ENOMEM;
848 else
849 new->filterkey = fk;
763 } 850 }
764 if (err) { 851 if (err) {
765 audit_free_rule(entry); 852 audit_free_rule(entry);
@@ -1245,6 +1332,34 @@ static void audit_list_rules(int pid, int seq, struct sk_buff_head *q)
1245 skb_queue_tail(q, skb); 1332 skb_queue_tail(q, skb);
1246} 1333}
1247 1334
1335/* Log rule additions and removals */
1336static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
1337 struct audit_krule *rule, int res)
1338{
1339 struct audit_buffer *ab;
1340
1341 ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
1342 if (!ab)
1343 return;
1344 audit_log_format(ab, "auid=%u", loginuid);
1345 if (sid) {
1346 char *ctx = NULL;
1347 u32 len;
1348 if (selinux_ctxid_to_string(sid, &ctx, &len))
1349 audit_log_format(ab, " ssid=%u", sid);
1350 else
1351 audit_log_format(ab, " subj=%s", ctx);
1352 kfree(ctx);
1353 }
1354 audit_log_format(ab, " %s rule key=", action);
1355 if (rule->filterkey)
1356 audit_log_untrustedstring(ab, rule->filterkey);
1357 else
1358 audit_log_format(ab, "(null)");
1359 audit_log_format(ab, " list=%d res=%d", rule->listnr, res);
1360 audit_log_end(ab);
1361}
1362
1248/** 1363/**
1249 * audit_receive_filter - apply all rules to the specified message type 1364 * audit_receive_filter - apply all rules to the specified message type
1250 * @type: audit message type 1365 * @type: audit message type
@@ -1304,24 +1419,7 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
1304 1419
1305 err = audit_add_rule(entry, 1420 err = audit_add_rule(entry,
1306 &audit_filter_list[entry->rule.listnr]); 1421 &audit_filter_list[entry->rule.listnr]);
1307 1422 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 1423
1326 if (err) 1424 if (err)
1327 audit_free_rule(entry); 1425 audit_free_rule(entry);
@@ -1337,24 +1435,8 @@ int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
1337 1435
1338 err = audit_del_rule(entry, 1436 err = audit_del_rule(entry,
1339 &audit_filter_list[entry->rule.listnr]); 1437 &audit_filter_list[entry->rule.listnr]);
1340 1438 audit_log_rule_change(loginuid, sid, "remove", &entry->rule,
1341 if (sid) { 1439 !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 1440
1359 audit_free_rule(entry); 1441 audit_free_rule(entry);
1360 break; 1442 break;
@@ -1514,11 +1596,16 @@ static inline int audit_rule_has_selinux(struct audit_krule *rule)
1514 for (i = 0; i < rule->field_count; i++) { 1596 for (i = 0; i < rule->field_count; i++) {
1515 struct audit_field *f = &rule->fields[i]; 1597 struct audit_field *f = &rule->fields[i];
1516 switch (f->type) { 1598 switch (f->type) {
1517 case AUDIT_SE_USER: 1599 case AUDIT_SUBJ_USER:
1518 case AUDIT_SE_ROLE: 1600 case AUDIT_SUBJ_ROLE:
1519 case AUDIT_SE_TYPE: 1601 case AUDIT_SUBJ_TYPE:
1520 case AUDIT_SE_SEN: 1602 case AUDIT_SUBJ_SEN:
1521 case AUDIT_SE_CLR: 1603 case AUDIT_SUBJ_CLR:
1604 case AUDIT_OBJ_USER:
1605 case AUDIT_OBJ_ROLE:
1606 case AUDIT_OBJ_TYPE:
1607 case AUDIT_OBJ_LEV_LOW:
1608 case AUDIT_OBJ_LEV_HIGH:
1522 return 1; 1609 return 1;
1523 } 1610 }
1524 } 1611 }
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index dc5e3f01efe7..ae40ac8c39e7 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 */
@@ -320,11 +321,11 @@ static int audit_filter_rules(struct task_struct *tsk,
320 if (ctx) 321 if (ctx)
321 result = audit_comparator(ctx->loginuid, f->op, f->val); 322 result = audit_comparator(ctx->loginuid, f->op, f->val);
322 break; 323 break;
323 case AUDIT_SE_USER: 324 case AUDIT_SUBJ_USER:
324 case AUDIT_SE_ROLE: 325 case AUDIT_SUBJ_ROLE:
325 case AUDIT_SE_TYPE: 326 case AUDIT_SUBJ_TYPE:
326 case AUDIT_SE_SEN: 327 case AUDIT_SUBJ_SEN:
327 case AUDIT_SE_CLR: 328 case AUDIT_SUBJ_CLR:
328 /* NOTE: this may return negative values indicating 329 /* NOTE: this may return negative values indicating
329 a temporary error. We simply treat this as a 330 a temporary error. We simply treat this as a
330 match for now to avoid losing information that 331 match for now to avoid losing information that
@@ -341,6 +342,46 @@ static int audit_filter_rules(struct task_struct *tsk,
341 ctx); 342 ctx);
342 } 343 }
343 break; 344 break;
345 case AUDIT_OBJ_USER:
346 case AUDIT_OBJ_ROLE:
347 case AUDIT_OBJ_TYPE:
348 case AUDIT_OBJ_LEV_LOW:
349 case AUDIT_OBJ_LEV_HIGH:
350 /* The above note for AUDIT_SUBJ_USER...AUDIT_SUBJ_CLR
351 also applies here */
352 if (f->se_rule) {
353 /* Find files that match */
354 if (name) {
355 result = selinux_audit_rule_match(
356 name->osid, f->type, f->op,
357 f->se_rule, ctx);
358 } else if (ctx) {
359 for (j = 0; j < ctx->name_count; j++) {
360 if (selinux_audit_rule_match(
361 ctx->names[j].osid,
362 f->type, f->op,
363 f->se_rule, ctx)) {
364 ++result;
365 break;
366 }
367 }
368 }
369 /* Find ipc objects that match */
370 if (ctx) {
371 struct audit_aux_data *aux;
372 for (aux = ctx->aux; aux;
373 aux = aux->next) {
374 if (aux->type == AUDIT_IPC) {
375 struct audit_aux_data_ipcctl *axi = (void *)aux;
376 if (selinux_audit_rule_match(axi->osid, f->type, f->op, f->se_rule, ctx)) {
377 ++result;
378 break;
379 }
380 }
381 }
382 }
383 }
384 break;
344 case AUDIT_ARG0: 385 case AUDIT_ARG0:
345 case AUDIT_ARG1: 386 case AUDIT_ARG1:
346 case AUDIT_ARG2: 387 case AUDIT_ARG2:
@@ -348,11 +389,17 @@ static int audit_filter_rules(struct task_struct *tsk,
348 if (ctx) 389 if (ctx)
349 result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val); 390 result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
350 break; 391 break;
392 case AUDIT_FILTERKEY:
393 /* ignore this field for filtering */
394 result = 1;
395 break;
351 } 396 }
352 397
353 if (!result) 398 if (!result)
354 return 0; 399 return 0;
355 } 400 }
401 if (rule->filterkey)
402 ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
356 switch (rule->action) { 403 switch (rule->action) {
357 case AUDIT_NEVER: *state = AUDIT_DISABLED; break; 404 case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
358 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; 405 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
@@ -627,6 +674,7 @@ static inline void audit_free_context(struct audit_context *context)
627 } 674 }
628 audit_free_names(context); 675 audit_free_names(context);
629 audit_free_aux(context); 676 audit_free_aux(context);
677 kfree(context->filterkey);
630 kfree(context); 678 kfree(context);
631 context = previous; 679 context = previous;
632 } while (context); 680 } while (context);
@@ -735,6 +783,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
735 context->euid, context->suid, context->fsuid, 783 context->euid, context->suid, context->fsuid,
736 context->egid, context->sgid, context->fsgid, tty); 784 context->egid, context->sgid, context->fsgid, tty);
737 audit_log_task_info(ab, tsk); 785 audit_log_task_info(ab, tsk);
786 if (context->filterkey) {
787 audit_log_format(ab, " key=");
788 audit_log_untrustedstring(ab, context->filterkey);
789 } else
790 audit_log_format(ab, " key=(null)");
738 audit_log_end(ab); 791 audit_log_end(ab);
739 792
740 for (aux = context->aux; aux; aux = aux->next) { 793 for (aux = context->aux; aux; aux = aux->next) {
@@ -1060,6 +1113,8 @@ void audit_syscall_exit(int valid, long return_code)
1060 } else { 1113 } else {
1061 audit_free_names(context); 1114 audit_free_names(context);
1062 audit_free_aux(context); 1115 audit_free_aux(context);
1116 kfree(context->filterkey);
1117 context->filterkey = NULL;
1063 tsk->audit_context = context; 1118 tsk->audit_context = context;
1064 } 1119 }
1065} 1120}