Merge branch 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Feb 2015 23:27:47 +0000 (15:27 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 17 Feb 2015 23:27:47 +0000 (15:27 -0800)
Pull getname/putname updates from Al Viro:
 "Rework of getname/getname_kernel/etc., mostly from Paul Moore.  Gets
  rid of quite a pile of kludges between namei and audit..."

* 'getname2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  audit: replace getname()/putname() hacks with reference counters
  audit: fix filename matching in __audit_inode() and __audit_inode_child()
  audit: enable filename recording via getname_kernel()
  simpler calling conventions for filename_mountpoint()
  fs: create proper filename objects using getname_kernel()
  fs: rework getname_kernel to handle up to PATH_MAX sized filenames
  cut down the number of do_path_lookup() callers

fs/exec.c
fs/namei.c
fs/open.c
include/linux/audit.h
include/linux/fs.h
kernel/audit.h
kernel/auditsc.c

index ad8798e26be9f6e40d15607d0971bc2143611fcc..c7f9b733406dc22165647a8f415ce00324ae7daf 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -794,8 +794,14 @@ exit:
 
 struct file *open_exec(const char *name)
 {
-       struct filename tmp = { .name = name };
-       return do_open_execat(AT_FDCWD, &tmp, 0);
+       struct filename *filename = getname_kernel(name);
+       struct file *f = ERR_CAST(filename);
+
+       if (!IS_ERR(filename)) {
+               f = do_open_execat(AT_FDCWD, filename, 0);
+               putname(filename);
+       }
+       return f;
 }
 EXPORT_SYMBOL(open_exec);
 
index bc35b02883bb968812a7ec7cb62f4e1ff6e88de3..96ca11dea4a20c56b89ca126274b68089235346f 100644 (file)
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  * PATH_MAX includes the nul terminator --RR.
  */
-void final_putname(struct filename *name)
-{
-       if (name->separate) {
-               __putname(name->name);
-               kfree(name);
-       } else {
-               __putname(name);
-       }
-}
 
 #define EMBEDDED_NAME_MAX      (PATH_MAX - sizeof(struct filename))
 
@@ -145,6 +136,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
        result = __getname();
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
+       result->refcnt = 1;
 
        /*
         * First, try to embed the struct filename inside the names_cache
@@ -179,6 +171,7 @@ recopy:
                }
                result->name = kname;
                result->separate = true;
+               result->refcnt = 1;
                max = PATH_MAX;
                goto recopy;
        }
@@ -202,7 +195,7 @@ recopy:
        return result;
 
 error:
-       final_putname(result);
+       putname(result);
        return err;
 }
 
@@ -212,43 +205,56 @@ getname(const char __user * filename)
        return getname_flags(filename, 0, NULL);
 }
 
-/*
- * The "getname_kernel()" interface doesn't do pathnames longer
- * than EMBEDDED_NAME_MAX. Deal with it - you're a kernel user.
- */
 struct filename *
 getname_kernel(const char * filename)
 {
        struct filename *result;
-       char *kname;
-       int len;
-
-       len = strlen(filename);
-       if (len >= EMBEDDED_NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
+       int len = strlen(filename) + 1;
 
        result = __getname();
        if (unlikely(!result))
                return ERR_PTR(-ENOMEM);
 
-       kname = (char *)result + sizeof(*result);
-       result->name = kname;
+       if (len <= EMBEDDED_NAME_MAX) {
+               result->name = (char *)(result) + sizeof(*result);
+               result->separate = false;
+       } else if (len <= PATH_MAX) {
+               struct filename *tmp;
+
+               tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+               if (unlikely(!tmp)) {
+                       __putname(result);
+                       return ERR_PTR(-ENOMEM);
+               }
+               tmp->name = (char *)result;
+               tmp->separate = true;
+               result = tmp;
+       } else {
+               __putname(result);
+               return ERR_PTR(-ENAMETOOLONG);
+       }
+       memcpy((char *)result->name, filename, len);
        result->uptr = NULL;
        result->aname = NULL;
-       result->separate = false;
+       result->refcnt = 1;
+       audit_getname(result);
 
-       strlcpy(kname, filename, EMBEDDED_NAME_MAX);
        return result;
 }
 
-#ifdef CONFIG_AUDITSYSCALL
 void putname(struct filename *name)
 {
-       if (unlikely(!audit_dummy_context()))
-               return audit_putname(name);
-       final_putname(name);
+       BUG_ON(name->refcnt <= 0);
+
+       if (--name->refcnt > 0)
+               return;
+
+       if (name->separate) {
+               __putname(name->name);
+               kfree(name);
+       } else
+               __putname(name);
 }
-#endif
 
 static int check_acl(struct inode *inode, int mask)
 {
@@ -2036,31 +2042,47 @@ static int filename_lookup(int dfd, struct filename *name,
 static int do_path_lookup(int dfd, const char *name,
                                unsigned int flags, struct nameidata *nd)
 {
-       struct filename filename = { .name = name };
+       struct filename *filename = getname_kernel(name);
+       int retval = PTR_ERR(filename);
 
-       return filename_lookup(dfd, &filename, flags, nd);
+       if (!IS_ERR(filename)) {
+               retval = filename_lookup(dfd, filename, flags, nd);
+               putname(filename);
+       }
+       return retval;
 }
 
 /* does lookup, returns the object with parent locked */
 struct dentry *kern_path_locked(const char *name, struct path *path)
 {
+       struct filename *filename = getname_kernel(name);
        struct nameidata nd;
        struct dentry *d;
-       int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
-       if (err)
-               return ERR_PTR(err);
+       int err;
+
+       if (IS_ERR(filename))
+               return ERR_CAST(filename);
+
+       err = filename_lookup(AT_FDCWD, filename, LOOKUP_PARENT, &nd);
+       if (err) {
+               d = ERR_PTR(err);
+               goto out;
+       }
        if (nd.last_type != LAST_NORM) {
                path_put(&nd.path);
-               return ERR_PTR(-EINVAL);
+               d = ERR_PTR(-EINVAL);
+               goto out;
        }
        mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        d = __lookup_hash(&nd.last, nd.path.dentry, 0);
        if (IS_ERR(d)) {
                mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
                path_put(&nd.path);
-               return d;
+               goto out;
        }
        *path = nd.path;
+out:
+       putname(filename);
        return d;
 }
 
@@ -2351,13 +2373,17 @@ static int
 filename_mountpoint(int dfd, struct filename *s, struct path *path,
                        unsigned int flags)
 {
-       int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
+       int error;
+       if (IS_ERR(s))
+               return PTR_ERR(s);
+       error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
        if (unlikely(error == -ECHILD))
                error = path_mountpoint(dfd, s->name, path, flags);
        if (unlikely(error == -ESTALE))
                error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL);
        if (likely(!error))
                audit_inode(s, path->dentry, 0);
+       putname(s);
        return error;
 }
 
@@ -2379,21 +2405,14 @@ int
 user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
                        struct path *path)
 {
-       struct filename *s = getname(name);
-       int error;
-       if (IS_ERR(s))
-               return PTR_ERR(s);
-       error = filename_mountpoint(dfd, s, path, flags);
-       putname(s);
-       return error;
+       return filename_mountpoint(dfd, getname(name), path, flags);
 }
 
 int
 kern_path_mountpoint(int dfd, const char *name, struct path *path,
                        unsigned int flags)
 {
-       struct filename s = {.name = name};
-       return filename_mountpoint(dfd, &s, path, flags);
+       return filename_mountpoint(dfd, getname_kernel(name), path, flags);
 }
 EXPORT_SYMBOL(kern_path_mountpoint);
 
@@ -3273,7 +3292,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
 {
        struct nameidata nd;
        struct file *file;
-       struct filename filename = { .name = name };
+       struct filename *filename;
        int flags = op->lookup_flags | LOOKUP_ROOT;
 
        nd.root.mnt = mnt;
@@ -3282,15 +3301,20 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,
        if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
 
-       file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);
+       filename = getname_kernel(name);
+       if (unlikely(IS_ERR(filename)))
+               return ERR_CAST(filename);
+
+       file = path_openat(-1, filename, &nd, op, flags | LOOKUP_RCU);
        if (unlikely(file == ERR_PTR(-ECHILD)))
-               file = path_openat(-1, &filename, &nd, op, flags);
+               file = path_openat(-1, filename, &nd, op, flags);
        if (unlikely(file == ERR_PTR(-ESTALE)))
-               file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL);
+               file = path_openat(-1, filename, &nd, op, flags | LOOKUP_REVAL);
+       putname(filename);
        return file;
 }
 
