From: Eric Paris <epa...@redhat.com> 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. This means that if the inode in question is unlinked and creat'd (aka updated) the rule will just continue to work.
Signed-off-by: Eric Paris <epa...@redhat.com> Signed-off-by: Richard Guy Briggs <r...@redhat.com> --- include/linux/audit.h | 2 +- kernel/audit.h | 31 ++++------------- kernel/audit_exe.c | 87 +++++++------------------------------------------ kernel/auditfilter.c | 18 ++++++---- 4 files changed, 31 insertions(+), 107 deletions(-) diff --git a/include/linux/audit.h b/include/linux/audit.h index 227171c..f2a8044 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -59,7 +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_exe *exe; + 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; diff --git a/kernel/audit.h b/kernel/audit.h index 8d863d4..61688ba 100644 --- a/kernel/audit.h +++ b/kernel/audit.h @@ -57,7 +57,6 @@ enum audit_state { /* Rule lists */ struct audit_watch; struct audit_fsnotify_mark; -struct audit_exe; struct audit_tree; struct audit_chunk; @@ -289,11 +288,8 @@ char *audit_mark_path(struct audit_fsnotify_mark *mark); void audit_remove_mark(struct audit_fsnotify_mark *audit_mark); int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev); -int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op); -void audit_remove_exe_rule(struct audit_krule *krule); -char *audit_exe_path(struct audit_exe *exe); int audit_dup_exe(struct audit_krule *new, struct audit_krule *old); -int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe); +int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark); #else #define audit_put_watch(w) {} @@ -320,31 +316,18 @@ static inline void audit_remove_mark(struct audit_fsnotify_mark *audit_mark) BUG(); } -static inline int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev) +static inline int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark) { BUG(); - return 0; -} - -static inline int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op) { return -EINVAL; } -static inline void audit_remove_exe_rule(struct audit_krule *krule) { - BUG(); - return 0; -} -static inline char *audit_exe_path(struct audit_exe *exe) { - BUG(); - return ""; -} -static inline int audit_dup_exe(struct audit_krule *new, struct audit_krule *old) { - BUG(); - return -EINVAL -} -static inline int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe) { + +static inline int audit_dup_exe(struct audit_krule *new, struct audit_krule *old) +{ BUG(); - return 0; + return -EINVAL; } + #endif /* CONFIG_AUDIT_WATCH */ #ifdef CONFIG_AUDIT_TREE diff --git a/kernel/audit_exe.c b/kernel/audit_exe.c index 09c436c..d704a54 100644 --- a/kernel/audit_exe.c +++ b/kernel/audit_exe.c @@ -21,93 +21,30 @@ #include <linux/kernel.h> #include <linux/audit.h> -#include <linux/mutex.h> #include <linux/fs.h> #include <linux/namei.h> #include <linux/slab.h> #include "audit.h" -struct audit_exe { - char *pathname; - unsigned long ino; - dev_t dev; -}; - -/* Translate a watch string to kernel respresentation. */ -int audit_make_exe_rule(struct audit_krule *krule, char *pathname, int len, u32 op) -{ - struct audit_exe *exe; - struct path path; - struct dentry *dentry; - unsigned long ino; - dev_t dev; - - if (pathname[0] != '/' || pathname[len-1] == '/') - return -EINVAL; - - dentry = kern_path_locked(pathname, &path); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - mutex_unlock(&path.dentry->d_inode->i_mutex); - - if (!dentry->d_inode) - return -ENOENT; - dev = dentry->d_inode->i_sb->s_dev; - ino = dentry->d_inode->i_ino; - dput(dentry); - - exe = kmalloc(sizeof(*exe), GFP_KERNEL); - if (!exe) - return -ENOMEM; - exe->ino = ino; - exe->dev = dev; - exe->pathname = pathname; - krule->exe = exe; - - return 0; -} - -void audit_remove_exe_rule(struct audit_krule *krule) -{ - struct audit_exe *exe; - - exe = krule->exe; - krule->exe = NULL; - kfree(exe->pathname); - kfree(exe); -} - -char *audit_exe_path(struct audit_exe *exe) -{ - return exe->pathname; -} - int audit_dup_exe(struct audit_krule *new, struct audit_krule *old) { - struct audit_exe *exe; - - exe = kmalloc(sizeof(*exe), GFP_KERNEL); - if (!exe) - return -ENOMEM; + struct audit_fsnotify_mark *audit_mark; + char *pathname; - exe->pathname = kstrdup(old->exe->pathname, GFP_KERNEL); - if (!exe->pathname) { - kfree(exe); - return -ENOMEM; - } + pathname = audit_mark_path(old->exe); - exe->ino = old->exe->ino; - exe->dev = old->exe->dev; - new->exe = exe; + audit_mark = audit_alloc_mark(pathname, strlen(pathname), new); + if (IS_ERR(audit_mark)) + return PTR_ERR(audit_mark); + new->exe = audit_mark; return 0; } -int audit_exe_compare(struct task_struct *tsk, struct audit_exe *exe) +int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark) { - if (tsk->mm->exe_file->f_inode->i_ino != exe->ino) - return 0; - if (tsk->mm->exe_file->f_inode->i_sb->s_dev != exe->dev) - return 0; - return 1; + 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); } diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 5c1951a..30091ce 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -411,6 +411,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, size_t remain = datasz - sizeof(struct audit_rule_data); int i; char *str; + struct audit_fsnotify_mark *audit_mark; entry = audit_to_entry_common(data); if (IS_ERR(entry)) @@ -550,6 +551,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, 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); @@ -559,11 +561,13 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data, } entry->rule.buflen += f->val; - err = audit_make_exe_rule(&entry->rule, str, f->val, f->op); - if (err) { - kfree(str); + audit_mark = audit_alloc_mark(str, f->val, &entry->rule); + kfree(str); + if (IS_ERR(audit_mark)) { + err = PTR_ERR(audit_mark); goto exit_free; } + entry->rule.exe = audit_mark; break; } } @@ -646,7 +650,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule) case AUDIT_EXE: case AUDIT_EXE_CHILDREN: data->buflen += data->values[i] = - audit_pack_string(&bufp, audit_exe_path(krule->exe)); + audit_pack_string(&bufp, audit_mark_path(krule->exe)); break; default: data->values[i] = f->val; @@ -706,8 +710,8 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b) case AUDIT_EXE: case AUDIT_EXE_CHILDREN: /* both paths exist based on above type compare */ - if (strcmp(audit_exe_path(a->exe), - audit_exe_path(b->exe))) + if (strcmp(audit_mark_path(a->exe), + audit_mark_path(b->exe))) return 1; break; case AUDIT_UID: @@ -1008,7 +1012,7 @@ int audit_del_rule(struct audit_entry *entry) audit_remove_tree_rule(&e->rule); if (e->rule.exe) - audit_remove_exe_rule(&e->rule); + audit_remove_mark(e->rule.exe); list_del_rcu(&e->list); list_del(&e->rule.list); call_rcu(&e->rcu, audit_free_rule_rcu); -- 1.7.1 -- Linux-audit mailing list Linux-audit@redhat.com https://www.redhat.com/mailman/listinfo/linux-audit