Places that call fcheck() to convert a file descriptor into a
struct file need to call the new .file_lookup LSM hook.  The
most important instances of this are in the fget() function,
but there are a few other direct users of fcheck().

If a new file descriptor is created from an existing file
descriptor, then any rights associated with the original FD
need to be propagated to the new FD.  The .file_install LSM
hook takes care of this, by potentially changing the struct
file that is about to be installed into the FD table.  This
affects accept(2) and openat(2); for the latter, the rights
associated with the dfd need to be propagated through the
code in fs/namei.c to allow this.

The path walking code in fs/namei.c is also modified to enable
the O_BENEATH_ONLY flag if the process is in capability mode,
or if the dfd is a Capsicum capability.

Signed-off-by: David Drysdale <drysd...@google.com>
---
 arch/powerpc/platforms/cell/spufs/coredump.c |   2 +
 fs/file.c                                    |   2 +-
 fs/locks.c                                   |   2 +
 fs/namei.c                                   | 217 ++++++++++++++++++++-------
 fs/notify/dnotify/dnotify.c                  |   2 +
 fs/proc/fd.c                                 |  16 +-
 net/socket.c                                 |  10 +-
 7 files changed, 192 insertions(+), 59 deletions(-)

diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c 
b/arch/powerpc/platforms/cell/spufs/coredump.c
index be6212ddbf06..589fad12c715 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -29,6 +29,7 @@
 #include <linux/syscalls.h>
 #include <linux/coredump.h>
 #include <linux/binfmts.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 
@@ -101,6 +102,7 @@ static struct spu_context *coredump_next_context(int *fd)
                return NULL;
        *fd = n - 1;
        file = fcheck(*fd);
+       file = security_file_lookup(file, NULL, NULL);
        return SPUFS_I(file_inode(file))->i_ctx;
 }
 
