From adb5c2473d3f91526c79db972aafb20a56d3fbb3 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 10 Oct 2012 16:43:13 -0400 Subject: [PATCH] audit: make audit_inode take struct filename Keep a pointer to the audit_names "slot" in struct filename. Have all of the audit_inode callers pass a struct filename ponter to audit_inode instead of a string pointer. If the aname field is already populated, then we can skip walking the list altogether and just use it directly. Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- fs/namei.c | 16 +++++++--------- include/linux/audit.h | 10 ++++++---- include/linux/fs.h | 6 ++++-- ipc/mqueue.c | 4 ++-- kernel/auditsc.c | 25 +++++++++++++++++++++++-- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 6bbd8fdfb1f..80b162b142f 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1999,8 +1999,7 @@ static int filename_lookup(int dfd, struct filename *name, flags | LOOKUP_REVAL, nd); if (likely(!retval)) - audit_inode(name->name, nd->path.dentry, - flags & LOOKUP_PARENT); + audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT); return retval; } @@ -2674,7 +2673,6 @@ static int do_last(struct nameidata *nd, struct path *path, struct path save_parent = { .dentry = NULL, .mnt = NULL }; bool retried = false; int error; - const char *pathname = name->name; nd->flags &= ~LOOKUP_PARENT; nd->flags |= op->intent; @@ -2690,7 +2688,7 @@ static int do_last(struct nameidata *nd, struct path *path, error = complete_walk(nd); if (error) return error; - audit_inode(pathname, nd->path.dentry, 0); + audit_inode(name, nd->path.dentry, 0); if (open_flag & O_CREAT) { error = -EISDIR; goto out; @@ -2700,7 +2698,7 @@ static int do_last(struct nameidata *nd, struct path *path, error = complete_walk(nd); if (error) return error; - audit_inode(pathname, dir, 0); + audit_inode(name, dir, 0); goto finish_open; } @@ -2729,7 +2727,7 @@ static int do_last(struct nameidata *nd, struct path *path, if (error) return error; - audit_inode(pathname, dir, 0); + audit_inode(name, dir, 0); error = -EISDIR; /* trailing slashes? */ if (nd->last.name[nd->last.len]) @@ -2759,7 +2757,7 @@ retry_lookup: !S_ISREG(file->f_path.dentry->d_inode->i_mode)) will_truncate = false; - audit_inode(pathname, file->f_path.dentry, 0); + audit_inode(name, file->f_path.dentry, 0); goto opened; } @@ -2776,7 +2774,7 @@ retry_lookup: * create/update audit record if it already exists. */ if (path->dentry->d_inode) - audit_inode(pathname, path->dentry, 0); + audit_inode(name, path->dentry, 0); /* * If atomic_open() acquired write access it is dropped now due to @@ -2841,7 +2839,7 @@ finish_lookup: error = -ENOTDIR; if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup) goto out; - audit_inode(pathname, nd->path.dentry, 0); + audit_inode(name, nd->path.dentry, 0); finish_open: if (!S_ISREG(nd->inode->i_mode)) will_truncate = false; diff --git a/include/linux/audit.h b/include/linux/audit.h index d5d7952ab7d..e5884f950b4 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -474,7 +474,7 @@ 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); -extern void __audit_inode(const char *name, const struct dentry *dentry, +extern void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int parent); extern void __audit_inode_child(const struct inode *parent, const struct dentry *dentry, @@ -519,7 +519,7 @@ static inline void audit_getname(struct filename *name) if (unlikely(!audit_dummy_context())) __audit_getname(name); } -static inline void audit_inode(const char *name, const struct dentry *dentry, +static inline void audit_inode(struct filename *name, const struct dentry *dentry, unsigned int parent) { if (unlikely(!audit_dummy_context())) __audit_inode(name, dentry, parent); @@ -680,14 +680,16 @@ static inline void audit_getname(struct filename *name) { } static inline void audit_putname(struct filename *name) { } -static inline void __audit_inode(const char *name, const struct dentry *dentry, +static inline void __audit_inode(struct filename *name, + const struct dentry *dentry, unsigned int parent) { } static inline void __audit_inode_child(const struct inode *parent, const struct dentry *dentry, const unsigned char type) { } -static inline void audit_inode(const char *name, const struct dentry *dentry, +static inline void audit_inode(struct filename *name, + const struct dentry *dentry, unsigned int parent) { } static inline void audit_inode_child(const struct inode *parent, diff --git a/include/linux/fs.h b/include/linux/fs.h index b6b10e7f0ac..4aa7160a51c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2196,9 +2196,11 @@ static inline int break_lease(struct inode *inode, unsigned int mode) #endif /* CONFIG_FILE_LOCKING */ /* fs/open.c */ +struct audit_names; struct filename { - const char *name; /* pointer to actual string */ - const __user char *uptr; /* original userland pointer */ + const char *name; /* pointer to actual string */ + const __user char *uptr; /* original userland pointer */ + struct audit_names *aname; }; extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6c5d9dcc903..71a3ca18c87 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -804,7 +804,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, if (oflag & O_CREAT) { if (path.dentry->d_inode) { /* entry already exists */ - audit_inode(name->name, path.dentry, 0); + audit_inode(name, path.dentry, 0); if (oflag & O_EXCL) { error = -EEXIST; goto out; @@ -824,7 +824,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, error = -ENOENT; goto out; } - audit_inode(name->name, path.dentry, 0); + audit_inode(name, path.dentry, 0); filp = do_open(&path, oflag); } diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 521163a5d65..2f186ed80c4 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -2076,6 +2076,7 @@ void __audit_getname(struct filename *name) n->name = name; n->name_len = AUDIT_NAME_FULL; n->name_put = true; + name->aname = n; if (!context->pwd.dentry) get_fs_pwd(current->fs, &context->pwd); @@ -2166,7 +2167,7 @@ static void audit_copy_inode(struct audit_names *name, const struct dentry *dent * @dentry: dentry being audited * @parent: does this dentry represent the parent? */ -void __audit_inode(const char *name, const struct dentry *dentry, +void __audit_inode(struct filename *name, const struct dentry *dentry, unsigned int parent) { struct audit_context *context = current->audit_context; @@ -2179,9 +2180,29 @@ void __audit_inode(const char *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. + */ + n = name->aname; + if (n) { + if (parent) { + if (n->type == AUDIT_TYPE_PARENT || + n->type == AUDIT_TYPE_UNKNOWN) + goto out; + } else { + if (n->type != AUDIT_TYPE_PARENT) + goto out; + } + } + list_for_each_entry_reverse(n, &context->names_list, list) { /* does the name pointer match? */ - if (!n->name || n->name->name != name) + if (!n->name || n->name->name != name->name) continue; /* match the correct record type */