-struct dentry *kern_path_create(int dfd, const char *pathname,
+static struct dentry *filename_create(int dfd, struct filename *name,
                                struct path *path, unsigned int lookup_flags)
 {
        struct dentry *dentry = ERR_PTR(-EEXIST);
@@ -3305,7 +3329,7 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
         */
        lookup_flags &= LOOKUP_REVAL;
 
-       error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
+       error = filename_lookup(dfd, name, LOOKUP_PARENT|lookup_flags, &nd);
        if (error)
                return ERR_PTR(error);
 
@@ -3359,6 +3383,19 @@ out:
        path_put(&nd.path);
        return dentry;
 }
+
+struct dentry *kern_path_create(int dfd, const char *pathname,
+                               struct path *path, unsigned int lookup_flags)
+{
+       struct filename *filename = getname_kernel(pathname);
+       struct dentry *res;
+
+       if (IS_ERR(filename))
+               return ERR_CAST(filename);
+       res = filename_create(dfd, filename, path, lookup_flags);
+       putname(filename);
+       return res;
+}
 EXPORT_SYMBOL(kern_path_create);
 
 void done_path_create(struct path *path, struct dentry *dentry)
@@ -3377,7 +3414,7 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp->name, path, lookup_flags);
+       res = filename_create(dfd, tmp, path, lookup_flags);
        putname(tmp);
        return res;
 }
