Merge branch 'upstream' of git://git.infradead.org/users/pcmoore/audit
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2014 22:52:18 +0000 (14:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Dec 2014 22:52:18 +0000 (14:52 -0800)
Pull audit fix from Paul Moore:
 "One audit patch to resolve a panic/oops when recording filenames in
  the audit log, see the mail archive link below.

  The fix isn't as nice as I would like, as it involves an allocate/copy
  of the filename, but it solves the problem and the overhead should
  only affect users who have configured audit rules involving file
  names.

  We'll revisit this issue with future kernels in an attempt to make
  this suck less, but in the meantime I think this fix should go into
  the next release of v3.19-rcX.

  [ https://marc.info/?t=141986927600001&r=1&w=2 ]"

* 'upstream' of git://git.infradead.org/users/pcmoore/audit:
  audit: create private file name copies when auditing inodes

1  2 
kernel/auditsc.c

diff --combined kernel/auditsc.c
@@@ -72,6 -72,8 +72,8 @@@
  #include <linux/fs_struct.h>
  #include <linux/compat.h>
  #include <linux/ctype.h>
+ #include <linux/string.h>
+ #include <uapi/linux/limits.h>
  
  #include "audit.h"
  
@@@ -1861,8 -1863,7 +1863,7 @@@ void __audit_inode(struct filename *nam
        }
  
        list_for_each_entry_reverse(n, &context->names_list, list) {
-               /* does the name pointer match? */
-               if (!n->name || n->name->name != name->name)
+               if (!n->name || strcmp(n->name->name, name->name))
                        continue;
  
                /* match the correct record type */
@@@ -1881,14 -1882,44 +1882,44 @@@ out_alloc
        n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
                return;
-       if (name)
-               /* since name is not NULL we know there is already a matching
-                * name record, see audit_getname(), so there must be a type
-                * mismatch; reuse the string path since the original name
-                * record will keep the string valid until we free it in
-                * audit_free_names() */
-               n->name = name;
+       /* 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;
+       }
  out:
        if (parent) {
                n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
        audit_copy_inode(n, dentry, inode);
  }
  
 +void __audit_file(const struct file *file)
 +{
 +      __audit_inode(NULL, file->f_path.dentry, 0);
 +}
 +
  /**
   * __audit_inode_child - collect inode info for created/removed objects
   * @parent: inode of dentry parent
@@@ -2384,7 -2410,7 +2415,7 @@@ int __audit_log_bprm_fcaps(struct linux
        ax->d.next = context->aux;
        context->aux = (void *)ax;
  
 -      dentry = dget(bprm->file->f_dentry);
 +      dentry = dget(bprm->file->f_path.dentry);
        get_vfs_caps_from_disk(dentry, &vcaps);
        dput(dentry);
  
   * @new: the new credentials
   * @old: the old (current) credentials
   *
 - * Record the aguments userspace sent to sys_capset for later printing by the
 + * Record the arguments userspace sent to sys_capset for later printing by the
   * audit system if applicable
   */
  void __audit_log_capset(const struct cred *new, const struct cred *old)