audit: set the name_len in audit_inode for parent lookups
[linux-block.git] / kernel / auditsc.c
index 29e090cc0e46a45a415d133dd8977d5b1a839368..b87b28947acc7b76003a1c38a708829d08cfbe59 100644 (file)
@@ -120,6 +120,7 @@ struct audit_names {
        struct audit_cap_data fcap;
        unsigned int    fcap_ver;
        int             name_len;       /* number of name's characters to log */
+       unsigned char   type;           /* record type */
        bool            name_put;       /* call __putname() for this name */
        /*
         * This was an allocated audit_names and not from the array of
@@ -1151,7 +1152,6 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
        const struct cred *cred;
        char name[sizeof(tsk->comm)];
        struct mm_struct *mm = tsk->mm;
-       struct vm_area_struct *vma;
        char *tty;
 
        if (!ab)
@@ -1191,16 +1191,8 @@ void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk)
 
        if (mm) {
                down_read(&mm->mmap_sem);
-               vma = mm->mmap;
-               while (vma) {
-                       if ((vma->vm_flags & VM_EXECUTABLE) &&
-                           vma->vm_file) {
-                               audit_log_d_path(ab, " exe=",
-                                                &vma->vm_file->f_path);
-                               break;
-                       }
-                       vma = vma->vm_next;
-               }
+               if (mm->exe_file)
+                       audit_log_d_path(ab, " exe=", &mm->exe_file->f_path);
                up_read(&mm->mmap_sem);
        }
        audit_log_task_context(ab);
@@ -2004,7 +1996,8 @@ retry:
 #endif
 }
 
-static struct audit_names *audit_alloc_name(struct audit_context *context)
+static struct audit_names *audit_alloc_name(struct audit_context *context,
+                                               unsigned char type)
 {
        struct audit_names *aname;
 
@@ -2019,6 +2012,7 @@ static struct audit_names *audit_alloc_name(struct audit_context *context)
        }
 
        aname->ino = (unsigned long)-1;
+       aname->type = type;
        list_add_tail(&aname->list, &context->names_list);
 
        context->name_count++;
@@ -2049,7 +2043,7 @@ void __audit_getname(const char *name)
                return;
        }
 
-       n = audit_alloc_name(context);
+       n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
                return;
 
@@ -2141,13 +2135,13 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent
 }
 
 /**
- * audit_inode - store the inode and device from a lookup
+ * __audit_inode - store the inode and device from a lookup
  * @name: name being audited
  * @dentry: dentry being audited
- *
- * Called from fs/namei.c:path_lookup().
+ * @parent: does this dentry represent the parent?
  */
-void __audit_inode(const char *name, const struct dentry *dentry)
+void __audit_inode(const char *name, const struct dentry *dentry,
+                  unsigned int parent)
 {
        struct audit_context *context = current->audit_context;
        const struct inode *inode = dentry->d_inode;
@@ -2156,24 +2150,48 @@ void __audit_inode(const char *name, const struct dentry *dentry)
        if (!context->in_syscall)
                return;
 
+       if (!name)
+               goto out_alloc;
+
        list_for_each_entry_reverse(n, &context->names_list, list) {
-               if (n->name && (n->name == name))
-                       goto out;
+               /* does the name pointer match? */
+               if (n->name != name)
+                       continue;
+
+               /* match the correct record type */
+               if (parent) {
+                       if (n->type == AUDIT_TYPE_PARENT ||
+                           n->type == AUDIT_TYPE_UNKNOWN)
+                               goto out;
+               } else {
+                       if (n->type != AUDIT_TYPE_PARENT)
+                               goto out;
+               }
        }
 
-       /* unable to find the name from a previous getname() */
-       n = audit_alloc_name(context);
+out_alloc:
+       /* unable to find the name from a previous getname(). Allocate a new
+        * anonymous entry.
+        */
+       n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
        if (!n)
                return;
 out:
+       if (parent) {
+               n->name_len = n->name ? parent_len(n->name) : AUDIT_NAME_FULL;
+               n->type = AUDIT_TYPE_PARENT;
+       } else {
+               n->name_len = AUDIT_NAME_FULL;
+               n->type = AUDIT_TYPE_NORMAL;
+       }
        handle_path(dentry);
        audit_copy_inode(n, dentry, inode);
 }
 
 /**
- * audit_inode_child - collect inode info for created/removed objects
- * @dentry: dentry being audited
+ * __audit_inode_child - collect inode info for created/removed objects
  * @parent: inode of dentry parent
+ * @dentry: dentry being audited
  *
  * For syscalls that create or remove filesystem objects, audit_inode
  * can only collect information for the filesystem object's parent.
@@ -2183,15 +2201,14 @@ out:
  * must be hooked prior, in order to capture the target inode during
  * unsuccessful attempts.
  */
-void __audit_inode_child(const struct dentry *dentry,
-                        const struct inode *parent)
+void __audit_inode_child(const struct inode *parent,
+                        const struct dentry *dentry)
 {
        struct audit_context *context = current->audit_context;
        const char *found_parent = NULL, *found_child = NULL;
        const struct inode *inode = dentry->d_inode;
        const char *dname = dentry->d_name.name;
        struct audit_names *n;
-       int dirlen = 0;
 
        if (!context->in_syscall)
                return;
@@ -2205,8 +2222,7 @@ void __audit_inode_child(const struct dentry *dentry,
                        continue;
 
                if (n->ino == parent->i_ino &&
-                   !audit_compare_dname_path(dname, n->name, &dirlen)) {
-                       n->name_len = dirlen; /* update parent data in place */
+                   !audit_compare_dname_path(dname, n->name, NULL)) {
                        found_parent = n->name;
                        goto add_names;
                }
@@ -2219,11 +2235,12 @@ void __audit_inode_child(const struct dentry *dentry,
 
                /* strcmp() is the more likely scenario */
                if (!strcmp(dname, n->name) ||
-                    !audit_compare_dname_path(dname, n->name, &dirlen)) {
+                    !audit_compare_dname_path(dname, n->name, NULL)) {
                        if (inode)
-                               audit_copy_inode(n, NULL, inode);
+                               audit_copy_inode(n, dentry, inode);
                        else
                                n->ino = (unsigned long)-1;
+                       n->type = AUDIT_TYPE_NORMAL;
                        found_child = n->name;
                        goto add_names;
                }
@@ -2231,14 +2248,14 @@ void __audit_inode_child(const struct dentry *dentry,
 
 add_names:
        if (!found_parent) {
-               n = audit_alloc_name(context);
+               n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
                if (!n)
                        return;
                audit_copy_inode(n, NULL, parent);
        }
 
        if (!found_child) {
-               n = audit_alloc_name(context);
+               n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
                if (!n)
                        return;
 
@@ -2253,7 +2270,7 @@ add_names:
                }
 
                if (inode)
-                       audit_copy_inode(n, NULL, inode);
+                       audit_copy_inode(n, dentry, inode);
        }
 }
 EXPORT_SYMBOL_GPL(__audit_inode_child);