index a293c2020676720e9da43c42d858cc5d73a41674..33f9cbf2610b39498d416cb8c142fb5ebe4cc790 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -968,8 +968,14 @@ struct file *file_open_name(struct filename *name, int flags, umode_t mode)
  */
 struct file *filp_open(const char *filename, int flags, umode_t mode)
 {
-       struct filename name = {.name = filename};
-       return file_open_name(&name, flags, mode);
+       struct filename *name = getname_kernel(filename);
+       struct file *file = ERR_CAST(name);
+       
+       if (!IS_ERR(name)) {
+               file = file_open_name(name, flags, mode);
+               putname(name);
+       }
+       return file;
 }
 EXPORT_SYMBOL(filp_open);
 
index 599f3bd2d6c5a43bde45fcb8dc4ec38b1275ebe7..c2e7e3a83965341207b64dab360a72b9cce780a6 100644 (file)
@@ -127,7 +127,6 @@ extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1,
 extern void __audit_syscall_exit(int ret_success, long ret_value);
 extern struct filename *__audit_reusename(const __user char *uptr);
 extern void __audit_getname(struct filename *name);
-extern void audit_putname(struct filename *name);
 
 #define AUDIT_INODE_PARENT     1       /* dentry represents the parent */
 #define AUDIT_INODE_HIDDEN     2       /* audit record should be hidden */
@@ -352,8 +351,6 @@ static inline struct filename *audit_reusename(const __user char *name)
 }
 static inline void audit_getname(struct filename *name)
 { }
-static inline void audit_putname(struct filename *name)
-{ }
 static inline void __audit_inode(struct filename *name,
                                        const struct dentry *dentry,
                                        unsigned int flags)
index ed5a0900b94d49989b9eb0fdff8db935fabc66a9..a9250b2a11ba89b4fd2e4a8d533a7b805e7bf25c 100644 (file)
@@ -2141,6 +2141,7 @@ struct filename {
        const char              *name;  /* pointer to actual string */
        const __user char       *uptr;  /* original userland pointer */
        struct audit_names      *aname;
+       int                     refcnt;
        bool                    separate; /* should "name" be freed? */
 };
 