diff --git a/fs/file.c b/fs/file.c
index 562cc82ba442..5a784234fd3a 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -742,7 +742,7 @@ static struct file *unwrap_file(struct file *orig,
                return ERR_PTR(-EBADF);
        if (IS_ERR(orig))
                return orig;
-       f = orig;  /* TODO: pass to an LSM hook here */
+       f = security_file_lookup(orig, required_rights, actual_rights);
        if (f != orig && update_refcnt) {
                /* We're not returning the original, and the calling code
                 * has already incremented the refcount on it, we need to
diff --git a/fs/locks.c b/fs/locks.c
index 375fac3392b9..fd95ced5ced1 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2121,6 +2121,7 @@ again:
         */
        spin_lock(&current->files->file_lock);
        f = fcheck(fd);
+       f = security_file_lookup(f, NULL, NULL);
        spin_unlock(&current->files->file_lock);
        if (!error && f != filp && flock.l_type != F_UNLCK) {
                flock.l_type = F_UNLCK;
@@ -2255,6 +2256,7 @@ again:
         */
        spin_lock(&current->files->file_lock);
        f = fcheck(fd);
+       f = security_file_lookup(f, NULL, NULL);
        spin_unlock(&current->files->file_lock);
        if (!error && f != filp && flock.l_type != F_UNLCK) {
                flock.l_type = F_UNLCK;
diff --git a/fs/namei.c b/fs/namei.c
index c93f7993960e..001baf46b7a5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -34,6 +34,7 @@
 #include <linux/device_cgroup.h>
 #include <linux/fs_struct.h>
 #include <linux/posix_acl.h>
+#include <linux/capsicum.h>
 #include <asm/uaccess.h>
 
 #include "internal.h"
@@ -1750,7 +1751,7 @@ static int link_path_walk(const char *name, struct 
nameidata *nd,
 {
        struct path next;
        int err;
-       
+
        while (*name == '/') {
                if (flags & LOOKUP_BENEATH_ONLY) {
                        err = -EACCES;
@@ -1836,15 +1837,18 @@ exit:
        return err;
 }
 
-static int path_init(int dfd, const char *name, unsigned int flags,
-                    struct nameidata *nd, struct file **fp)
+static int path_init(int dfd, const char *name, unsigned int *flags,
+               struct nameidata *nd, struct file **fp,
+               const struct capsicum_rights **dfd_rights,
+               const struct capsicum_rights *rights)
 {
        int retval = 0;
 
        nd->last_type = LAST_ROOT; /* if there are only slashes... */
-       nd->flags = flags | LOOKUP_JUMPED;
+       nd->flags = (*flags) | LOOKUP_PARENT | LOOKUP_JUMPED;
        nd->depth = 0;
-       if (flags & LOOKUP_ROOT) {
+
+       if ((*flags) & LOOKUP_ROOT) {
                struct dentry *root = nd->root.dentry;
                struct inode *inode = root->d_inode;
                if (*name) {
@@ -1856,7 +1860,7 @@ static int path_init(int dfd, const char *name, unsigned 
int flags,
                }
                nd->path = nd->root;
                nd->inode = inode;
-               if (flags & LOOKUP_RCU) {
+               if ((*flags) & LOOKUP_RCU) {
                        rcu_read_lock();
                        nd->seq = 
__read_seqcount_begin(&nd->path.dentry->d_seq);
                        nd->m_seq = read_seqbegin(&mount_lock);
@@ -1870,9 +1874,11 @@ static int path_init(int dfd, const char *name, unsigned 
int flags,
 
        nd->m_seq = read_seqbegin(&mount_lock);
        if (*name=='/') {
-               if (flags & LOOKUP_BENEATH_ONLY)
+               if ((*flags) & LOOKUP_BENEATH_ONLY)
                        return -EACCES;
-               if (flags & LOOKUP_RCU) {
+               if (dfd_rights)
+                       *dfd_rights = NULL;
+               if ((*flags) & LOOKUP_RCU) {
                        rcu_read_lock();
                        set_root_rcu(nd);
                } else {
@@ -1881,7 +1887,9 @@ static int path_init(int dfd, const char *name, unsigned 
int flags,
                }
                nd->path = nd->root;
        } else if (dfd == AT_FDCWD) {
-               if (flags & LOOKUP_RCU) {
+               if (dfd_rights)
+                       *dfd_rights = NULL;
+               if ((*flags) & LOOKUP_RCU) {
                        struct fs_struct *fs = current->fs;
                        unsigned seq;
 
@@ -1897,11 +1905,13 @@ static int path_init(int dfd, const char *name, 
unsigned int flags,
                }
        } else {
                /* Caller must check execute permissions on the starting path 
component */
-               struct fd f = fdget_raw(dfd);
+               struct fd f = fdget_raw_rights(dfd, dfd_rights, rights);
                struct dentry *dentry;
 
-               if (!f.file)
-                       return -EBADF;
+               if (IS_ERR(f.file))
+                       return PTR_ERR(f.file);
+               if (!cap_rights_is_all(*dfd_rights))
+                       *flags |= LOOKUP_BENEATH_ONLY;
 
                dentry = f.file->f_path.dentry;
 
@@ -1913,7 +1923,7 @@ static int path_init(int dfd, const char *name, unsigned 
int flags,
                }
 
                nd->path = f.file->f_path;
-               if (flags & LOOKUP_RCU) {
+               if ((*flags) & LOOKUP_RCU) {
                        if (f.flags & FDPUT_FPUT)
                                *fp = f.file;
                        nd->seq = 
__read_seqcount_begin(&nd->path.dentry->d_seq);
@@ -1938,9 +1948,12 @@ static inline int lookup_last(struct nameidata *nd, 
struct path *path)
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
-static int path_lookupat(int dfd, const char *name,
-                               unsigned int flags, struct nameidata *nd)
+static int path_lookupat(int dfd,
+                        const char *name, unsigned int flags,
+                        struct nameidata *nd,
+                        const struct capsicum_rights *rights)
 {
+       const struct capsicum_rights *dfd_rights;
        struct file *base = NULL;
        struct path path;
        int err;
@@ -1959,7 +1972,7 @@ static int path_lookupat(int dfd, const char *name,
         * be handled by restarting a traditional ref-walk (which will always
         * be able to complete).
         */
-       err = path_init(dfd, name, flags | LOOKUP_PARENT, nd, &base);
+       err = path_init(dfd, name, &flags, nd, &base, &dfd_rights, rights);
 
        if (unlikely(err))
                return err;
@@ -2004,27 +2017,32 @@ static int path_lookupat(int dfd, const char *name,
        return err;
 }
 
-static int filename_lookup(int dfd, struct filename *name,
-                               unsigned int flags, struct nameidata *nd)
+static int filename_lookup(int dfd,
+                       struct filename *name, unsigned int flags,
+                       struct nameidata *nd,
+                       const struct capsicum_rights *rights)
 {
-       int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);
+       int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd,
+                                  rights);
        if (unlikely(retval == -ECHILD))
-               retval = path_lookupat(dfd, name->name, flags, nd);
+               retval = path_lookupat(dfd, name->name, flags, nd, rights);
        if (unlikely(retval == -ESTALE))
-               retval = path_lookupat(dfd, name->name,
-                                               flags | LOOKUP_REVAL, nd);
+               retval = path_lookupat(dfd, name->name, flags | LOOKUP_REVAL,
+                                      nd, rights);
 
        if (likely(!retval))
                audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
        return retval;
 }
 
-static int do_path_lookup(int dfd, const char *name,
-                               unsigned int flags, struct nameidata *nd)
+static int do_path_lookup(int dfd,
+                         const char *name, unsigned int flags,
+                         struct nameidata *nd,
+                         const struct capsicum_rights *rights)
 {
        struct filename filename = { .name = name };
 
-       return filename_lookup(dfd, &filename, flags, nd);
+       return filename_lookup(dfd, &filename, flags, nd, rights);
 }
 
 /* does lookup, returns the object with parent locked */
@@ -2032,7 +2050,8 @@ struct dentry *kern_path_locked(const char *name, struct 
path *path)
 {
        struct nameidata nd;
        struct dentry *d;
-       int err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd);
+       int err;
+       err = do_path_lookup(AT_FDCWD, name, LOOKUP_PARENT, &nd, NULL);
        if (err)
                return ERR_PTR(err);
        if (nd.last_type != LAST_NORM) {
@@ -2053,7 +2072,8 @@ struct dentry *kern_path_locked(const char *name, struct 
path *path)
 int kern_path(const char *name, unsigned int flags, struct path *path)
 {
        struct nameidata nd;
-       int res = do_path_lookup(AT_FDCWD, name, flags, &nd);
+       int res;
+       res = do_path_lookup(AT_FDCWD, name, flags, &nd, NULL);
        if (!res)
                *path = nd.path;
        return res;
@@ -2078,7 +2098,7 @@ int vfs_path_lookup(struct dentry *dentry, struct 
vfsmount *mnt,
        nd.root.mnt = mnt;
        BUG_ON(flags & LOOKUP_PARENT);
        /* the first argument of do_path_lookup() is ignored with LOOKUP_ROOT */
-       err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd);
+       err = do_path_lookup(AT_FDCWD, name, flags | LOOKUP_ROOT, &nd, NULL);
        if (!err)
                *path = nd.path;
        return err;
@@ -2161,8 +2181,7 @@ static int user_path_at_empty_rights(int dfd,
        if (!IS_ERR(tmp)) {
 
                BUG_ON(flags & LOOKUP_PARENT);
-
-               err = filename_lookup(dfd, tmp, flags, &nd);
+               err = filename_lookup(dfd, tmp, flags, &nd, rights);
                putname(tmp);
                if (!err)
                        *path = nd.path;
@@ -2211,7 +2230,7 @@ int _user_path_atr(int dfd,
  */
 static struct filename *
 user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
-                unsigned int flags)
+                unsigned int flags, const struct capsicum_rights *rights)
 {
        struct filename *s = getname(path);
        int error;
@@ -2222,7 +2241,7 @@ user_path_parent(int dfd, const char __user *path, struct 
nameidata *nd,
        if (IS_ERR(s))
                return s;
 
-       error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd);
+       error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd, rights);
        if (error) {
                putname(s);
                return ERR_PTR(error);
@@ -2338,9 +2357,11 @@ path_mountpoint(int dfd, const char *name, struct path 
*path, unsigned int flags
 {
        struct file *base = NULL;
        struct nameidata nd;
+       const struct capsicum_rights *dfd_rights;
        int err;
 
-       err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base);
+       err = path_init(dfd, name, &flags, &nd, &base,
+                       &dfd_rights, &lookup_rights);
        if (unlikely(err))
                return err;
 
@@ -3165,8 +3186,9 @@ static int do_tmpfile(int dfd, struct filename *pathname,
        static const struct qstr name = QSTR_INIT("/", 1);
        struct dentry *dentry, *child;
        struct inode *dir;
-       int error = path_lookupat(dfd, pathname->name,
-                                 flags | LOOKUP_DIRECTORY, nd);
+       int error;
+       error = path_lookupat(dfd, pathname->name, flags | LOOKUP_DIRECTORY, nd,
+                             &lookup_rights);
        if (unlikely(error))
                return error;
        error = mnt_want_write(nd->path.mnt);
@@ -3218,15 +3240,42 @@ out:
        return error;
 }
 
+static void openat_primary_rights(struct capsicum_rights *rights,
+                                 unsigned int flags)
+{
+       switch (flags & O_ACCMODE) {
+       case O_RDONLY:
+               cap_rights_set(rights, CAP_READ);
+               break;
+       case O_RDWR:
+               cap_rights_set(rights, CAP_READ);
+               /* FALLTHRU */
+       case O_WRONLY:
+               cap_rights_set(rights, CAP_WRITE);
+               if (!(flags & (O_APPEND | O_TRUNC)))
+                       cap_rights_set(rights, CAP_SEEK);
+               break;
+       }
+       if (flags & O_CREAT)
+               cap_rights_set(rights, CAP_CREATE);
+       if (flags & O_TRUNC)
+               cap_rights_set(rights, CAP_FTRUNCATE);
+       if (flags & (O_DSYNC|FASYNC))
+               cap_rights_set(rights, CAP_FSYNC);
+}
+
 static struct file *path_openat(int dfd, struct filename *pathname,
                struct nameidata *nd, const struct open_flags *op, int flags)
 {
+       struct capsicum_rights rights;
+       const struct capsicum_rights *dfd_rights;
        struct file *base = NULL;
        struct file *file;
        struct path path;
        int opened = 0;
        int error;
 
+       cap_rights_init(&rights, CAP_LOOKUP);
        file = get_empty_filp();
        if (IS_ERR(file))
                return file;
@@ -3238,7 +3287,9 @@ static struct file *path_openat(int dfd, struct filename 
*pathname,
                goto out;
        }
 
-       error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, 
&base);
+       openat_primary_rights(&rights, file->f_flags);
+       error = path_init(dfd, pathname->name, &flags, nd, &base,
+                         &dfd_rights, &rights);
        if (unlikely(error))
                goto out;
 
@@ -3268,6 +3319,16 @@ static struct file *path_openat(int dfd, struct filename 
*pathname,
                error = do_last(nd, &path, file, op, &opened, pathname);
                put_link(nd, &link, cookie);
        }
+       if (!error) {
+               struct file *install_file;
+               install_file = security_file_install(dfd_rights, file);
+               if (IS_ERR(install_file)) {
+                       error = PTR_ERR(install_file);
+                       goto out;
+               } else {
+                       file = install_file;
+               }
+       }
 out:
        if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT))
                path_put(&nd->root);
@@ -3326,8 +3387,12 @@ struct file *do_file_open_root(struct dentry *dentry, 
struct vfsmount *mnt,
        return file;
 }
 
-struct dentry *kern_path_create(int dfd, const char *pathname,
-                               struct path *path, unsigned int lookup_flags)
+static struct dentry *
+kern_path_create_rights(int dfd,
+                       const char *pathname,
+                       struct path *path,
+                       unsigned int lookup_flags,
+                       const struct capsicum_rights *rights)
 {
        struct dentry *dentry = ERR_PTR(-EEXIST);
        struct nameidata nd;
@@ -3341,7 +3406,8 @@ struct dentry *kern_path_create(int dfd, const char 
*pathname,
         */
        lookup_flags &= LOOKUP_REVAL;
 
-       error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd);
+       error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd,
+                              rights);
        if (error)
                return ERR_PTR(error);
 
@@ -3395,6 +3461,13 @@ out:
        path_put(&nd.path);
        return dentry;
 }
+
+struct dentry *kern_path_create(int dfd, const char *pathname,
+                               struct path *path, unsigned int lookup_flags)
+{
+       return kern_path_create_rights(dfd, pathname, path, lookup_flags,
+                                      &lookup_rights);
+}
 EXPORT_SYMBOL(kern_path_create);
 
 void done_path_create(struct path *path, struct dentry *dentry)
@@ -3406,17 +3479,29 @@ void done_path_create(struct path *path, struct dentry 
*dentry)
 }
 EXPORT_SYMBOL(done_path_create);
 
-struct dentry *user_path_create(int dfd, const char __user *pathname,
-                               struct path *path, unsigned int lookup_flags)
+static struct dentry *
+user_path_create_rights(int dfd,
+                       const char __user *pathname,
+                       struct path *path,
+                       unsigned int lookup_flags,
+                       const struct capsicum_rights *rights)
 {
        struct filename *tmp = getname(pathname);
        struct dentry *res;
        if (IS_ERR(tmp))
                return ERR_CAST(tmp);
-       res = kern_path_create(dfd, tmp->name, path, lookup_flags);
+       res = kern_path_create_rights(dfd, tmp->name, path, lookup_flags,
+                                     rights);
        putname(tmp);
        return res;
 }
+
+struct dentry *user_path_create(int dfd, const char __user *pathname,
+                               struct path *path, unsigned int lookup_flags)
+{
+       return user_path_create_rights(dfd, pathname, path, lookup_flags,
+                                      &lookup_rights);
+}
 EXPORT_SYMBOL(user_path_create);
 
 int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t 
dev)
@@ -3467,16 +3552,28 @@ static int may_mknod(umode_t mode)
 SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, 
mode,
                unsigned, dev)
 {
+       struct capsicum_rights rights;
        struct dentry *dentry;
        struct path path;
        int error;
        unsigned int lookup_flags = 0;
 
+       cap_rights_init(&rights, CAP_LOOKUP);
        error = may_mknod(mode);
        if (error)
                return error;
+
+       switch (mode & S_IFMT) {
+       case S_IFCHR: case S_IFBLK:
+               cap_rights_set(&rights, CAP_MKNODAT);
+               break;
+       case S_IFIFO:
+               cap_rights_set(&rights, CAP_MKFIFOAT);
+               break;
+       }
 retry:
-       dentry = user_path_create(dfd, filename, &path, lookup_flags);
+       dentry = user_path_create_rights(dfd, filename, &path, lookup_flags,
+                                        &rights);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3543,9 +3640,12 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, 
pathname, umode_t, mode)
        struct path path;
        int error;
        unsigned int lookup_flags = LOOKUP_DIRECTORY;
+       struct capsicum_rights rights;
+       cap_rights_init(&rights, CAP_LOOKUP, CAP_MKDIRAT);
 
 retry:
-       dentry = user_path_create(dfd, pathname, &path, lookup_flags);
+       dentry = user_path_create_rights(dfd, pathname, &path, lookup_flags,
+                                        &rights);
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
@@ -3636,9 +3736,11 @@ static long do_rmdir(int dfd, const char __user 
*pathname)
        struct filename *name;
        struct dentry *dentry;
        struct nameidata nd;
+       struct capsicum_rights rights;
        unsigned int lookup_flags = 0;
+       cap_rights_init(&rights, CAP_UNLINKAT);
 retry:
-       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags, &rights);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3763,8 +3865,10 @@ static long do_unlinkat(int dfd, const char __user 
*pathname)
        struct inode *inode = NULL;
        struct inode *delegated_inode = NULL;
        unsigned int lookup_flags = 0;
+       struct capsicum_rights rights;
+       cap_rights_init(&rights, CAP_UNLINKAT);
 retry:
-       name = user_path_parent(dfd, pathname, &nd, lookup_flags);
+       name = user_path_parent(dfd, pathname, &nd, lookup_flags, &rights);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -3870,12 +3974,15 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
        struct dentry *dentry;
        struct path path;
        unsigned int lookup_flags = 0;
+       struct capsicum_rights rights;
 
        from = getname(oldname);
        if (IS_ERR(from))
                return PTR_ERR(from);
+       cap_rights_init(&rights, CAP_SYMLINKAT);
 retry:
-       dentry = user_path_create(newdfd, newname, &path, lookup_flags);
+       dentry = user_path_create_rights(newdfd, newname, &path, lookup_flags,
+                                        &rights);
        error = PTR_ERR(dentry);
        if (IS_ERR(dentry))
                goto out_putname;
@@ -3986,6 +4093,7 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, 
oldname,
        struct dentry *new_dentry;
        struct path old_path, new_path;
        struct inode *delegated_inode = NULL;
+       struct capsicum_rights rights;
        int how = 0;
        int error;
 
@@ -4004,13 +4112,14 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user 
*, oldname,
 
        if (flags & AT_SYMLINK_FOLLOW)
                how |= LOOKUP_FOLLOW;
+       cap_rights_init(&rights, CAP_LINKAT);
 retry:
        error = user_path_at(olddfd, oldname, how, &old_path);
        if (error)
                return error;
 
-       new_dentry = user_path_create(newdfd, newname, &new_path,
-                                       (how & LOOKUP_REVAL));
+       new_dentry = user_path_create_rights(newdfd, newname, &new_path,
+                                            (how & LOOKUP_REVAL), &rights);
        error = PTR_ERR(new_dentry);
        if (IS_ERR(new_dentry))
                goto out;
@@ -4241,6 +4350,8 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user 
*, oldname,
        struct inode *delegated_inode = NULL;
        struct filename *from;
        struct filename *to;
+       struct capsicum_rights old_rights;
+       struct capsicum_rights new_rights;
        unsigned int lookup_flags = 0;
        bool should_retry = false;
        int error;
@@ -4251,14 +4362,18 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char 
__user *, oldname,
        if ((flags & RENAME_NOREPLACE) && (flags & RENAME_EXCHANGE))
                return -EINVAL;
 
+       cap_rights_init(&old_rights, CAP_RENAMEAT);
+       cap_rights_init(&new_rights, CAP_LINKAT);
 retry:
-       from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
+       from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags,
+                               &old_rights);
        if (IS_ERR(from)) {
                error = PTR_ERR(from);
                goto exit;
        }
 
-       to = user_path_parent(newdfd, newname, &newnd, lookup_flags);
+       to = user_path_parent(newdfd, newname, &newnd, lookup_flags,
+                             &new_rights);
        if (IS_ERR(to)) {
                error = PTR_ERR(to);
                goto exit1;
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index abc8cbcfe90e..33a269166b05 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/fdtable.h>
 #include <linux/fsnotify_backend.h>
+#include <linux/security.h>
 
 int dir_notify_enable __read_mostly = 1;
 
@@ -327,6 +328,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned 
long arg)
 
        rcu_read_lock();
        f = fcheck(fd);
+       f = security_file_lookup(f, NULL, NULL);
        rcu_read_unlock();
 
        /* if (f != filp) means that we lost a race and another task/thread
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 0788d093f5d8..d260dd1acdee 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -20,6 +20,7 @@ static int seq_show(struct seq_file *m, void *v)
        struct files_struct *files = NULL;
        int f_flags = 0, ret = -ENOENT;
        struct file *file = NULL;
+       struct file *underlying = NULL;
        struct task_struct *task;
 
        task = get_proc_task(m->private);
@@ -36,12 +37,13 @@ static int seq_show(struct seq_file *m, void *v)
                file = fcheck_files(files, fd);
                if (file) {
                        struct fdtable *fdt = files_fdtable(files);
-
-                       f_flags = file->f_flags;
+                       underlying = security_file_lookup(file, NULL, NULL);
+                       f_flags = underlying->f_flags;
                        if (close_on_exec(fd, fdt))
                                f_flags |= O_CLOEXEC;
 
                        get_file(file);
+                       get_file(underlying);
                        ret = 0;
                }
                spin_unlock(&files->file_lock);
@@ -50,10 +52,11 @@ static int seq_show(struct seq_file *m, void *v)
 
        if (!ret) {
                seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n",
-                          (long long)file->f_pos, f_flags,
-                          real_mount(file->f_path.mnt)->mnt_id);
+                          (long long)underlying->f_pos, f_flags,
+                          real_mount(underlying->f_path.mnt)->mnt_id);
                if (file->f_op->show_fdinfo)
                        ret = file->f_op->show_fdinfo(m, file);
+               fput(underlying);
                fput(file);
        }
 
@@ -95,7 +98,9 @@ static int tid_fd_revalidate(struct dentry *dentry, unsigned 
int flags)
                        rcu_read_lock();
                        file = fcheck_files(files, fd);
                        if (file) {
-                               unsigned f_mode = file->f_mode;
+                               unsigned f_mode;
+                               file = security_file_lookup(file, NULL, NULL);
+                               f_mode = file->f_mode;
 
                                rcu_read_unlock();
                                put_files_struct(files);
@@ -158,6 +163,7 @@ static int proc_fd_link(struct dentry *dentry, struct path 
*path)
                spin_lock(&files->file_lock);
                fd_file = fcheck_files(files, fd);
                if (fd_file) {
+                       fd_file = security_file_lookup(fd_file, NULL, NULL);
                        *path = fd_file->f_path;
                        path_get(&fd_file->f_path);
                        ret = 0;
diff --git a/net/socket.c b/net/socket.c
index dbc00f0b992a..f635dc3f9a3c 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1669,6 +1669,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user 
*, upeer_sockaddr,
 {
        struct socket *sock, *newsock;
        struct file *newfile;
+       struct file *installfile;
        int err, len, newfd, fput_needed;
        struct sockaddr_storage address;
        struct capsicum_rights rights;
@@ -1736,7 +1737,12 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user 
*, upeer_sockaddr,
 
        /* File flags are not inherited via accept() unlike another OSes. */
 
-       fd_install(newfd, newfile);
+       installfile = security_file_install(listen_rights, newfile);
+       if (IS_ERR(installfile)) {
+               err = PTR_ERR(installfile);
+               goto out_fd;
+       }
+       fd_install(newfd, installfile);
        err = newfd;
 
 out_put:
@@ -2115,7 +2121,7 @@ static int ___sys_sendmsg(struct socket *sock_noaddr, 
struct socket *sock_addr,
        }
        sock = (msg_sys->msg_name ? sock_addr : sock_noaddr);
        if (!sock)
-               return -EBADF;
+               return -ENOTCAPABLE;
 
        if (msg_sys->msg_iovlen > UIO_FASTIOV) {
                err = -EMSGSIZE;
-- 
2.0.0.526.g5318336

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to