audit by executable name
v8 cover audit by executable name
Please see the accompanying userspace patchset:
https://www.redhat.com/archives/linux-audit/2015-July/thread.html
[[PATCH V2] 0/2] Log on the future execution of a path
The userspace interface is not expected to change appreciably unless something important has been overlooked. Setting and deleting rules works as expected.
If the path does not exist at rule creation time, it will be re-evaluated every time there is a change to the parent directory at which point the change in device and inode will be noted.
Here's a sample run:
Test for addition, trigger and deletion of tree executable rule:
# auditctl -a always,exit -S all -F dir=/tmp -F exe=/usr/bin/touch -F key=exetest_tree ---- time->Sat Jul 11 10:41:50 2015 type=CONFIG_CHANGE msg=audit(1436629310.720:44711): auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="add_rule" key="exetest_tree" list=4 res=1 ----
# /usr/bin/touch /tmp/test ---- time->Sat Jul 11 10:41:50 2015 type=PROCTITLE msg=audit(1436629310.757:44712): proctitle=2F7573722F62696E2F746F756368002F746D702F74657374 type=PATH msg=audit(1436629310.757:44712): item=1 name="/tmp/test" inode=166932 dev=00:24 mode=0100644 ouid=0 ogid=0 rdev=00:00 obj=unconfined_u:object_r:user_tmp_t:s0 nametype=CREATE type=PATH msg=audit(1436629310.757:44712): item=0 name="/tmp/" inode=11525 dev=00:24 mode=041777 ouid=0 ogid=0 rdev=00:00 obj=system_u:object_r:tmp_t:s0 nametype=PARENT type=CWD msg=audit(1436629310.757:44712): cwd="/root" type=SYSCALL msg=audit(1436629310.757:44712): arch=c000003e syscall=2 success=yes exit=3 a0=7ffdee2f9e27 a1=941 a2=1b6 a3=691 items=2 ppid=17655 pid=17762 auid=0 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=ttyS0 ses=1 comm="touch" exe="/usr/bin/touch" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key="exetest_tree" ----
# auditctl -d always,exit -S all -F dir=/tmp -F exe=/usr/bin/touch -F key=exetest_tree ---- time->Sat Jul 11 10:41:50 2015 type=CONFIG_CHANGE msg=audit(1436629310.839:44713): auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 op="remove_rule" key="exetest_tree" list=4 res=1 ----
Revision history:
v8: Re-spin due to mods to:
"audit: save signal match info in case entry passed in is the one deleted"
v7: Add Audit Feature Bitmap macro AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH to
AUDIT_FEATURE_BITMAP_ALL.
Split out new patch to use macros for unset inode and device values. Remove BUG() usage in stubs.
Rename audit_mark_free() to audit_fsnotify_mark_free().
Remove unused audit_get_mark() and audit_put_mark() functions.
Rework ino and dev comparisons and assignments, using macros and existing
funcs and eliminating temp variables.
Move audit_update_mark() above its first usage.
Move contents of kernel/audit_exe.c to kernel/audit_watch.c.
Merge patch 3 with 1, merge patch 4 with 1 and 3 and rewrite the patch descriptions. Split out patch to audit by executable children.
v6: Explicitly declare prototypes as external.
Rename audit_dup_exe() to audit_dupe_exe() consistent with rule, watch, lsm_field. Rebased on v4.1.
Rename audit_remove_mark_rule() called from audit_mark_handle_event() to
audit_autoremove_mark_rule() to avoid confusion with audit_remove_{watch,tree}_rule() usage.
Add audit_remove_mark_rule() to provide similar interface as
audit_remove_{watch,tree}_rule().
Simplify stubs to defines.
Rename audit_free_fsnotify_mark() to audit_fsnotify_free_mark() in keeping with
the naming convention of inotify_free_mark(), dnotify_free_mark(), fanotify_free_mark(), audit_watch_free_mark().
Return -ENOMEM rather than null in case of memory allocation failure for
audit_mark in audit_alloc_mark().
Rename audit_free_mark() to audit_mark_free() to avoid association with
{i,d,fa}notify_free_mark() and audit_watch_free_mark().
Clean up exe with similar interface as watch and tree.
Clean up audit exe mark just before audit_free_rule() rather than in it to
avoid mutex in software interrupt context.
Fixed bug in audit_dupe_exe() that returned error rather than valid pointer.
v5: Revert patch "Let audit_free_rule() take care of calling
audit_remove_mark()." since it caused a group mark deadlock.
https://www.redhat.com/archives/linux-audit/2014-October/msg00024.html
v4: Re-order and squash down fixups
Fix audit_dup_exe() to copy pathname string before calling audit_alloc_mark().
https://www.redhat.com/archives/linux-audit/2014-August/msg00065.html
v3: Rationalize and rename some function names and clean up get/put and free code.
Rename several "watch" references to "mark".
Rename audit_remove_rule() to audit_remove_mark_rule().
Let audit_free_rule() take care of calling audit_remove_mark(). Put audit_alloc_mark() arguments in same order as watch, tree and inode. Move the access to the entry for audit_match_signal() to the beginning
of the function in case the entry found is the same one passed in. This will enable it to be used by audit_remove_mark_rule().
https://www.redhat.com/archives/linux-audit/2014-July/msg00000.html
v2: Misguided attempt to add in audit_exe similar to watches
https://www.redhat.com/archives/linux-audit/2014-June/msg00066.html
v1.5: eparis' switch to fsnotify
https://www.redhat.com/archives/linux-audit/2014-May/msg00046.html https://www.redhat.com/archives/linux-audit/2014-May/msg00066.html
v1: Change to path interface instead of inode
https://www.redhat.com/archives/linux-audit/2014-May/msg00017.html
v0: Peter Moodie's original patches
https://www.redhat.com/archives/linux-audit/2012-August/msg00033.html
Future step:
Get full-path notify working.
Richard Guy Briggs (3):
audit: clean simple fsnotify implementation
audit: implement audit by executable
audit: add audit by children of executable path
include/linux/audit.h | 1 + include/uapi/linux/audit.h | 6 +- kernel/Makefile | 2 +- kernel/audit.h | 18 ++++ kernel/audit_fsnotify.c | 215 ++++++++++++++++++++++++++++++++++++++++++++ kernel/audit_tree.c | 2 + kernel/audit_watch.c | 31 +++++++ kernel/auditfilter.c | 57 +++++++++++- kernel/auditsc.c | 14 +++ 9 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 kernel/audit_fsnotify.c
PATCH v8 1/3 audit: clean simple fsnotify implementation
This is to be used to audit by executable path rules, but audit watches should be able to share this code eventually.
At the moment the audit watch code is a lot more complex. That code only creates one fsnotify watch per parent directory. That 'audit_parent' in turn has a list of 'audit_watches' which contain the name, ino, dev of the specific object we care about. This just creates one fsnotify watch per object we care about. So if you watch 100 inodes in /etc this code will create 100 fsnotify watches on /etc. The audit_watch code will instead create 1 fsnotify watch on /etc (the audit_parent) and then 100 individual watches chained from that fsnotify mark.
We should be able to convert the audit_watch code to do one fsnotify mark per watch and simplify things/remove a whole lot of code. After that conversion we should be able to convert the audit_fsnotify code to support that hierarchy if the optimization is necessary.
Move the access to the entry for audit_match_signal() to the beginning of the audit_del_rule() function in case the entry found is the same one passed in. This will enable it to be used by audit_autoremove_mark_rule(), kill_rules() and audit_remove_parent_watches().
This is a heavily modified and merged version of two patches originally submitted by Eric Paris.
--- kernel/Makefile | 2 +- kernel/audit.h | 14 +++ kernel/audit_fsnotify.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++ kernel/auditfilter.c | 2 +- 4 files changed, 231 insertions(+), 2 deletions(-) create mode 100644 kernel/audit_fsnotify.c
kernel/Makefile +1 -1
@@ -64,7 +64,7 @@ obj-$(CONFIG_SMP) += stop_machine.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o -obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o +obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_GCOV_KERNEL) += gcov/ obj-$(CONFIG_KPROBES) += kprobes.o
kernel/audit.h +14 -0
@@ -50,6 +50,7 @@ enum audit_state {/* Rule lists */ struct audit_watch ; +struct audit_fsnotify_mark ;struct audit_tree ;struct audit_chunk ;
@@ -252,6 +253,7 @@ struct audit_net {extern int selinux_audit_rule_update (void );extern struct mutex audit_filter_mutex; +extern int audit_del_rule (struct audit_entry *);extern void audit_free_rule_rcu (struct rcu_head *);extern struct list_head audit_filter_list[];
@@ -269,6 +271,13 @@ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);extern void audit_remove_watch_rule (struct audit_krule *krule);extern char *audit_watch_path (struct audit_watch *watch);extern int audit_watch_compare (struct audit_watch *watch,unsigned long ino,dev_t dev); + +extern struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname,int len); +extern char *audit_mark_path (struct audit_fsnotify_mark *mark); +extern void audit_remove_mark (struct audit_fsnotify_mark *audit_mark); +extern void audit_remove_mark_rule (struct audit_krule *krule); +extern int audit_mark_compare (struct audit_fsnotify_mark *mark,unsigned long ino,dev_t dev); +#else #define audit_put_watch (w) {}#define audit_get_watch (w) {}
@@ -278,6 +287,11 @@ extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev#define audit_watch_path (w) ""#define audit_watch_compare (w, i, d) 0 +#define audit_alloc_mark (k, p, l) (ERR_PTR(-EINVAL)) +#define audit_mark_path (m) "" +#define audit_remove_mark (m) +#define audit_remove_mark_rule (k) +#define audit_mark_compare (m, i, d) 0#endif /* CONFIG_AUDIT_WATCH */ #ifdef CONFIG_AUDIT_TREE
kernel/audit_fsnotify.c new file +215 -0
215 lines not on this page · raw message
kernel/auditfilter.c +1 -1
@@ -935,7 +935,7 @@ static inline int audit_add_rule(struct audit_entry *entry) }/* Remove an existing rule from filterlist. */ -static inline int audit_del_rule (struct audit_entry *entry) +int audit_del_rule (struct audit_entry *entry) {struct audit_entry *e;struct audit_tree *tree = entry->rule.tree;
Signature · 1 line
1.7.1
PATCH v8 2/3 audit: implement audit by executable
In reply to Richard Guy BriggsThis adds the ability audit the actions of a not-yet-running process.
This patch implements the ability to filter on the executable path. Instead of just hard coding the ino and dev of the executable we care about at the moment the rule is inserted into the kernel, use the new audit_fsnotify infrastructure to manage this dynamically. This means that if the filename does not yet exist but the containing directory does, or if the inode in question is unlinked and creat'd (aka updated) the rule will just continue to work. If the containing directory is moved or deleted or the filesystem is unmounted, the rule is deleted automatically. A future enhancement would be to have the rule survive across directory disruptions.
This is a heavily modified version of a patch originally submitted by Eric Paris with some ideas from Peter Moody.
--- include/linux/audit.h | 1 + include/uapi/linux/audit.h | 5 +++- kernel/audit.h | 4 +++ kernel/audit_tree.c | 2 + kernel/audit_watch.c | 31 +++++++++++++++++++++++++++ kernel/auditfilter.c | 50 +++++++++++++++++++++++++++++++++++++++++++- kernel/auditsc.c | 3 ++ 7 files changed, 94 insertions(+), 2 deletions(-)
include/linux/audit.h +1 -0
@@ -59,6 +59,7 @@ struct audit_krule {struct audit_field *inode_f;/* quick access to an inode field */ struct audit_watch *watch;/* associated watch */ struct audit_tree *tree;/* associated watched tree */ +struct audit_fsnotify_mark *exe;struct list_head rlist;/* entry in audit_{watch,tree}.rules list */ struct list_head list;/* for AUDIT_LIST* purposes only */ u64 prio;
include/uapi/linux/audit.h +4 -1
@@ -266,6 +266,7 @@#define AUDIT_OBJ_UID 109#define AUDIT_OBJ_GID 110#define AUDIT_FIELD_COMPARE 111 +#define AUDIT_EXE 112#define AUDIT_ARG0 200#define AUDIT_ARG1 (AUDIT_ARG0+1)
@@ -324,8 +325,10 @@ enum {#define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT 0x00000001#define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME 0x00000002 +#define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH 0x00000004#define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \ - AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME) + AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \ + AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH )/* deprecated: AUDIT_VERSION_* */ #define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL
kernel/audit.h +4 -0
@@ -277,6 +277,8 @@ extern char *audit_mark_path(struct audit_fsnotify_mark *mark);extern void audit_remove_mark (struct audit_fsnotify_mark *audit_mark);extern void audit_remove_mark_rule (struct audit_krule *krule);extern int audit_mark_compare (struct audit_fsnotify_mark *mark,unsigned long ino,dev_t dev); +extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old); +extern int audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark);#else #define audit_put_watch (w) {}
@@ -292,6 +294,8 @@ extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long in#define audit_remove_mark (m)#define audit_remove_mark_rule (k)#define audit_mark_compare (m, i, d) 0 +#define audit_exe_compare (t, m) (-EINVAL) +#define audit_dupe_exe (n, o) (-EINVAL)#endif /* CONFIG_AUDIT_WATCH */ #ifdef CONFIG_AUDIT_TREE
kernel/audit_tree.c +2 -0
@@ -479,6 +479,8 @@ static void kill_rules(struct audit_tree *tree)if (rule->tree) {/* not a half-baked one */ audit_tree_log_remove_rule (rule); +if (entry->rule.exe) +audit_remove_mark (entry->rule.exe); rule->tree =NULL ;list_del_rcu (&entry->list);list_del (&entry->rule.list);
kernel/audit_watch.c +31 -0
@@ -312,6 +312,8 @@ static void audit_update_watch(struct audit_parent *parent,list_replace (&oentry->rule.list, &nentry->rule.list); } +if (oentry->rule.exe) +audit_remove_mark (oentry->rule.exe);audit_watch_log_rule_change (r, owatch,"updated_rules" );
@@ -342,6 +344,8 @@ static void audit_remove_parent_watches(struct audit_parent *parent)list_for_each_entry_safe (r, nextr, &w->rules, rlist) { e = container_of(r, struct audit_entry, rule);audit_watch_log_rule_change (r, w,"remove_rule" ); +if (e->rule.exe) +audit_remove_mark (e->rule.exe);list_del (&r->rlist);list_del (&r->list);list_del_rcu (&e->list);
@@ -514,3 +518,30 @@ static int __init audit_watch_init(void)return 0 ; }device_initcall (audit_watch_init); + +int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old) +{ +struct audit_fsnotify_mark *audit_mark; +char *pathname; + + pathname =kstrdup (audit_mark_path (old->exe),GFP_KERNEL ); +if (!pathname) +return -ENOMEM ; + + audit_mark =audit_alloc_mark (new, pathname,strlen (pathname)); +if (IS_ERR (audit_mark)) { +kfree (pathname); +return PTR_ERR (audit_mark); + } + new->exe = audit_mark; + +return 0 ; +} + +int audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark) +{ +unsigned long ino = tsk->mm->exe_file->f_inode->i_ino; +dev_t dev = tsk->mm->exe_file->f_inode->i_sb->s_dev; + +return audit_mark_compare (mark, ino, dev); +}
kernel/auditfilter.c +49 -1
107 lines not on this page · raw message
kernel/auditsc.c +3 -0
@@ -466,6 +466,9 @@ static int audit_filter_rules(struct task_struct *tsk, result =audit_comparator (ctx->ppid, f->op, f->val); }break ; +case AUDIT_EXE : + result =audit_exe_compare (tsk, rule->exe); +break ;case AUDIT_UID : result =audit_uid_comparator (cred->uid, f->op, f->uid);break ;
Signature · 1 line
1.7.1
PATCH v8 3/3 audit: add audit by children of executable path
In reply to Richard Guy BriggsThis adds the ability to audit the actions of children of a not-yet-running process.
This is a split-out of a heavily modified version of a patch originally submitted by Eric Paris with some ideas from Peter Moody.
--- include/uapi/linux/audit.h | 1 + kernel/auditfilter.c | 5 +++++ kernel/auditsc.c | 11 +++++++++++ 3 files changed, 17 insertions(+), 0 deletions(-)
include/uapi/linux/audit.h +1 -0
@@ -267,6 +267,7 @@#define AUDIT_OBJ_GID 110#define AUDIT_FIELD_COMPARE 111#define AUDIT_EXE 112 +#define AUDIT_EXE_CHILDREN 113#define AUDIT_ARG0 200#define AUDIT_ARG1 (AUDIT_ARG0+1)
kernel/auditfilter.c +5 -0
@@ -406,6 +406,7 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)return -EINVAL ;break ;case AUDIT_EXE : +case AUDIT_EXE_CHILDREN :if (f->op != Audit_equal)return -EINVAL ;if (entry->rule.listnr !=AUDIT_FILTER_EXIT )
@@ -547,6 +548,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, entry->rule.filterkey = str;break ;case AUDIT_EXE : +case AUDIT_EXE_CHILDREN :if (entry->rule.exe || f->val >PATH_MAX ) goto exit_free; str =audit_unpack_string (&bufp, &remain, f->val);
@@ -643,6 +645,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)audit_pack_string (&bufp, krule->filterkey);break ;case AUDIT_EXE : +case AUDIT_EXE_CHILDREN : data->buflen += data->values[i] =audit_pack_string (&bufp,audit_mark_path (krule->exe));break ;
@@ -710,6 +713,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)return 1 ;break ;case AUDIT_EXE : +case AUDIT_EXE_CHILDREN :/* both paths exist based on above type compare */ if (strcmp (audit_mark_path (a->exe),audit_mark_path (b->exe)))
@@ -838,6 +842,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old) new->filterkey = fk;break ;case AUDIT_EXE : +case AUDIT_EXE_CHILDREN : err =audit_dupe_exe (new, old);break ; }
kernel/auditsc.c +11 -0
@@ -469,6 +469,17 @@ static int audit_filter_rules(struct task_struct *tsk,case AUDIT_EXE : result =audit_exe_compare (tsk, rule->exe);break ; +case AUDIT_EXE_CHILDREN : + { +struct task_struct *ptsk; +for (ptsk = tsk; ptsk->parent->pid >0 ; ptsk =find_task_by_vpid (ptsk->parent->pid)) { +if (audit_exe_compare (ptsk, rule->exe)) { + ++result; +break ; + } + } + } +break ;case AUDIT_UID : result =audit_uid_comparator (cred->uid, f->op, f->uid);break ;
Signature · 1 line
1.7.1