Commit fc25465f09414538afdbceacc517dd4dbabadeca

Authored by Linus Torvalds

Merge branch 'audit.b22' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current

* 'audit.b22' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current:
  [PATCH] audit syscall classes
  [PATCH] audit: support for object context filters
  [PATCH] audit: rename AUDIT_SE_* constants
  [PATCH] add rule filterkey

Showing 17 changed files Side-by-side Diff

arch/i386/kernel/Makefile
... ... @@ -38,6 +38,7 @@
38 38 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
39 39 obj-$(CONFIG_HPET_TIMER) += hpet.o
40 40 obj-$(CONFIG_K8_NB) += k8.o
  41 +obj-$(CONFIG_AUDIT) += audit.o
41 42  
42 43 EXTRA_AFLAGS := -traditional
43 44  
arch/i386/kernel/audit.c
  1 +#include <linux/init.h>
  2 +#include <linux/types.h>
  3 +#include <linux/audit.h>
  4 +#include <asm/unistd.h>
  5 +
  6 +static unsigned dir_class[] = {
  7 +#include <asm-generic/audit_dir_write.h>
  8 +~0U
  9 +};
  10 +
  11 +static unsigned chattr_class[] = {
  12 +#include <asm-generic/audit_change_attr.h>
  13 +~0U
  14 +};
  15 +
  16 +static int __init audit_classes_init(void)
  17 +{
  18 + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
  19 + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
  20 + return 0;
  21 +}
  22 +
  23 +__initcall(audit_classes_init);
arch/ia64/ia32/Makefile
... ... @@ -4,6 +4,7 @@
4 4  
5 5 obj-y := ia32_entry.o sys_ia32.o ia32_signal.o \
6 6 ia32_support.o ia32_traps.o binfmt_elf32.o ia32_ldt.o
  7 +obj-$(CONFIG_AUDIT) += audit.o
7 8  
8 9 # Don't let GCC uses f16-f31 so that save_ia32_fpstate_live() and
9 10 # restore_ia32_fpstate_live() can be sure the live register contain user-level state.
arch/ia64/ia32/audit.c
  1 +#include <asm-i386/unistd.h>
  2 +
  3 +unsigned ia32_dir_class[] = {
  4 +#include <asm-generic/audit_dir_write.h>
  5 +~0U
  6 +};
  7 +
  8 +unsigned ia32_chattr_class[] = {
  9 +#include <asm-generic/audit_change_attr.h>
  10 +~0U
  11 +};
arch/ia64/kernel/Makefile
... ... @@ -29,6 +29,7 @@
29 29 obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
30 30 obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
31 31 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
  32 +obj-$(CONFIG_AUDIT) += audit.o
32 33 mca_recovery-y += mca_drv.o mca_drv_asm.o
33 34  
34 35 # The gate DSO image is built using a special linker script.
arch/ia64/kernel/audit.c
  1 +#include <linux/init.h>
  2 +#include <linux/types.h>
  3 +#include <linux/audit.h>
  4 +#include <asm/unistd.h>
  5 +
  6 +static unsigned dir_class[] = {
  7 +#include <asm-generic/audit_dir_write.h>
  8 +~0U
  9 +};
  10 +
  11 +static unsigned chattr_class[] = {
  12 +#include <asm-generic/audit_change_attr.h>
  13 +~0U
  14 +};
  15 +
  16 +static int __init audit_classes_init(void)
  17 +{
  18 +#ifdef CONFIG_IA32_SUPPORT
  19 + extern __u32 ia32_dir_class[];
  20 + extern __u32 ia32_chattr_class[];
  21 + audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
  22 + audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
  23 +#endif
  24 + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
  25 + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
  26 + return 0;
  27 +}
  28 +
  29 +__initcall(audit_classes_init);
arch/x86_64/ia32/Makefile
... ... @@ -11,6 +11,9 @@
11 11  
12 12 obj-$(CONFIG_IA32_AOUT) += ia32_aout.o
13 13  
  14 +audit-class-$(CONFIG_AUDIT) := audit.o
  15 +obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
  16 +
14 17 $(obj)/syscall32_syscall.o: \
15 18 $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
16 19  
arch/x86_64/ia32/audit.c
  1 +#include <asm-i386/unistd.h>
  2 +
  3 +unsigned ia32_dir_class[] = {
  4 +#include <asm-generic/audit_dir_write.h>
  5 +~0U
  6 +};
  7 +
  8 +unsigned ia32_chattr_class[] = {
  9 +#include <asm-generic/audit_change_attr.h>
  10 +~0U
  11 +};
