aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2012-10-10 15:25:23 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-12 00:32:01 -0400
commitbfcec7087458812f575d9022b2d151641f34ee84 (patch)
tree6c0f7dd3b016992da8d113ceeaae404c6abc03a1 /kernel
parent78e2e802a8519031e5858595070b39713e26340d (diff)
audit: set the name_len in audit_inode for parent lookups
Currently, this gets set mostly by happenstance when we call into audit_inode_child. While that might be a little more efficient, it seems wrong. If the syscall ends up failing before audit_inode_child ever gets called, then you'll have an audit_names record that shows the full path but has the parent inode info attached. Fix this by passing in a parent flag when we call audit_inode that gets set to the value of LOOKUP_PARENT. We can then fix up the pathname for the audit entry correctly from the get-go. While we're at it, clean up the no-op macro for audit_inode in the !CONFIG_AUDITSYSCALL case. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c30
-rw-r--r--kernel/auditsc.c41
3 files changed, 60 insertions, 12 deletions
diff --git a/kernel/audit.h b/kernel/audit.h
index 9eb3d79482b..163b9a5d944 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -78,6 +78,7 @@ extern int audit_match_class(int class, unsigned syscall);
extern int audit_comparator(const u32 left, const u32 op, const u32 right);
extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
+extern int parent_len(const char *path);
extern int audit_compare_dname_path(const char *dname, const char *path,
int *dirlen);
extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index c4bcdbaf4d4..71bb13598df 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -1298,6 +1298,36 @@ int audit_gid_comparator(kgid_t left, u32 op, kgid_t right)
}
}
+/**
+ * parent_len - find the length of the parent portion of a pathname
+ * @path: pathname of which to determine length
+ */
+int parent_len(const char *path)
+{
+ int plen;
+ const char *p;
+
+ plen = strlen(path);
+
+ if (plen == 0)
+ return plen;
+
+ /* disregard trailing slashes */
+ p = path + plen - 1;
+ while ((*p == '/') && (p > path))
+ p--;
+
+ /* walk backward until we find the next slash or hit beginning */
+ while ((*p != '/') && (p > path))
+ p--;
+
+ /* did we find a slash? Then increment to include it in path */
+ if (*p == '/')
+ p++;
+
+ return p - path;
+}
+
/* Compare given dentry name with last component in given path,
* return of 0 indicates a match. */
int audit_compare_dname_path(const char *dname, const char *path,
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 19b232f86d7..b87b28947ac 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2135,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;
@@ -2154,19 +2154,38 @@ void __audit_inode(const char *name, const struct dentry *dentry)
goto out_alloc;
list_for_each_entry_reverse(n, &context->names_list, list) {
- if (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;
+ }
}
out_alloc:
- /* unable to find the name from a previous getname() */
+ /* 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);
- n->type = AUDIT_TYPE_NORMAL;
}
/**
@@ -2190,7 +2209,6 @@ void __audit_inode_child(const struct inode *parent,
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;
@@ -2204,8 +2222,7 @@ void __audit_inode_child(const struct inode *parent,
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;
}
@@ -2218,7 +2235,7 @@ void __audit_inode_child(const struct inode *parent,
/* 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, dentry, inode);
else