@@ -2162,6 +2163,7 @@ extern int filp_close(struct file *, fl_owner_t id);
 extern struct filename *getname_flags(const char __user *, int, int *);
 extern struct filename *getname(const char __user *);
 extern struct filename *getname_kernel(const char *);
+extern void putname(struct filename *name);
 
 enum {
        FILE_CREATED = 1,
@@ -2182,15 +2184,8 @@ extern void __init vfs_caches_init(unsigned long);
 
 extern struct kmem_cache *names_cachep;
 
-extern void final_putname(struct filename *name);
-
 #define __getname()            kmem_cache_alloc(names_cachep, GFP_KERNEL)
 #define __putname(name)                kmem_cache_free(names_cachep, (void *)(name))
-#ifndef CONFIG_AUDITSYSCALL
-#define putname(name)          final_putname(name)
-#else
-extern void putname(struct filename *name);
-#endif
 
 #ifdef CONFIG_BLOCK
 extern int register_blkdev(unsigned int, const char *);
index 3cdffad5a1d9fb941823af4fc981aa587b342828..1caa0d345d90613f955578dacaa7082d9fac5163 100644 (file)
 #include <linux/skbuff.h>
 #include <uapi/linux/mqueue.h>
 
-/* 0 = no checking
-   1 = put_count checking
-   2 = verbose put_count checking
-*/
-#define AUDIT_DEBUG 0
-
 /* AUDIT_NAMES is the number of slots we reserve in the audit_context
  * for saving names from getname().  If we get more names we will allocate
  * a name dynamically and also add those to the list anchored by names_list. */
@@ -74,9 +68,8 @@ struct audit_cap_data {
        };
 };
 
-/* When fs/namei.c:getname() is called, we store the pointer in name and
- * we don't let putname() free it (instead we free all of the saved
- * pointers at syscall exit time).
+/* When fs/namei.c:getname() is called, we store the pointer in name and bump
+ * the refcnt in the associated filename struct.
  *
  * Further, in fs/namei.c:path_lookup() we store the inode and device.
  */
@@ -86,7 +79,6 @@ struct audit_names {
        struct filename         *name;
        int                     name_len;       /* number of chars to log */
        bool                    hidden;         /* don't log this record */
-       bool                    name_put;       /* call __putname()? */
 
        unsigned long           ino;
        dev_t                   dev;
@@ -208,11 +200,6 @@ struct audit_context {
        };
        int fds[2];
        struct audit_proctitle proctitle;
-
-#if AUDIT_DEBUG
-       int                 put_count;
-       int                 ino_count;
-#endif
 };
 
 extern u32 audit_ever_enabled;
index 55f82fce2526cee574bda09f98909510fa3e3c48..dc4ae70a74133eabbd52e40e5271202ac28ca9a4 100644 (file)
@@ -866,33 +866,10 @@ static inline void audit_free_names(struct audit_context *context)
 {
        struct audit_names *n, *next;
 
-#if AUDIT_DEBUG == 2
-       if (context->put_count + context->ino_count != context->name_count) {
-               int i = 0;
-
-               pr_err("%s:%d(:%d): major=%d in_syscall=%d"
-                      " name_count=%d put_count=%d ino_count=%d"
-                      " [NOT freeing]\n", __FILE__, __LINE__,
-                      context->serial, context->major, context->in_syscall,
-                      context->name_count, context->put_count,
-                      context->ino_count);
-               list_for_each_entry(n, &context->names_list, list) {
-                       pr_err("names[%d] = %p = %s\n", i++, n->name,
-                              n->name->name ?: "(null)");
-               }
-               dump_stack();
-               return;
-       }
-#endif
-#if AUDIT_DEBUG
-       context->put_count  = 0;
-       context->ino_count  = 0;
-#endif
-
        list_for_each_entry_safe(n, next, &context->names_list, list) {
                list_del(&n->list);
-               if (n->name && n->name_put)
-                       final_putname(n->name);
+               if (n->name)
+                       putname(n->name);
                if (n->should_free)
                        kfree(n);
        }
@@ -1711,9 +1688,6 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
        list_add_tail(&aname->list, &context->names_list);
 
        context->name_count++;
-#if AUDIT_DEBUG
-       context->ino_count++;
-#endif
        return aname;
 }
 