arch/x86_64/kernel/Makefile
... ... @@ -35,6 +35,7 @@
35 35 obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o
36 36 obj-$(CONFIG_X86_VSMP) += vsmp.o
37 37 obj-$(CONFIG_K8_NB) += k8.o
  38 +obj-$(CONFIG_AUDIT) += audit.o
38 39  
39 40 obj-$(CONFIG_MODULES) += module.o
40 41  
arch/x86_64/kernel/audit.c
  1 +#include <linux/init.h>
  2 +#include <linux/types.h>
  3 +#include <linux/audit.h>
  4 +#include <asm/unistd.h>
  5 +
  6 +static unsigned dir_class[] = {
  7 +#include <asm-generic/audit_dir_write.h>
  8 +~0U
  9 +};
  10 +
  11 +static unsigned chattr_class[] = {
  12 +#include <asm-generic/audit_change_attr.h>
  13 +~0U
  14 +};
  15 +
  16 +static int __init audit_classes_init(void)
  17 +{
  18 +#ifdef CONFIG_IA32_EMULATION
  19 + extern __u32 ia32_dir_class[];
  20 + extern __u32 ia32_chattr_class[];
  21 + audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
  22 + audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
  23 +#endif
  24 + audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
  25 + audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
  26 + return 0;
  27 +}
  28 +
  29 +__initcall(audit_classes_init);
include/asm-generic/audit_change_attr.h
  1 +__NR_chmod,
  2 +__NR_fchmod,
  3 +__NR_chown,
  4 +__NR_fchown,
  5 +__NR_lchown,
  6 +__NR_setxattr,
  7 +__NR_lsetxattr,
  8 +__NR_fsetxattr,
  9 +__NR_removexattr,
  10 +__NR_lremovexattr,
  11 +__NR_fremovexattr,
  12 +__NR_fchownat,
  13 +__NR_fchmodat,
  14 +#ifdef __NR_chown32
  15 +__NR_chown32,
  16 +__NR_fchown32,
  17 +__NR_lchown32,
  18 +#endif
include/asm-generic/audit_dir_write.h
  1 +__NR_rename,
  2 +__NR_mkdir,
  3 +__NR_rmdir,
  4 +__NR_creat,
  5 +__NR_link,
  6 +__NR_unlink,
  7 +__NR_symlink,
  8 +__NR_mknod,
  9 +__NR_mkdirat,
  10 +__NR_mknodat,
  11 +__NR_unlinkat,
  12 +__NR_renameat,
  13 +__NR_linkat,
  14 +__NR_symlinkat,
include/linux/audit.h
... ... @@ -122,10 +122,17 @@
122 122 /* Rule structure sizes -- if these change, different AUDIT_ADD and
123 123 * AUDIT_LIST commands must be implemented. */
124 124 #define AUDIT_MAX_FIELDS 64
  125 +#define AUDIT_MAX_KEY_LEN 32
125 126 #define AUDIT_BITMASK_SIZE 64
126 127 #define AUDIT_WORD(nr) ((__u32)((nr)/32))
127 128 #define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
128 129  
  130 +#define AUDIT_SYSCALL_CLASSES 16
  131 +#define AUDIT_CLASS_DIR_WRITE 0
  132 +#define AUDIT_CLASS_DIR_WRITE_32 1
  133 +#define AUDIT_CLASS_CHATTR 2
  134 +#define AUDIT_CLASS_CHATTR_32 3
  135 +
129 136 /* This bitmask is used to validate user input. It represents all bits that
130 137 * are currently used in an audit field constant understood by the kernel.
131 138 * If you are adding a new #define AUDIT_<whatever>, please ensure that
132 139  
... ... @@ -150,12 +157,17 @@
150 157 #define AUDIT_PERS 10
151 158 #define AUDIT_ARCH 11
152 159 #define AUDIT_MSGTYPE 12
153   -#define AUDIT_SE_USER 13 /* security label user */
154   -#define AUDIT_SE_ROLE 14 /* security label role */
155   -#define AUDIT_SE_TYPE 15 /* security label type */
156   -#define AUDIT_SE_SEN 16 /* security label sensitivity label */
157   -#define AUDIT_SE_CLR 17 /* security label clearance label */
  160 +#define AUDIT_SUBJ_USER 13 /* security label user */
  161 +#define AUDIT_SUBJ_ROLE 14 /* security label role */
  162 +#define AUDIT_SUBJ_TYPE 15 /* security label type */
  163 +#define AUDIT_SUBJ_SEN 16 /* security label sensitivity label */
  164 +#define AUDIT_SUBJ_CLR 17 /* security label clearance label */
