Merge ath-next from ath.git
[firefly-linux-kernel-4.4.55.git] / kernel / audit_watch.c
index b81ad5bc74850ff0c23df911db9241e359e002f0..656c7e93ac0d30d3e42a8f7e0dfc7dd071360d78 100644 (file)
@@ -138,7 +138,7 @@ char *audit_watch_path(struct audit_watch *watch)
 
 int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
 {
-       return (watch->ino != (unsigned long)-1) &&
+       return (watch->ino != AUDIT_INO_UNSET) &&
                (watch->ino == ino) &&
                (watch->dev == dev);
 }
@@ -146,7 +146,7 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
 /* Initialize a parent watch entry. */
 static struct audit_parent *audit_init_parent(struct path *path)
 {
-       struct inode *inode = path->dentry->d_inode;
+       struct inode *inode = d_backing_inode(path->dentry);
        struct audit_parent *parent;
        int ret;
 
@@ -179,8 +179,8 @@ static struct audit_watch *audit_init_watch(char *path)
        INIT_LIST_HEAD(&watch->rules);
        atomic_set(&watch->count, 1);
        watch->path = path;
-       watch->dev = (dev_t)-1;
-       watch->ino = (unsigned long)-1;
+       watch->dev = AUDIT_DEV_UNSET;
+       watch->ino = AUDIT_INO_UNSET;
 
        return watch;
 }
@@ -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);
@@ -360,11 +364,11 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
        struct dentry *d = kern_path_locked(watch->path, parent);
        if (IS_ERR(d))
                return PTR_ERR(d);
-       mutex_unlock(&parent->dentry->d_inode->i_mutex);
-       if (d->d_inode) {
+       mutex_unlock(&d_backing_inode(parent->dentry)->i_mutex);
+       if (d_is_positive(d)) {
                /* update watch filter fields */
-               watch->dev = d->d_inode->i_sb->s_dev;
-               watch->ino = d->d_inode->i_ino;
+               watch->dev = d_backing_inode(d)->i_sb->s_dev;
+               watch->ino = d_backing_inode(d)->i_ino;
        }
        dput(d);
        return 0;
@@ -426,7 +430,7 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
                return ret;
 
        /* either find an old parent or attach a new one */
-       parent = audit_find_parent(parent_path.dentry->d_inode);
+       parent = audit_find_parent(d_backing_inode(parent_path.dentry));
        if (!parent) {
                parent = audit_init_parent(&parent_path);
                if (IS_ERR(parent)) {
@@ -479,7 +483,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
 
        switch (data_type) {
        case (FSNOTIFY_EVENT_PATH):
-               inode = ((struct path *)data)->dentry->d_inode;
+               inode = d_backing_inode(((struct path *)data)->dentry);
                break;
        case (FSNOTIFY_EVENT_INODE):
                inode = (struct inode *)data;
@@ -493,7 +497,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
        if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
                audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
        else if (mask & (FS_DELETE|FS_MOVED_FROM))
-               audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
+               audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
        else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
                audit_remove_parent_watches(parent);
 
@@ -514,3 +518,36 @@ 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)
+{
+       struct file *exe_file;
+       unsigned long ino;
+       dev_t dev;
+
+       rcu_read_lock();
+       exe_file = rcu_dereference(tsk->mm->exe_file);
+       ino = exe_file->f_inode->i_ino;
+       dev = exe_file->f_inode->i_sb->s_dev;
+       rcu_read_unlock();
+       return audit_mark_compare(mark, ino, dev);
+}