@@ -1734,8 +1708,10 @@ __audit_reusename(const __user char *uptr)
        list_for_each_entry(n, &context->names_list, list) {
                if (!n->name)
                        continue;
-               if (n->name->uptr == uptr)
+               if (n->name->uptr == uptr) {
+                       n->name->refcnt++;
                        return n->name;
+               }
        }
        return NULL;
 }
@@ -1752,19 +1728,8 @@ void __audit_getname(struct filename *name)
        struct audit_context *context = current->audit_context;
        struct audit_names *n;
 
-       if (!context->in_syscall) {
-#if AUDIT_DEBUG == 2
-               pr_err("%s:%d(:%d): ignoring getname(%p)\n",
-                      __FILE__, __LINE__, context->serial, name);
-               dump_stack();
-#endif
+       if (!context->in_syscall)
                return;
-       }
-
-#if AUDIT_DEBUG
-       /* The filename _must_ have a populated ->name */
-       BUG_ON(!name->name);
-#endif
 
        n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
@@ -1772,56 +1737,13 @@ void __audit_getname(struct filename *name)
 
        n->name = name;
        n->name_len = AUDIT_NAME_FULL;
-       n->name_put = true;
        name->aname = n;
+       name->refcnt++;
 
        if (!context->pwd.dentry)
                get_fs_pwd(current->fs, &context->pwd);
 }
 
-/* audit_putname - intercept a putname request
- * @name: name to intercept and delay for putname
- *
- * If we have stored the name from getname in the audit context,
- * then we delay the putname until syscall exit.
- * Called from include/linux/fs.h:putname().
- */
-void audit_putname(struct filename *name)
-{
-       struct audit_context *context = current->audit_context;
-
-       BUG_ON(!context);
-       if (!name->aname || !context->in_syscall) {
-#if AUDIT_DEBUG == 2
-               pr_err("%s:%d(:%d): final_putname(%p)\n",
-                      __FILE__, __LINE__, context->serial, name);
-               if (context->name_count) {
-                       struct audit_names *n;
-                       int i = 0;
-
-                       list_for_each_entry(n, &context->names_list, list)
-                               pr_err("name[%d] = %p = %s\n", i++, n->name,
-                                      n->name->name ?: "(null)");
-                       }
-#endif
-               final_putname(name);
-       }
-#if AUDIT_DEBUG
-       else {
-               ++context->put_count;
-               if (context->put_count > context->name_count) {
-                       pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)"
-                              " name_count=%d put_count=%d\n",
-                              __FILE__, __LINE__,
-                              context->serial, context->major,
-                              context->in_syscall, name->name,
-                              context->name_count, context->put_count);
-                       dump_stack();
-               }
-       }
-#endif
-}
-
 /**
  * __audit_inode - store the inode and device from a lookup
  * @name: name being audited
@@ -1842,10 +1764,6 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        if (!name)
                goto out_alloc;
 
-#if AUDIT_DEBUG
-       /* The struct filename _must_ have a populated ->name */
-       BUG_ON(!name->name);
-#endif
        /*
         * If we have a pointer to an audit_names entry already, then we can
         * just use it directly if the type is correct.
@@ -1863,7 +1781,17 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        }
 
        list_for_each_entry_reverse(n, &context->names_list, list) {
-               if (!n->name || strcmp(n->name->name, name->name))
+               if (n->ino) {
+                       /* valid inode number, use that for the comparison */
+                       if (n->ino != inode->i_ino ||
+                           n->dev != inode->i_sb->s_dev)
+                               continue;
+               } else if (n->name) {
+                       /* inode number has not been set, check the name */
+                       if (strcmp(n->name->name, name->name))
+                               continue;
+               } else
+                       /* no inode and no name (?!) ... this is odd ... */
                        continue;
 
                /* match the correct record type */
@@ -1882,44 +1810,11 @@ out_alloc:
        n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
                return;
-       /* unfortunately, while we may have a path name to record with the
-        * inode, we can't always rely on the string lasting until the end of
-        * the syscall so we need to create our own copy, it may fail due to
-        * memory allocation issues, but we do our best */
        if (name) {
-               /* we can't use getname_kernel() due to size limits */
-               size_t len = strlen(name->name) + 1;
-               struct filename *new = __getname();
-
-               if (unlikely(!new))
-                       goto out;
-
-               if (len <= (PATH_MAX - sizeof(*new))) {
-                       new->name = (char *)(new) + sizeof(*new);
-                       new->separate = false;
-               } else if (len <= PATH_MAX) {
-                       /* this looks odd, but is due to final_putname() */
-                       struct filename *new2;
-
-                       new2 = kmalloc(sizeof(*new2), GFP_KERNEL);
-                       if (unlikely(!new2)) {
-                               __putname(new);
-                               goto out;
-                       }
-                       new2->name = (char *)new;
-                       new2->separate = true;
-                       new = new2;
-               } else {
-                       /* we should never get here, but let's be safe */
-                       __putname(new);
-                       goto out;
-               }
-               strlcpy((char *)new->name, name->name, len);
-               new->uptr = NULL;
-               new->aname = n;
-               n->name = new;
-               n->name_put = true;
+               n->name = name;
+               name->refcnt++;
        }
+
 out:
        if (parent) {
                n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
@@ -1970,11 +1865,16 @@ void __audit_inode_child(const struct inode *parent,
 
        /* look for a parent entry first */
        list_for_each_entry(n, &context->names_list, list) {
-               if (!n->name || n->type != AUDIT_TYPE_PARENT)
+               if (!n->name ||
+                   (n->type != AUDIT_TYPE_PARENT &&
+                    n->type != AUDIT_TYPE_UNKNOWN))
                        continue;
 
-               if (n->ino == parent->i_ino &&
-                   !audit_compare_dname_path(dname, n->name->name, n->name_len)) {
+               if (n->ino == parent->i_ino && n->dev == parent->i_sb->s_dev &&
+                   !audit_compare_dname_path(dname,
+                                             n->name->name, n->name_len)) {
+                       if (n->type == AUDIT_TYPE_UNKNOWN)
+                               n->type = AUDIT_TYPE_PARENT;
                        found_parent = n;
                        break;
                }
@@ -1983,11 +1883,8 @@ void __audit_inode_child(const struct inode *parent,
        /* is there a matching child entry? */
        list_for_each_entry(n, &context->names_list, list) {
                /* can only match entries that have a name */
-               if (!n->name || n->type != type)
-                       continue;
-
-               /* if we found a parent, make sure this one is a child of it */
-               if (found_parent && (n->name != found_parent->name))
+               if (!n->name ||
+                   (n->type != type && n->type != AUDIT_TYPE_UNKNOWN))
                        continue;
 
                if (!strcmp(dname, n->name->name) ||
@@ -1995,6 +1892,8 @@ void __audit_inode_child(const struct inode *parent,
                                                found_parent ?
                                                found_parent->name_len :
                                                AUDIT_NAME_FULL)) {
+                       if (n->type == AUDIT_TYPE_UNKNOWN)
+                               n->type = type;
                        found_child = n;
                        break;
                }
@@ -2019,10 +1918,10 @@ void __audit_inode_child(const struct inode *parent,
                if (found_parent) {
                        found_child->name = found_parent->name;
                        found_child->name_len = AUDIT_NAME_FULL;
-                       /* don't call __putname() */
-                       found_child->name_put = false;
+                       found_child->name->refcnt++;
                }
        }
+
        if (inode)
                audit_copy_inode(found_child, dentry, inode);
        else