158 165 #define AUDIT_PPID 18
  166 +#define AUDIT_OBJ_USER 19
  167 +#define AUDIT_OBJ_ROLE 20
  168 +#define AUDIT_OBJ_TYPE 21
  169 +#define AUDIT_OBJ_LEV_LOW 22
  170 +#define AUDIT_OBJ_LEV_HIGH 23
159 171  
160 172 /* These are ONLY useful when checking
161 173 * at syscall exit time (AUDIT_AT_EXIT). */
... ... @@ -171,6 +183,8 @@
171 183 #define AUDIT_ARG2 (AUDIT_ARG0+2)
172 184 #define AUDIT_ARG3 (AUDIT_ARG0+3)
173 185  
  186 +#define AUDIT_FILTERKEY 210
  187 +
174 188 #define AUDIT_NEGATE 0x80000000
175 189  
176 190 /* These are the supported operators.
... ... @@ -299,6 +313,7 @@
299 313 #define AUDITSC_SUCCESS 1
300 314 #define AUDITSC_FAILURE 2
301 315 #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
  316 +extern int __init audit_register_class(int class, unsigned *list);
302 317 #ifdef CONFIG_AUDITSYSCALL
303 318 /* These are defined in auditsc.c */
304 319 /* Public API */
... ... @@ -81,6 +81,7 @@
81 81 u32 mask[AUDIT_BITMASK_SIZE];
82 82 u32 buflen; /* for data alloc on list rules */
83 83 u32 field_count;
  84 + char *filterkey; /* ties events to rules */
84 85 struct audit_field *fields;
85 86 struct audit_field *inode_f; /* quick access to an inode field */
86 87 struct audit_watch *watch; /* associated watch */
kernel/auditfilter.c
... ... @@ -141,6 +141,7 @@
141 141 selinux_audit_rule_free(f->se_rule);
142 142 }
143 143 kfree(e->rule.fields);
  144 + kfree(e->rule.filterkey);
144 145 kfree(e);
145 146 }
146 147  
... ... @@ -278,6 +279,29 @@
278 279 return 0;
279 280 }
280 281  
  282 +static __u32 *classes[AUDIT_SYSCALL_CLASSES];
  283 +
  284 +int __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 305 /* Common user-space to kernel rule translation. */
