aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/audit.h1
-rw-r--r--include/uapi/linux/audit.h5
-rw-r--r--kernel/audit.h4
-rw-r--r--kernel/audit_tree.c2
-rw-r--r--kernel/audit_watch.c31
-rw-r--r--kernel/auditfilter.c53
-rw-r--r--kernel/auditsc.c3
7 files changed, 97 insertions, 2 deletions
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 759feb0e9d13..b2abc996c25d 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -62,6 +62,7 @@ struct audit_krule {
62 struct audit_field *inode_f; /* quick access to an inode field */ 62 struct audit_field *inode_f; /* quick access to an inode field */
63 struct audit_watch *watch; /* associated watch */ 63 struct audit_watch *watch; /* associated watch */
64 struct audit_tree *tree; /* associated watched tree */ 64 struct audit_tree *tree; /* associated watched tree */
65 struct audit_fsnotify_mark *exe;
65 struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ 66 struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
66 struct list_head list; /* for AUDIT_LIST* purposes only */ 67 struct list_head list; /* for AUDIT_LIST* purposes only */
67 u64 prio; 68 u64 prio;
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index d3475e1f15ec..f6ff62c24aba 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,7 @@
266#define AUDIT_OBJ_UID 109 266#define AUDIT_OBJ_UID 109
267#define AUDIT_OBJ_GID 110 267#define AUDIT_OBJ_GID 110
268#define AUDIT_FIELD_COMPARE 111 268#define AUDIT_FIELD_COMPARE 111
269#define AUDIT_EXE 112
269 270
270#define AUDIT_ARG0 200 271#define AUDIT_ARG0 200
271#define AUDIT_ARG1 (AUDIT_ARG0+1) 272#define AUDIT_ARG1 (AUDIT_ARG0+1)
@@ -324,8 +325,10 @@ enum {
324 325
325#define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT 0x00000001 326#define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT 0x00000001
326#define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME 0x00000002 327#define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME 0x00000002
328#define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH 0x00000004
327#define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \ 329#define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \
328 AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME) 330 AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \
331 AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH)
329 332
330/* deprecated: AUDIT_VERSION_* */ 333/* deprecated: AUDIT_VERSION_* */
331#define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL 334#define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL
diff --git a/kernel/audit.h b/kernel/audit.h
index 7102d538737b..24ec86145667 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -274,6 +274,8 @@ extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
274extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark); 274extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
275extern void audit_remove_mark_rule(struct audit_krule *krule); 275extern void audit_remove_mark_rule(struct audit_krule *krule);
276extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev); 276extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev);
277extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old);
278extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark);
277 279
278#else 280#else
279#define audit_put_watch(w) {} 281#define audit_put_watch(w) {}
@@ -289,6 +291,8 @@ extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long in
289#define audit_remove_mark(m) 291#define audit_remove_mark(m)
290#define audit_remove_mark_rule(k) 292#define audit_remove_mark_rule(k)
291#define audit_mark_compare(m, i, d) 0 293#define audit_mark_compare(m, i, d) 0
294#define audit_exe_compare(t, m) (-EINVAL)
295#define audit_dupe_exe(n, o) (-EINVAL)
292#endif /* CONFIG_AUDIT_WATCH */ 296#endif /* CONFIG_AUDIT_WATCH */
293 297
294#ifdef CONFIG_AUDIT_TREE 298#ifdef CONFIG_AUDIT_TREE
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 2e0c97427b33..f41722506808 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -478,6 +478,8 @@ static void kill_rules(struct audit_tree *tree)
478 if (rule->tree) { 478 if (rule->tree) {
479 /* not a half-baked one */ 479 /* not a half-baked one */
480 audit_tree_log_remove_rule(rule); 480 audit_tree_log_remove_rule(rule);
481 if (entry->rule.exe)
482 audit_remove_mark(entry->rule.exe);
481 rule->tree = NULL; 483 rule->tree = NULL;
482 list_del_rcu(&entry->list); 484 list_del_rcu(&entry->list);
483 list_del(&entry->rule.list); 485 list_del(&entry->rule.list);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 645c6884cee5..27ef8dcf7cd8 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -312,6 +312,8 @@ static void audit_update_watch(struct audit_parent *parent,
312 list_replace(&oentry->rule.list, 312 list_replace(&oentry->rule.list,
313 &nentry->rule.list); 313 &nentry->rule.list);
314 } 314 }
315 if (oentry->rule.exe)
316 audit_remove_mark(oentry->rule.exe);
315 317
316 audit_watch_log_rule_change(r, owatch, "updated_rules"); 318 audit_watch_log_rule_change(r, owatch, "updated_rules");
317 319
@@ -342,6 +344,8 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
342 list_for_each_entry_safe(r, nextr, &w->rules, rlist) { 344 list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
343 e = container_of(r, struct audit_entry, rule); 345 e = container_of(r, struct audit_entry, rule);
344 audit_watch_log_rule_change(r, w, "remove_rule"); 346 audit_watch_log_rule_change(r, w, "remove_rule");
347 if (e->rule.exe)
348 audit_remove_mark(e->rule.exe);
345 list_del(&r->rlist); 349 list_del(&r->rlist);
346 list_del(&r->list); 350 list_del(&r->list);
347 list_del_rcu(&e->list); 351 list_del_rcu(&e->list);
@@ -514,3 +518,30 @@ static int __init audit_watch_init(void)
514 return 0; 518 return 0;
515} 519}
516device_initcall(audit_watch_init); 520device_initcall(audit_watch_init);
521
522int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
523{
524 struct audit_fsnotify_mark *audit_mark;
525 char *pathname;
526
527 pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
528 if (!pathname)
529 return -ENOMEM;
530
531 audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
532 if (IS_ERR(audit_mark)) {
533 kfree(pathname);
534 return PTR_ERR(audit_mark);
535 }
536 new->exe = audit_mark;
537
538 return 0;
539}
540
541int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
542{
543 unsigned long ino = tsk->mm->exe_file->f_inode->i_ino;
544 dev_t dev = tsk->mm->exe_file->f_inode->i_sb->s_dev;
545
546 return audit_mark_compare(mark, ino, dev);
547}
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index b4d8c366ec30..7714d93edb85 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -405,6 +405,12 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
405 if (f->val > AUDIT_MAX_FIELD_COMPARE) 405 if (f->val > AUDIT_MAX_FIELD_COMPARE)
406 return -EINVAL; 406 return -EINVAL;
407 break; 407 break;
408 case AUDIT_EXE:
409 if (f->op != Audit_equal)
410 return -EINVAL;
411 if (entry->rule.listnr != AUDIT_FILTER_EXIT)
412 return -EINVAL;
413 break;
408 }; 414 };
409 return 0; 415 return 0;
410} 416}
@@ -419,6 +425,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
419 size_t remain = datasz - sizeof(struct audit_rule_data); 425 size_t remain = datasz - sizeof(struct audit_rule_data);
420 int i; 426 int i;
421 char *str; 427 char *str;
428 struct audit_fsnotify_mark *audit_mark;
422 429
423 entry = audit_to_entry_common(data); 430 entry = audit_to_entry_common(data);
424 if (IS_ERR(entry)) 431 if (IS_ERR(entry))
@@ -539,6 +546,24 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
539 entry->rule.buflen += f->val; 546 entry->rule.buflen += f->val;
540 entry->rule.filterkey = str; 547 entry->rule.filterkey = str;
541 break; 548 break;
549 case AUDIT_EXE:
550 if (entry->rule.exe || f->val > PATH_MAX)
551 goto exit_free;
552 str = audit_unpack_string(&bufp, &remain, f->val);
553 if (IS_ERR(str)) {
554 err = PTR_ERR(str);
555 goto exit_free;
556 }
557 entry->rule.buflen += f->val;
558
559 audit_mark = audit_alloc_mark(&entry->rule, str, f->val);
560 if (IS_ERR(audit_mark)) {
561 kfree(str);
562 err = PTR_ERR(audit_mark);
563 goto exit_free;
564 }
565 entry->rule.exe = audit_mark;
566 break;
542 } 567 }
543 } 568 }
544 569
@@ -551,6 +576,8 @@ exit_nofree:
551exit_free: 576exit_free:
552 if (entry->rule.tree) 577 if (entry->rule.tree)
553 audit_put_tree(entry->rule.tree); /* that's the temporary one */ 578 audit_put_tree(entry->rule.tree); /* that's the temporary one */
579 if (entry->rule.exe)
580 audit_remove_mark(entry->rule.exe); /* that's the template one */
554 audit_free_rule(entry); 581 audit_free_rule(entry);
555 return ERR_PTR(err); 582 return ERR_PTR(err);
556} 583}
@@ -615,6 +642,10 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
615 data->buflen += data->values[i] = 642 data->buflen += data->values[i] =
616 audit_pack_string(&bufp, krule->filterkey); 643 audit_pack_string(&bufp, krule->filterkey);
617 break; 644 break;
645 case AUDIT_EXE:
646 data->buflen += data->values[i] =
647 audit_pack_string(&bufp, audit_mark_path(krule->exe));
648 break;
618 case AUDIT_LOGINUID_SET: 649 case AUDIT_LOGINUID_SET:
619 if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) { 650 if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
620 data->fields[i] = AUDIT_LOGINUID; 651 data->fields[i] = AUDIT_LOGINUID;
@@ -678,6 +709,12 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
678 if (strcmp(a->filterkey, b->filterkey)) 709 if (strcmp(a->filterkey, b->filterkey))
679 return 1; 710 return 1;
680 break; 711 break;
712 case AUDIT_EXE:
713 /* both paths exist based on above type compare */
714 if (strcmp(audit_mark_path(a->exe),
715 audit_mark_path(b->exe)))
716 return 1;
717 break;
681 case AUDIT_UID: 718 case AUDIT_UID:
682 case AUDIT_EUID: 719 case AUDIT_EUID:
683 case AUDIT_SUID: 720 case AUDIT_SUID:
@@ -799,8 +836,14 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
799 err = -ENOMEM; 836 err = -ENOMEM;
800 else 837 else
801 new->filterkey = fk; 838 new->filterkey = fk;
839 break;
840 case AUDIT_EXE:
841 err = audit_dupe_exe(new, old);
842 break;
802 } 843 }
803 if (err) { 844 if (err) {
845 if (new->exe)
846 audit_remove_mark(new->exe);
804 audit_free_rule(entry); 847 audit_free_rule(entry);
805 return ERR_PTR(err); 848 return ERR_PTR(err);
806 } 849 }
@@ -963,6 +1006,9 @@ int audit_del_rule(struct audit_entry *entry)
963 if (e->rule.tree) 1006 if (e->rule.tree)
964 audit_remove_tree_rule(&e->rule); 1007 audit_remove_tree_rule(&e->rule);
965 1008
1009 if (e->rule.exe)
1010 audit_remove_mark_rule(&e->rule);
1011
966#ifdef CONFIG_AUDITSYSCALL 1012#ifdef CONFIG_AUDITSYSCALL
967 if (!dont_count) 1013 if (!dont_count)
968 audit_n_rules--; 1014 audit_n_rules--;
@@ -1067,8 +1113,11 @@ int audit_rule_change(int type, __u32 portid, int seq, void *data,
1067 WARN_ON(1); 1113 WARN_ON(1);
1068 } 1114 }
1069 1115
1070 if (err || type == AUDIT_DEL_RULE) 1116 if (err || type == AUDIT_DEL_RULE) {
1117 if (entry->rule.exe)
1118 audit_remove_mark(entry->rule.exe);
1071 audit_free_rule(entry); 1119 audit_free_rule(entry);
1120 }
1072 1121
1073 return err; 1122 return err;
1074} 1123}
@@ -1360,6 +1409,8 @@ static int update_lsm_rule(struct audit_krule *r)
1360 return 0; 1409 return 0;
1361 1410
1362 nentry = audit_dupe_rule(r); 1411 nentry = audit_dupe_rule(r);
1412 if (entry->rule.exe)
1413 audit_remove_mark(entry->rule.exe);
1363 if (IS_ERR(nentry)) { 1414 if (IS_ERR(nentry)) {
1364 /* save the first error encountered for the 1415 /* save the first error encountered for the
1365 * return value */ 1416 * return value */
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ea3fe2b748a8..9b56b7ae053f 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -466,6 +466,9 @@ static int audit_filter_rules(struct task_struct *tsk,
466 result = audit_comparator(ctx->ppid, f->op, f->val); 466 result = audit_comparator(ctx->ppid, f->op, f->val);
467 } 467 }
468 break; 468 break;
469 case AUDIT_EXE:
470 result = audit_exe_compare(tsk, rule->exe);
471 break;
469 case AUDIT_UID: 472 case AUDIT_UID:
470 result = audit_uid_comparator(cred->uid, f->op, f->uid); 473 result = audit_uid_comparator(cred->uid, f->op, f->uid);
471 break; 474 break;