lkml.org 
[lkml]   [2012]   [Jul]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v5 5/9] audit: set the name_len in audit_inode for parent lookups
    Date
    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.

    Signed-off-by: Jeff Layton <jlayton@redhat.com>
    ---
    fs/namei.c | 14 +++++++-------
    fs/open.c | 4 ++--
    fs/xattr.c | 8 ++++----
    include/linux/audit.h | 13 ++++++++-----
    ipc/mqueue.c | 8 ++++----
    kernel/audit.h | 1 +
    kernel/auditfilter.c | 30 ++++++++++++++++++++++++++++++
    kernel/auditsc.c | 41 +++++++++++++++++++++++++++++------------
    8 files changed, 85 insertions(+), 34 deletions(-)

    diff --git a/fs/namei.c b/fs/namei.c
    index 1077c2a..a19af74 100644
    --- a/fs/namei.c
    +++ b/fs/namei.c
    @@ -1857,7 +1857,7 @@ static int do_path_lookup(int dfd, const char *name,
    retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd);

    if (likely(!retval))
    - audit_inode(name, nd->path.dentry);
    + audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
    return retval;
    }

    @@ -2531,7 +2531,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);
    + audit_inode(pathname, nd->path.dentry, 0);
    if (open_flag & O_CREAT) {
    error = -EISDIR;
    goto out;
    @@ -2541,7 +2541,7 @@ static int do_last(struct nameidata *nd, struct path *path,
    error = complete_walk(nd);
    if (error)
    return error;
    - audit_inode(pathname, dir);
    + audit_inode(pathname, dir, 0);
    goto finish_open;
    }

    @@ -2570,7 +2570,7 @@ static int do_last(struct nameidata *nd, struct path *path,
    if (error)
    return error;

    - audit_inode(pathname, dir);
    + audit_inode(pathname, dir, 0);
    error = -EISDIR;
    /* trailing slashes? */
    if (nd->last.name[nd->last.len])
    @@ -2590,7 +2590,7 @@ retry_lookup:
    !S_ISREG(file->f_path.dentry->d_inode->i_mode))
    will_truncate = false;

    - audit_inode(pathname, file->f_path.dentry);
    + audit_inode(pathname, file->f_path.dentry, 0);
    goto opened;
    }

    @@ -2607,7 +2607,7 @@ retry_lookup:
    * create/update audit record if it already exists.
    */
    if (path->dentry->d_inode)
    - audit_inode(pathname, path->dentry);
    + audit_inode(pathname, path->dentry, 0);

    /*
    * If atomic_open() acquired write access it is dropped now due to
    @@ -2672,7 +2672,7 @@ finish_lookup:
    error = -ENOTDIR;
    if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
    goto out;
    - audit_inode(pathname, nd->path.dentry);
    + audit_inode(pathname, nd->path.dentry, 0);
    finish_open:
    if (!S_ISREG(nd->inode->i_mode))
    will_truncate = false;
    diff --git a/fs/open.c b/fs/open.c
    index 1e914b3..fea9b0e 100644
    --- a/fs/open.c
    +++ b/fs/open.c
    @@ -476,7 +476,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)

    file = fget(fd);
    if (file) {
    - audit_inode(NULL, file->f_path.dentry);
    + audit_inode(NULL, file->f_path.dentry, 0);
    err = chmod_common(&file->f_path, mode);
    fput(file);
    }
    @@ -589,7 +589,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
    if (error)
    goto out_fput;
    dentry = file->f_path.dentry;
    - audit_inode(NULL, dentry);
    + audit_inode(NULL, dentry, 0);
    error = chown_common(&file->f_path, user, group);
    mnt_drop_write_file(file);
    out_fput:
    diff --git a/fs/xattr.c b/fs/xattr.c
    index 1d7ac37..9d25532 100644
    --- a/fs/xattr.c
    +++ b/fs/xattr.c
    @@ -408,7 +408,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
    if (!f)
    return error;
    dentry = f->f_path.dentry;
    - audit_inode(NULL, dentry);
    + audit_inode(NULL, dentry, 0);
    error = mnt_want_write_file(f);
    if (!error) {
    error = setxattr(dentry, name, value, size, flags);
    @@ -494,7 +494,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
    f = fget_light(fd, &fput_needed);
    if (!f)
    return error;
    - audit_inode(NULL, f->f_path.dentry);
    + audit_inode(NULL, f->f_path.dentry, 0);
    error = getxattr(f->f_path.dentry, name, value, size);
    fput_light(f, fput_needed);
    return error;
    @@ -575,7 +575,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
    f = fget_light(fd, &fput_needed);
    if (!f)
    return error;
    - audit_inode(NULL, f->f_path.dentry);
    + audit_inode(NULL, f->f_path.dentry, 0);
    error = listxattr(f->f_path.dentry, list, size);
    fput_light(f, fput_needed);
    return error;
    @@ -646,7 +646,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
    if (!f)
    return error;
    dentry = f->f_path.dentry;
    - audit_inode(NULL, dentry);
    + audit_inode(NULL, dentry, 0);
    error = mnt_want_write_file(f);
    if (!error) {
    error = removexattr(dentry, name);
    diff --git a/include/linux/audit.h b/include/linux/audit.h
    index 7acbfc8..2fc6831 100644
    --- a/include/linux/audit.h
    +++ b/include/linux/audit.h
    @@ -453,6 +453,7 @@ extern int audit_classify_arch(int arch);
    /* audit_names->type values */
    #define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */
    #define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */
    +#define AUDIT_TYPE_PARENT 2 /* a parent audit record */

    #ifdef CONFIG_AUDITSYSCALL
    /* These are defined in auditsc.c */
    @@ -465,7 +466,8 @@ extern void __audit_syscall_entry(int arch,
    extern void __audit_syscall_exit(int ret_success, long ret_value);
    extern void __audit_getname(const char *name);
    extern void audit_putname(const char *name);
    -extern void __audit_inode(const char *name, const struct dentry *dentry);
    +extern void __audit_inode(const char *name, const struct dentry *dentry,
    + unsigned int parent);
    extern void __audit_inode_child(const struct inode *parent,
    const struct dentry *dentry);
    extern void __audit_seccomp(unsigned long syscall, long signr, int code);
    @@ -502,9 +504,10 @@ static inline void audit_getname(const char *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(const char *name, const struct dentry *dentry,
    + unsigned int parent) {
    if (unlikely(!audit_dummy_context()))
    - __audit_inode(name, dentry);
    + __audit_inode(name, dentry, parent);
    }
    static inline void audit_inode_child(const struct inode *parent,
    const struct dentry *dentry) {
    @@ -634,9 +637,9 @@ extern int audit_signals;
    #define audit_dummy_context() 1
    #define audit_getname(n) do { ; } while (0)
    #define audit_putname(n) do { ; } while (0)
    -#define __audit_inode(n,d) do { ; } while (0)
    +#define __audit_inode(n,d,p) do { ; } while (0)
    #define __audit_inode_child(p,d) do { ; } while (0)
    -#define audit_inode(n,d) do { (void)(d); } while (0)
    +#define audit_inode(n,d,p) do { (void)(d); } while (0)
    #define audit_inode_child(p,d) do { ; } while (0)
    #define audit_core_dumps(i) do { ; } while (0)
    #define audit_seccomp(i,s,c) do { ; } while (0)
    diff --git a/ipc/mqueue.c b/ipc/mqueue.c
    index f8e54f5..574218c 100644
    --- a/ipc/mqueue.c
    +++ b/ipc/mqueue.c
    @@ -813,7 +813,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, path.dentry);
    + audit_inode(name, path.dentry, 0);
    if (oflag & O_EXCL) {
    error = -EEXIST;
    goto out;
    @@ -829,7 +829,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
    error = -ENOENT;
    goto out;
    }
    - audit_inode(name, path.dentry);
    + audit_inode(name, path.dentry, 0);
    filp = do_open(&path, oflag);
    }

    @@ -984,7 +984,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
    goto out_fput;
    }
    info = MQUEUE_I(inode);
    - audit_inode(NULL, filp->f_path.dentry);
    + audit_inode(NULL, filp->f_path.dentry, 0);

    if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
    ret = -EBADF;
    @@ -1101,7 +1101,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
    goto out_fput;
    }
    info = MQUEUE_I(inode);
    - audit_inode(NULL, filp->f_path.dentry);
    + audit_inode(NULL, filp->f_path.dentry, 0);

    if (unlikely(!(filp->f_mode & FMODE_READ))) {
    ret = -EBADF;
    diff --git a/kernel/audit.h b/kernel/audit.h
    index 8167668..276ca88 100644
    --- a/kernel/audit.h
    +++ b/kernel/audit.h
    @@ -76,6 +76,7 @@ static inline int audit_hash_ino(u32 ino)

    extern int audit_match_class(int class, unsigned syscall);
    extern int audit_comparator(const u32 left, const u32 op, const u32 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 a6c3f1a..29b167b 100644
    --- a/kernel/auditfilter.c
    +++ b/kernel/auditfilter.c
    @@ -1198,6 +1198,36 @@ int audit_comparator(u32 left, u32 op, u32 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 21c4223..e9f8b60 100644
    --- a/kernel/auditsc.c
    +++ b/kernel/auditsc.c
    @@ -2149,13 +2149,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;
    @@ -2165,18 +2165,37 @@ void __audit_inode(const char *name, const struct dentry *dentry)
    return;

    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 || 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() */
    + /* 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;
    }

    /**
    @@ -2200,7 +2219,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;
    @@ -2214,8 +2232,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;
    }
    @@ -2228,7 +2245,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
    --
    1.7.11.2


    \
     
     \ /
      Last update: 2012-07-26 15:21    [W:0.044 / U:32.564 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site