282 306 static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
283 307 {
... ... @@ -321,6 +345,22 @@
321 345 for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
322 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 364 return entry;
325 365  
326 366 exit_err:
... ... @@ -469,11 +509,16 @@
469 509 case AUDIT_ARG2:
470 510 case AUDIT_ARG3:
471 511 break;
472   - case AUDIT_SE_USER:
473   - case AUDIT_SE_ROLE:
474   - case AUDIT_SE_TYPE:
475   - case AUDIT_SE_SEN:
476   - case AUDIT_SE_CLR:
  512 + case AUDIT_SUBJ_USER:
  513 + case AUDIT_SUBJ_ROLE:
  514 + case AUDIT_SUBJ_TYPE:
  515 + case AUDIT_SUBJ_SEN:
  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 522 str = audit_unpack_string(&bufp, &remain, f->val);
478 523 if (IS_ERR(str))
479 524 goto exit_free;
... ... @@ -511,6 +556,16 @@
511 556 if (err)
512 557 goto exit_free;
513 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 569 default:
515 570 goto exit_free;
516 571 }
... ... @@ -600,11 +655,16 @@
600 655 data->fields[i] = f->type;
601 656 data->fieldflags[i] = f->op;
602 657 switch(f->type) {
603   - case AUDIT_SE_USER:
604   - case AUDIT_SE_ROLE:
605   - case AUDIT_SE_TYPE:
606   - case AUDIT_SE_SEN:
607   - case AUDIT_SE_CLR:
  658 + case AUDIT_SUBJ_USER:
  659 + case AUDIT_SUBJ_ROLE:
  660 + case AUDIT_SUBJ_TYPE:
  661 + case AUDIT_SUBJ_SEN:
  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 668 data->buflen += data->values[i] =
609 669 audit_pack_string(&bufp, f->se_str);
610 670 break;
... ... @@ -612,6 +672,10 @@
612 672 data->buflen += data->values[i] =
613 673 audit_pack_string(&bufp, krule->watch->path);
614 674 break;
  675 + case AUDIT_FILTERKEY:
  676 + data->buflen += data->values[i] =
  677 + audit_pack_string(&bufp, krule->filterkey);
  678 + break;
615 679 default:
616 680 data->values[i] = f->val;
617 681 }
... ... @@ -639,11 +703,16 @@
639 703 return 1;
640 704  
641 705 switch(a->fields[i].type) {
642   - case AUDIT_SE_USER:
643   - case AUDIT_SE_ROLE:
644   - case AUDIT_SE_TYPE:
645   - case AUDIT_SE_SEN:
646   - case AUDIT_SE_CLR:
  706 + case AUDIT_SUBJ_USER:
  707 + case AUDIT_SUBJ_ROLE:
  708 + case AUDIT_SUBJ_TYPE:
  709 + case AUDIT_SUBJ_SEN:
  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 716 if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
648 717 return 1;
649 718 break;
... ... @@ -651,6 +720,11 @@
651 720 if (strcmp(a->watch->path, b->watch->path))
652 721 return 1;
653 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 728 default:
655 729 if (a->fields[i].val != b->fields[i].val)
656 730 return 1;
... ... @@ -730,6 +804,7 @@
730 804 u32 fcount = old->field_count;
731 805 struct audit_entry *entry;
732 806 struct audit_krule *new;
  807 + char *fk;
733 808 int i, err = 0;
734 809  
735 810 entry = audit_init_entry(fcount);
736 811  
... ... @@ -753,13 +828,25 @@
753 828 * the originals will all be freed when the old rule is freed. */
754 829 for (i = 0; i < fcount; i++) {
755 830 switch (new->fields[i].type) {
756   - case AUDIT_SE_USER:
757   - case AUDIT_SE_ROLE:
758   - case AUDIT_SE_TYPE:
759   - case AUDIT_SE_SEN:
760   - case AUDIT_SE_CLR:
  831 + case AUDIT_SUBJ_USER:
  832 + case AUDIT_SUBJ_ROLE:
  833 + case AUDIT_SUBJ_TYPE:
  834 + case AUDIT_SUBJ_SEN:
  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 841 err = audit_dupe_selinux_field(&new->fields[i],
762 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 851 if (err) {
765 852 audit_free_rule(entry);
... ... @@ -1245,6 +1332,34 @@
1245 1332 skb_queue_tail(q, skb);
1246 1333 }
1247 1334  
  1335 +/* Log rule additions and removals */
  1336 +static 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 1364 * audit_receive_filter - apply all rules to the specified message type
1250 1365 * @type: audit message type
1251 1366  
... ... @@ -1304,25 +1419,8 @@
1304 1419  
1305 1420 err = audit_add_rule(entry,
1306 1421 &audit_filter_list[entry->rule.listnr]);
  1422 + audit_log_rule_change(loginuid, sid, "add", &entry->rule, !err);
1307 1423  
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   -
1326 1424 if (err)
1327 1425 audit_free_rule(entry);
1328 1426 break;
1329 1427  
... ... @@ -1337,25 +1435,9 @@
1337 1435  
1338 1436 err = audit_del_rule(entry,
1339 1437 &audit_filter_list[entry->rule.listnr]);
  1438 + audit_log_rule_change(loginuid, sid, "remove", &entry->rule,
  1439 + !err);
1340 1440  
1341   - if (sid) {
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   -
1359 1441 audit_free_rule(entry);
1360 1442 break;
1361 1443 default:
... ... @@ -1514,11 +1596,16 @@
1514 1596 for (i = 0; i < rule->field_count; i++) {
1515 1597 struct audit_field *f = &rule->fields[i];
1516 1598 switch (f->type) {
1517   - case AUDIT_SE_USER:
1518   - case AUDIT_SE_ROLE:
1519   - case AUDIT_SE_TYPE:
1520   - case AUDIT_SE_SEN:
1521   - case AUDIT_SE_CLR:
  1599 + case AUDIT_SUBJ_USER:
  1600 + case AUDIT_SUBJ_ROLE:
  1601 + case AUDIT_SUBJ_TYPE:
  1602 + case AUDIT_SUBJ_SEN:
  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 1609 return 1;
1523 1610 }
1524 1611 }
... ... @@ -186,6 +186,7 @@
186 186 int auditable; /* 1 if record should be written */
187 187 int name_count;
188 188 struct audit_names names[AUDIT_NAMES];
  189 + char * filterkey; /* key for rule that triggered record */
189 190 struct dentry * pwd;
190 191 struct vfsmount * pwdmnt;
191 192 struct audit_context *previous; /* For nested syscalls */
... ... @@ -320,11 +321,11 @@
320 321 if (ctx)
321 322 result = audit_comparator(ctx->loginuid, f->op, f->val);
322 323 break;
323   - case AUDIT_SE_USER:
324   - case AUDIT_SE_ROLE:
325   - case AUDIT_SE_TYPE:
326   - case AUDIT_SE_SEN:
327   - case AUDIT_SE_CLR:
  324 + case AUDIT_SUBJ_USER:
  325 + case AUDIT_SUBJ_ROLE:
  326 + case AUDIT_SUBJ_TYPE:
  327 + case AUDIT_SUBJ_SEN:
  328 + case AUDIT_SUBJ_CLR:
328 329 /* NOTE: this may return negative values indicating
329 330 a temporary error. We simply treat this as a
330 331 match for now to avoid losing information that
... ... @@ -341,6 +342,46 @@
341 342 ctx);
342 343 }
343 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 385 case AUDIT_ARG0:
345 386 case AUDIT_ARG1:
346 387 case AUDIT_ARG2:
347 388  
... ... @@ -348,11 +389,17 @@
348 389 if (ctx)
349 390 result = audit_comparator(ctx->argv[f->type-AUDIT_ARG0], f->op, f->val);
350 391 break;
  392 + case AUDIT_FILTERKEY:
  393 + /* ignore this field for filtering */
  394 + result = 1;
  395 + break;
351 396 }
352 397  
353 398 if (!result)
354 399 return 0;
355 400 }
  401 + if (rule->filterkey)
  402 + ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
356 403 switch (rule->action) {
357 404 case AUDIT_NEVER: *state = AUDIT_DISABLED; break;
358 405 case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break;
... ... @@ -627,6 +674,7 @@
627 674 }
628 675 audit_free_names(context);
629 676 audit_free_aux(context);
  677 + kfree(context->filterkey);
630 678 kfree(context);
631 679 context = previous;
632 680 } while (context);
... ... @@ -735,6 +783,11 @@
735 783 context->euid, context->suid, context->fsuid,
736 784 context->egid, context->sgid, context->fsgid, tty);
737 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 791 audit_log_end(ab);
739 792  
740 793 for (aux = context->aux; aux; aux = aux->next) {
... ... @@ -1060,6 +1113,8 @@
1060 1113 } else {
1061 1114 audit_free_names(context);
1062 1115 audit_free_aux(context);
  1116 + kfree(context->filterkey);
  1117 + context->filterkey = NULL;
1063 1118 tsk->audit_context = context;
1064 1119 }
1065 1120 }
security/selinux/ss/services.c
... ... @@ -1845,15 +1845,20 @@
1845 1845 return -ENOTSUPP;
1846 1846  
1847 1847 switch (field) {
1848   - case AUDIT_SE_USER:
1849   - case AUDIT_SE_ROLE:
1850   - case AUDIT_SE_TYPE:
  1848 + case AUDIT_SUBJ_USER:
  1849 + case AUDIT_SUBJ_ROLE:
  1850 + case AUDIT_SUBJ_TYPE:
  1851 + case AUDIT_OBJ_USER:
  1852 + case AUDIT_OBJ_ROLE:
  1853 + case AUDIT_OBJ_TYPE:
1851 1854 /* only 'equals' and 'not equals' fit user, role, and type */
1852 1855 if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
1853 1856 return -EINVAL;
1854 1857 break;
1855   - case AUDIT_SE_SEN:
1856   - case AUDIT_SE_CLR:
  1858 + case AUDIT_SUBJ_SEN:
  1859 + case AUDIT_SUBJ_CLR:
  1860 + case AUDIT_OBJ_LEV_LOW:
  1861 + case AUDIT_OBJ_LEV_HIGH:
1857 1862 /* we do not allow a range, indicated by the presense of '-' */
1858 1863 if (strchr(rulestr, '-'))
1859 1864 return -EINVAL;
1860 1865  
1861 1866  
1862 1867  
... ... @@ -1874,29 +1879,34 @@
1874 1879 tmprule->au_seqno = latest_granting;
1875 1880  
1876 1881 switch (field) {
1877   - case AUDIT_SE_USER:
  1882 + case AUDIT_SUBJ_USER:
  1883 + case AUDIT_OBJ_USER:
1878 1884 userdatum = hashtab_search(policydb.p_users.table, rulestr);
1879 1885 if (!userdatum)
1880 1886 rc = -EINVAL;
1881 1887 else
1882 1888 tmprule->au_ctxt.user = userdatum->value;
1883 1889 break;
1884   - case AUDIT_SE_ROLE:
  1890 + case AUDIT_SUBJ_ROLE:
  1891 + case AUDIT_OBJ_ROLE:
1885 1892 roledatum = hashtab_search(policydb.p_roles.table, rulestr);
1886 1893 if (!roledatum)
1887 1894 rc = -EINVAL;
1888 1895 else
1889 1896 tmprule->au_ctxt.role = roledatum->value;
1890 1897 break;
1891   - case AUDIT_SE_TYPE:
  1898 + case AUDIT_SUBJ_TYPE:
  1899 + case AUDIT_OBJ_TYPE:
1892 1900 typedatum = hashtab_search(policydb.p_types.table, rulestr);
1893 1901 if (!typedatum)
1894 1902 rc = -EINVAL;
1895 1903 else
1896 1904 tmprule->au_ctxt.type = typedatum->value;
1897 1905 break;
1898   - case AUDIT_SE_SEN:
1899   - case AUDIT_SE_CLR:
  1906 + case AUDIT_SUBJ_SEN:
  1907 + case AUDIT_SUBJ_CLR:
  1908 + case AUDIT_OBJ_LEV_LOW:
  1909 + case AUDIT_OBJ_LEV_HIGH:
1900 1910 rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
1901 1911 break;
1902 1912 }
... ... @@ -1948,7 +1958,8 @@
1948 1958 /* a field/op pair that is not caught here will simply fall through
1949 1959 without a match */
1950 1960 switch (field) {
1951   - case AUDIT_SE_USER:
  1961 + case AUDIT_SUBJ_USER:
  1962 + case AUDIT_OBJ_USER:
1952 1963 switch (op) {
1953 1964 case AUDIT_EQUAL:
1954 1965 match = (ctxt->user == rule->au_ctxt.user);
... ... @@ -1958,7 +1969,8 @@
1958 1969 break;
1959 1970 }
1960 1971 break;
1961   - case AUDIT_SE_ROLE:
  1972 + case AUDIT_SUBJ_ROLE:
  1973 + case AUDIT_OBJ_ROLE:
1962 1974 switch (op) {
1963 1975 case AUDIT_EQUAL:
1964 1976 match = (ctxt->role == rule->au_ctxt.role);
... ... @@ -1968,7 +1980,8 @@
1968 1980 break;
1969 1981 }
1970 1982 break;
1971   - case AUDIT_SE_TYPE:
  1983 + case AUDIT_SUBJ_TYPE:
  1984 + case AUDIT_OBJ_TYPE:
1972 1985 switch (op) {
1973 1986 case AUDIT_EQUAL:
1974 1987 match = (ctxt->type == rule->au_ctxt.type);
... ... @@ -1978,9 +1991,12 @@
1978 1991 break;
1979 1992 }
1980 1993 break;
1981   - case AUDIT_SE_SEN:
1982   - case AUDIT_SE_CLR:
1983   - level = (field == AUDIT_SE_SEN ?
  1994 + case AUDIT_SUBJ_SEN:
  1995 + case AUDIT_SUBJ_CLR:
  1996 + case AUDIT_OBJ_LEV_LOW:
  1997 + case AUDIT_OBJ_LEV_HIGH:
  1998 + level = ((field == AUDIT_SUBJ_SEN ||
  1999 + field == AUDIT_OBJ_LEV_LOW) ?
1984 2000 &ctxt->range.level[0] : &ctxt->range.level[1]);
1985 2001 switch (op) {
1986 2002 case AUDIT_EQUAL: