commit 101b08479cf1b5baa0e7687281548ea351fa3a8b Author: Linus Torvalds Date: Mon Feb 3 13:47:08 2014 -0800 Make 'inode_permission()' take the dentry pointer too --- drivers/staging/lustre/lustre/llite/file.c | 6 ++-- .../staging/lustre/lustre/llite/llite_internal.h | 2 +- fs/afs/internal.h | 2 +- fs/afs/security.c | 2 +- fs/bad_inode.c | 2 +- fs/btrfs/inode.c | 2 +- fs/btrfs/ioctl.c | 16 +++++---- fs/ceph/inode.c | 2 +- fs/ceph/super.h | 2 +- fs/cifs/cifsfs.c | 2 +- fs/coda/coda_linux.h | 2 +- fs/coda/dir.c | 2 +- fs/coda/pioctl.c | 4 +-- fs/ecryptfs/inode.c | 4 +-- fs/exec.c | 2 +- fs/fuse/dir.c | 2 +- fs/gfs2/inode.c | 11 ++++-- fs/hostfs/hostfs_kern.c | 2 +- fs/internal.h | 1 - fs/kernfs/inode.c | 2 +- fs/kernfs/kernfs-internal.h | 2 +- fs/namei.c | 40 +++++++++++----------- fs/ncpfs/ioctl.c | 6 ++-- fs/nfs/dir.c | 2 +- fs/nfsd/nfsfh.c | 2 +- fs/nfsd/vfs.c | 4 +-- fs/nilfs2/inode.c | 2 +- fs/nilfs2/nilfs.h | 2 +- fs/notify/fanotify/fanotify_user.c | 2 +- fs/notify/inotify/inotify_user.c | 2 +- fs/ocfs2/file.c | 2 +- fs/ocfs2/file.h | 2 +- fs/ocfs2/refcounttree.c | 15 ++++---- fs/open.c | 14 ++++---- fs/proc/base.c | 2 +- fs/proc/fd.c | 2 +- fs/proc/fd.h | 2 +- fs/proc/proc_sysctl.c | 2 +- fs/reiserfs/xattr.c | 2 +- fs/reiserfs/xattr.h | 2 +- fs/udf/file.c | 2 +- fs/utimes.c | 2 +- fs/xattr.c | 12 +++---- include/linux/fs.h | 4 +-- include/linux/nfs_fs.h | 2 +- ipc/mqueue.c | 2 +- kernel/sys.c | 2 +- mm/memcontrol.c | 2 +- net/unix/af_unix.c | 2 +- virt/kvm/assigned-dev.c | 2 +- 50 files changed, 112 insertions(+), 99 deletions(-) diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index c12821aedc2f..7a2e5f9b2e1d 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -1951,8 +1951,8 @@ static int ll_swap_layouts(struct file *file1, struct file *file2, if (!S_ISREG(llss->inode2->i_mode)) GOTO(free, rc = -EINVAL); - if (inode_permission(llss->inode1, MAY_WRITE) || - inode_permission(llss->inode2, MAY_WRITE)) + if (inode_permission(file1->f_dentry, llss->inode1, MAY_WRITE) || + inode_permission(file2->f_dentry, llss->inode2, MAY_WRITE)) GOTO(free, rc = -EPERM); if (llss->inode2->i_sb != llss->inode1->i_sb) @@ -3079,7 +3079,7 @@ struct posix_acl * ll_get_acl(struct inode *inode, int type) } -int ll_inode_permission(struct inode *inode, int mask) +int ll_inode_permission(struct dentry *dentry, struct inode *inode, int mask) { int rc = 0; diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 7ee5c02783f9..b767e484dfe9 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -799,7 +799,7 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat); struct ll_file_data *ll_file_data_get(void); struct posix_acl * ll_get_acl(struct inode *inode, int type); -int ll_inode_permission(struct inode *inode, int mask); +int ll_inode_permission(struct dentry *dentry, struct inode *inode, int mask); int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file, int flags, struct lov_user_md *lum, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 6621f8008122..63a03b555fd3 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -626,7 +626,7 @@ extern void afs_clear_permits(struct afs_vnode *); extern void afs_cache_permit(struct afs_vnode *, struct key *, long); extern void afs_zap_permits(struct rcu_head *); extern struct key *afs_request_key(struct afs_cell *); -extern int afs_permission(struct inode *, int); +extern int afs_permission(struct dentry *, struct inode *, int); /* * server.c diff --git a/fs/afs/security.c b/fs/afs/security.c index 8d010422dc89..cc34a41bab04 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -285,7 +285,7 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, * - AFS ACLs are attached to directories only, and a file is controlled by its * parent directory's ACL */ -int afs_permission(struct inode *inode, int mask) +int afs_permission(struct dentry *dentry, struct inode *inode, int mask) { struct afs_vnode *vnode = AFS_FS_I(inode); afs_access_t uninitialized_var(access); diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 7c93953030fb..cf6181b12add 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -230,7 +230,7 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, return -EIO; } -static int bad_inode_permission(struct inode *inode, int mask) +static int bad_inode_permission(struct dentry *dentry, struct inode *inode, int mask) { return -EIO; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5c4ab9c18940..546a6872e841 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8817,7 +8817,7 @@ static int btrfs_set_page_dirty(struct page *page) return __set_page_dirty_nobuffers(page); } -static int btrfs_permission(struct inode *inode, int mask) +static int btrfs_permission(struct dentry *dentry, struct inode *inode, int mask) { struct btrfs_root *root = BTRFS_I(inode)->root; umode_t mode = inode->i_mode; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index b0134892dc70..d07fdc9b8c9e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -716,9 +716,10 @@ static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode) * nfs_async_unlink(). */ -static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) +static int btrfs_may_delete(struct dentry *parent, struct dentry *victim, int isdir) { int error; + struct inode *dir = parent->d_inode; if (!victim->d_inode) return -ENOENT; @@ -726,7 +727,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + error = inode_permission(parent, dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) @@ -750,13 +751,14 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) } /* copy of may_create in fs/namei.c() */ -static inline int btrfs_may_create(struct inode *dir, struct dentry *child) +static inline int btrfs_may_create(struct dentry *parent, struct dentry *child) { + struct inode *dir = parent->d_inode; if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); + return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC); } /* @@ -787,7 +789,7 @@ static noinline int btrfs_mksubvol(struct path *parent, if (dentry->d_inode) goto out_dput; - error = btrfs_may_create(dir, dentry); + error = btrfs_may_create(parent->dentry, dentry); if (error) goto out_dput; @@ -2213,13 +2215,13 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, if (root == dest) goto out_dput; - err = inode_permission(inode, MAY_WRITE | MAY_EXEC); + err = inode_permission(dentry, inode, MAY_WRITE | MAY_EXEC); if (err) goto out_dput; } /* check if subvolume may be deleted by a user */ - err = btrfs_may_delete(dir, dentry, 1); + err = btrfs_may_delete(parent, dentry, 1); if (err) goto out_dput; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 32d519d8a2e2..04db1774cb2d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1875,7 +1875,7 @@ int ceph_do_getattr(struct inode *inode, int mask) * Check inode permissions. We verify we have a valid value for * the AUTH cap, then call the generic handler. */ -int ceph_permission(struct inode *inode, int mask) +int ceph_permission(struct dentry *dentry, struct inode *inode, int mask) { int err; diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 19793b56d0a7..6215dc38b676 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -716,7 +716,7 @@ extern void ceph_queue_invalidate(struct inode *inode); extern void ceph_queue_writeback(struct inode *inode); extern int ceph_do_getattr(struct inode *inode, int mask); -extern int ceph_permission(struct inode *inode, int mask); +extern int ceph_permission(struct dentry *, struct inode *inode, int mask); extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 849f6132b327..ca304878ef7b 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -211,7 +211,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } -static int cifs_permission(struct inode *inode, int mask) +static int cifs_permission(struct dentry *dentry, struct inode *inode, int mask) { struct cifs_sb_info *cifs_sb; diff --git a/fs/coda/coda_linux.h b/fs/coda/coda_linux.h index e7550cb9fb74..be666ad53717 100644 --- a/fs/coda/coda_linux.h +++ b/fs/coda/coda_linux.h @@ -39,7 +39,7 @@ extern const struct file_operations coda_ioctl_operations; /* operations shared over more than one file */ int coda_open(struct inode *i, struct file *f); int coda_release(struct inode *i, struct file *f); -int coda_permission(struct inode *inode, int mask); +int coda_permission(struct dentry *dentry, struct inode *inode, int mask); int coda_revalidate_inode(struct inode *); int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); int coda_setattr(struct dentry *, struct iattr *); diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 5efbb5ee0adc..c3ce50ad725e 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -128,7 +128,7 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsig } -int coda_permission(struct inode *inode, int mask) +int coda_permission(struct dentry *dentry, struct inode *inode, int mask) { int error; diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 3f5de96bbb58..2b760b97fe9c 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -24,7 +24,7 @@ #include "coda_linux.h" /* pioctl ops */ -static int coda_ioctl_permission(struct inode *inode, int mask); +static int coda_ioctl_permission(struct dentry *dentry, struct inode *inode, int mask); static long coda_pioctl(struct file *filp, unsigned int cmd, unsigned long user_data); @@ -41,7 +41,7 @@ const struct file_operations coda_ioctl_operations = { }; /* the coda pioctl inode ops */ -static int coda_ioctl_permission(struct inode *inode, int mask) +static int coda_ioctl_permission(struct dentry *dentry, struct inode *inode, int mask) { return (mask & MAY_EXEC) ? -EACCES : 0; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index a7a823f980c5..f2dc516c626a 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -882,9 +882,9 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) } static int -ecryptfs_permission(struct inode *inode, int mask) +ecryptfs_permission(struct dentry *dentry, struct inode *inode, int mask) { - return inode_permission(ecryptfs_inode_to_lower(inode), mask); + return inode_permission(ecryptfs_dentry_to_lower(dentry), ecryptfs_inode_to_lower(inode), mask); } /** diff --git a/fs/exec.c b/fs/exec.c index e1529b4c79b1..3d86968c5ffb 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1100,7 +1100,7 @@ EXPORT_SYMBOL(flush_old_exec); void would_dump(struct linux_binprm *bprm, struct file *file) { - if (inode_permission(file_inode(file), MAY_READ) < 0) + if (inode_permission(file->f_path.dentry, file_inode(file), MAY_READ) < 0) bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; } EXPORT_SYMBOL(would_dump); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 1d1292c581c3..dbb7ae00e66b 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1095,7 +1095,7 @@ static int fuse_perm_getattr(struct inode *inode, int mask) * access request is sent. Execute permission is still checked * locally based on file mode. */ -static int fuse_permission(struct inode *inode, int mask) +static int fuse_permission(struct dentry *dentry, struct inode *inode, int mask) { struct fuse_conn *fc = get_fuse_conn(inode); bool refreshed = false; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5c524180c98e..79d162029cae 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1890,8 +1890,13 @@ out: return ret; } +static int gfs2_vfs_permission(struct dentry *dentry, struct inode *inode, int mask) +{ + return gfs2_permission(inode, mask); +} + const struct inode_operations gfs2_file_iops = { - .permission = gfs2_permission, + .permission = gfs2_vfs_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, @@ -1913,7 +1918,7 @@ const struct inode_operations gfs2_dir_iops = { .rmdir = gfs2_unlink, .mknod = gfs2_mknod, .rename = gfs2_rename, - .permission = gfs2_permission, + .permission = gfs2_vfs_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, @@ -1930,7 +1935,7 @@ const struct inode_operations gfs2_symlink_iops = { .readlink = generic_readlink, .follow_link = gfs2_follow_link, .put_link = kfree_put_link, - .permission = gfs2_permission, + .permission = gfs2_vfs_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, .setxattr = gfs2_setxattr, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index fe649d325b1f..ef1573189fd7 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -759,7 +759,7 @@ static int hostfs_rename(struct inode *from_ino, struct dentry *from, return err; } -static int hostfs_permission(struct inode *ino, int desired) +static int hostfs_permission(struct dentry *dentry, struct inode *ino, int desired) { char *name; int r = 0, w = 0, x = 0, err; diff --git a/fs/internal.h b/fs/internal.h index 465742407466..52108c8f3919 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -42,7 +42,6 @@ extern void __init chrdev_init(void); /* * namei.c */ -extern int __inode_permission(struct inode *, int); extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct path *); diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index e55126f85bd2..9f084fc16fcf 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -360,7 +360,7 @@ void kernfs_evict_inode(struct inode *inode) kernfs_put(kn); } -int kernfs_iop_permission(struct inode *inode, int mask) +int kernfs_iop_permission(struct dentry *dentry, struct inode *inode, int mask) { struct kernfs_node *kn; diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index eb536b76374a..f41ba12978a9 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -78,7 +78,7 @@ extern struct kmem_cache *kernfs_node_cache; */ struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn); void kernfs_evict_inode(struct inode *inode); -int kernfs_iop_permission(struct inode *inode, int mask); +int kernfs_iop_permission(struct dentry *dentry, struct inode *inode, int mask); int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr); int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); diff --git a/fs/namei.c b/fs/namei.c index 142741e1ac9e..a885b9322637 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -335,11 +335,11 @@ int generic_permission(struct inode *inode, int mask) * flag in inode->i_opflags, that says "this has not special * permission function, use the fast case". */ -static inline int do_inode_permission(struct inode *inode, int mask) +static inline int do_inode_permission(struct dentry *dentry, struct inode *inode, int mask) { if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { if (likely(inode->i_op->permission)) - return inode->i_op->permission(inode, mask); + return inode->i_op->permission(dentry, inode, mask); /* This gets set once for the inode lifetime */ spin_lock(&inode->i_lock); @@ -361,7 +361,7 @@ static inline int do_inode_permission(struct inode *inode, int mask) * This does not check for a read-only file system. You probably want * inode_permission(). */ -int __inode_permission(struct inode *inode, int mask) +static int __inode_permission(struct dentry *dentry, struct inode *inode, int mask) { int retval; @@ -373,7 +373,7 @@ int __inode_permission(struct inode *inode, int mask) return -EACCES; } - retval = do_inode_permission(inode, mask); + retval = do_inode_permission(dentry, inode, mask); if (retval) return retval; @@ -416,14 +416,14 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask) * * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. */ -int inode_permission(struct inode *inode, int mask) +int inode_permission(struct dentry *dentry, struct inode *inode, int mask) { int retval; retval = sb_permission(inode->i_sb, inode, mask); if (retval) return retval; - return __inode_permission(inode, mask); + return __inode_permission(dentry, inode, mask); } /** @@ -729,7 +729,7 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd) * * Otherwise returns true. */ -static bool safe_hardlink_source(struct inode *inode) +static bool safe_hardlink_source(struct dentry *dentry, struct inode *inode) { umode_t mode = inode->i_mode; @@ -746,7 +746,7 @@ static bool safe_hardlink_source(struct inode *inode) return false; /* Hardlinking to unreadable or unwritable sources is dangerous. */ - if (inode_permission(inode, MAY_READ | MAY_WRITE)) + if (inode_permission(dentry, inode, MAY_READ | MAY_WRITE)) return false; return true; @@ -778,7 +778,7 @@ static int may_linkat(struct path *link) /* Source inode owner (or CAP_FOWNER) can hardlink all they like, * otherwise, it must be a safe source. */ - if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(inode) || + if (uid_eq(cred->fsuid, inode->i_uid) || safe_hardlink_source(link->dentry, inode) || capable(CAP_FOWNER)) return 0; @@ -1442,13 +1442,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path) static inline int may_lookup(struct nameidata *nd) { if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); + int err = inode_permission(nd->path.dentry, nd->inode, MAY_EXEC|MAY_NOT_BLOCK); if (err != -ECHILD) return err; if (unlazy_walk(nd, NULL)) return -ECHILD; } - return inode_permission(nd->inode, MAY_EXEC); + return inode_permission(nd->path.dentry, nd->inode, MAY_EXEC); } static inline int handle_dots(struct nameidata *nd, int type) @@ -1792,7 +1792,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, if (*name) { if (!d_is_directory(root)) return -ENOTDIR; - retval = inode_permission(inode, MAY_EXEC); + retval = inode_permission(root, inode, MAY_EXEC); if (retval) return retval; } @@ -2078,7 +2078,7 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) return ERR_PTR(err); } - err = inode_permission(base->d_inode, MAY_EXEC); + err = inode_permission(base, base->d_inode, MAY_EXEC); if (err) return ERR_PTR(err); @@ -2378,7 +2378,7 @@ static int may_delete(struct dentry *parent, struct dentry *victim, bool isdir) BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); + error = inode_permission(parent, dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) @@ -2417,7 +2417,7 @@ static inline int may_create(struct dentry *parent, struct dentry *child) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); + return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC); } /* @@ -2514,7 +2514,7 @@ static int may_open(struct path *path, int acc_mode, int flag) break; } - error = inode_permission(inode, acc_mode); + error = inode_permission(dentry, inode, acc_mode); if (error) return error; @@ -2570,7 +2570,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode) if (error) return error; - error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); + error = inode_permission(dir->dentry, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); if (error) return error; @@ -3079,10 +3079,10 @@ static int do_tmpfile(int dfd, struct filename *pathname, if (unlikely(error)) goto out; /* we want directory to be writable */ - error = inode_permission(nd->inode, MAY_WRITE | MAY_EXEC); + dentry = nd->path.dentry; + error = inode_permission(dentry, nd->inode, MAY_WRITE | MAY_EXEC); if (error) goto out2; - dentry = nd->path.dentry; dir = dentry->d_inode; if (!dir->i_op->tmpfile) { error = -EOPNOTSUPP; @@ -4000,7 +4000,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, * we'll need to flip '..'. */ if (new_dir != old_dir) { - error = inode_permission(old_dentry->d_inode, MAY_WRITE); + error = inode_permission(old_dentry, old_dentry->d_inode, MAY_WRITE); if (error) return error; } diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 60426ccb3b65..1294ebb5b4ce 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -872,7 +872,8 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (ret) goto out; need_drop_write = 1; - ret = inode_permission(inode, MAY_WRITE); + // Why not just check f_mode & FMODE_WRITE? + ret = inode_permission(filp->f_path.dentry, inode, MAY_WRITE); if (ret) goto outDropWrite; break; @@ -884,7 +885,8 @@ long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case NCP_IOC_GETMOUNTUID64: case NCP_IOC_GETROOT: case NCP_IOC_SIGN_WANTED: - ret = inode_permission(inode, MAY_READ); + // Why not just check f_mode & FMODE_READ? + ret = inode_permission(filp->f_path.dentry, inode, MAY_READ); if (ret) goto out; break; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index be38b573495a..d13216693d1a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -2269,7 +2269,7 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) } EXPORT_SYMBOL_GPL(nfs_may_open); -int nfs_permission(struct inode *inode, int mask) +int nfs_permission(struct dentry *dentry, struct inode *inode, int mask) { struct rpc_cred *cred; int res = 0; diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3c37b160dcad..979be190080f 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -38,7 +38,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); - err = inode_permission(parent->d_inode, MAY_EXEC); + err = inode_permission(parent, parent->d_inode, MAY_EXEC); if (err < 0) { dput(parent); break; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6faef0e5e43b..f045c435d49a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2028,13 +2028,13 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, return 0; /* This assumes NFSD_MAY_{READ,WRITE,EXEC} == MAY_{READ,WRITE,EXEC} */ - err = inode_permission(inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); + err = inode_permission(dentry, inode, acc & (MAY_READ|MAY_WRITE|MAY_EXEC)); /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) - err = inode_permission(inode, MAY_EXEC); + err = inode_permission(dentry, inode, MAY_EXEC); return err? nfserrno(err) : 0; } diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 7e350c562e0e..5348b2f14395 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -850,7 +850,7 @@ out_err: return err; } -int nilfs_permission(struct inode *inode, int mask) +int nilfs_permission(struct dentry *dentry, struct inode *inode, int mask) { struct nilfs_root *root = NILFS_I(inode)->i_root; if ((mask & MAY_WRITE) && root && diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 9bc72dec3fa6..3d5abd228b8c 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -278,7 +278,7 @@ extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); extern int nilfs_setattr(struct dentry *, struct iattr *); extern void nilfs_write_failed(struct address_space *mapping, loff_t to); -int nilfs_permission(struct inode *inode, int mask); +int nilfs_permission(struct dentry *dentry, struct inode *inode, int mask); int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); extern int nilfs_inode_dirty(struct inode *); int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index b6175fa11bf8..5f151d788733 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -490,7 +490,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, } /* you can only watch an inode if you have read permissions on it */ - ret = inode_permission(path->dentry->d_inode, MAY_READ); + ret = inode_permission(path->dentry, path->dentry->d_inode, MAY_READ); if (ret) path_put(path); out: diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 497395c8274b..4c022eb266c7 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -338,7 +338,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns if (error) return error; /* you can only watch an inode if you have read permissions on it */ - error = inode_permission(path->dentry->d_inode, MAY_READ); + error = inode_permission(path->dentry, path->dentry->d_inode, MAY_READ); if (error) path_put(path); return error; diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index d77d71ead8d1..562d9d73433d 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1269,7 +1269,7 @@ bail: return err; } -int ocfs2_permission(struct inode *inode, int mask) +int ocfs2_permission(struct dentry *dentry, struct inode *inode, int mask) { int ret; diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 97bf761c9e7c..e2bdbcadd6f4 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h @@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh, int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); -int ocfs2_permission(struct inode *inode, int mask); +int ocfs2_permission(struct dentry *dentry, struct inode *inode, int mask); int ocfs2_should_update_atime(struct inode *inode, struct vfsmount *vfsmnt); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 6ba4bcbc4796..a5d429b65bef 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4350,13 +4350,15 @@ out: */ /* copied from may_create in VFS. */ -static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) +static inline int ocfs2_may_create(struct dentry *parent, struct dentry *child) { + struct inode *dir = parent->d_inode; + if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); + return inode_permission(parent, dir, MAY_WRITE | MAY_EXEC); } /** @@ -4367,16 +4369,17 @@ static inline int ocfs2_may_create(struct inode *dir, struct dentry *child) * @new_dentry: target dentry * @preserve: if true, preserve all file attributes */ -static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir, +static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct dentry *new_parent, struct dentry *new_dentry, bool preserve) { + struct inode *dir = new_parent->d_inode; struct inode *inode = old_dentry->d_inode; int error; if (!inode) return -ENOENT; - error = ocfs2_may_create(dir, new_dentry); + error = ocfs2_may_create(new_parent, new_dentry); if (error) return error; @@ -4410,7 +4413,7 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir, * file. */ if (!preserve) { - error = inode_permission(inode, MAY_READ); + error = inode_permission(old_dentry, inode, MAY_READ); if (error) return error; } @@ -4458,7 +4461,7 @@ int ocfs2_reflink_ioctl(struct inode *inode, } error = ocfs2_vfs_reflink(old_path.dentry, - new_path.dentry->d_inode, + new_path.dentry, new_dentry, preserve); out_dput: done_path_create(&new_path, new_dentry); diff --git a/fs/open.c b/fs/open.c index 4b3e1edf2fe4..788be4fb87f3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -65,10 +65,12 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, long vfs_truncate(struct path *path, loff_t length) { + struct dentry *dentry; struct inode *inode; long error; - inode = path->dentry->d_inode; + dentry = path->dentry; + inode = dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ if (S_ISDIR(inode->i_mode)) @@ -80,7 +82,7 @@ long vfs_truncate(struct path *path, loff_t length) if (error) goto out; - error = inode_permission(inode, MAY_WRITE); + error = inode_permission(dentry, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; @@ -344,7 +346,7 @@ retry: goto out_path_release; } - res = inode_permission(inode, mode | MAY_ACCESS); + res = inode_permission(path.dentry, inode, mode | MAY_ACCESS); /* SuS v2 requires we report a read only fs too */ if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) goto out_path_release; @@ -388,7 +390,7 @@ retry: if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission(path.dentry, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; @@ -420,7 +422,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) if (!S_ISDIR(inode->i_mode)) goto out_putf; - error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission(f.file->f_path.dentry, inode, MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: @@ -439,7 +441,7 @@ retry: if (error) goto out; - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); + error = inode_permission(path.dentry, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); if (error) goto dput_and_out; diff --git a/fs/proc/base.c b/fs/proc/base.c index 51507065263b..eb4752863442 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -596,7 +596,7 @@ static bool has_pid_permissions(struct pid_namespace *pid, } -static int proc_pid_permission(struct inode *inode, int mask) +static int proc_pid_permission(struct dentry *dentry, struct inode *inode, int mask) { struct pid_namespace *pid = inode->i_sb->s_fs_info; struct task_struct *task; diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 985ea881b5bc..026594d5c820 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -281,7 +281,7 @@ static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, * /proc/pid/fd needs a special permission handler so that a process can still * access /proc/self/fd after it has executed a setuid(). */ -int proc_fd_permission(struct inode *inode, int mask) +int proc_fd_permission(struct dentry *dentry, struct inode *inode, int mask) { int rv = generic_permission(inode, mask); if (rv == 0) diff --git a/fs/proc/fd.h b/fs/proc/fd.h index 7c047f256ae2..29a70c16fd67 100644 --- a/fs/proc/fd.h +++ b/fs/proc/fd.h @@ -9,7 +9,7 @@ extern const struct inode_operations proc_fd_inode_operations; extern const struct file_operations proc_fdinfo_operations; extern const struct inode_operations proc_fdinfo_inode_operations; -extern int proc_fd_permission(struct inode *inode, int mask); +extern int proc_fd_permission(struct dentry *dentry, struct inode *inode, int mask); static inline int proc_fd(struct inode *inode) { diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 71290463a1d3..afcf1e80ab97 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -680,7 +680,7 @@ static int proc_sys_readdir(struct file *file, struct dir_context *ctx) return 0; } -static int proc_sys_permission(struct inode *inode, int mask) +static int proc_sys_permission(struct dentry *dentry, struct inode *inode, int mask) { /* * sysctl entries that are not writeable, diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 5cdfbd638b5c..fbfed32cb2d7 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -930,7 +930,7 @@ static int xattr_mount_check(struct super_block *s) return 0; } -int reiserfs_permission(struct inode *inode, int mask) +int reiserfs_permission(struct dentry *dentry, struct inode *inode, int mask) { /* * We don't do permission checks on the internal objects. diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h index f59626c5d33b..8d29ed9a19d4 100644 --- a/fs/reiserfs/xattr.h +++ b/fs/reiserfs/xattr.h @@ -15,7 +15,7 @@ int reiserfs_xattr_init(struct super_block *sb, int mount_flags); int reiserfs_lookup_privroot(struct super_block *sb); int reiserfs_delete_xattrs(struct inode *inode); int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); -int reiserfs_permission(struct inode *inode, int mask); +int reiserfs_permission(struct dentry *dentry, struct inode *inode, int mask); #ifdef CONFIG_REISERFS_FS_XATTR #define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) diff --git a/fs/udf/file.c b/fs/udf/file.c index c02a27a19c6d..0da4aabe25d6 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -182,7 +182,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long old_block, new_block; int result = -EINVAL; - if (inode_permission(inode, MAY_READ) != 0) { + if (inode_permission(filp->f_path.dentry, inode, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; goto out; diff --git a/fs/utimes.c b/fs/utimes.c index aa138d64560a..b7f17db4f08c 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -97,7 +97,7 @@ static int utimes_common(struct path *path, struct timespec *times) goto mnt_drop_write_and_out; if (!inode_owner_or_capable(inode)) { - error = inode_permission(inode, MAY_WRITE); + error = inode_permission(path->dentry, inode, MAY_WRITE); if (error) goto mnt_drop_write_and_out; } diff --git a/fs/xattr.c b/fs/xattr.c index 3377dff18404..00575e033549 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -29,7 +29,7 @@ * because different namespaces have very different rules. */ static int -xattr_permission(struct inode *inode, const char *name, int mask) +xattr_permission(struct dentry *dentry, struct inode *inode, const char *name, int mask) { /* * We can never set or remove an extended attribute on a read-only @@ -70,7 +70,7 @@ xattr_permission(struct inode *inode, const char *name, int mask) return -EPERM; } - return inode_permission(inode, mask); + return inode_permission(dentry, inode, mask); } /** @@ -125,7 +125,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, struct inode *inode = dentry->d_inode; int error; - error = xattr_permission(inode, name, MAY_WRITE); + error = xattr_permission(dentry, inode, name, MAY_WRITE); if (error) return error; @@ -185,7 +185,7 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, char *value = *xattr_value; int error; - error = xattr_permission(inode, name, MAY_READ); + error = xattr_permission(dentry, inode, name, MAY_READ); if (error) return error; @@ -233,7 +233,7 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) struct inode *inode = dentry->d_inode; int error; - error = xattr_permission(inode, name, MAY_READ); + error = xattr_permission(dentry, inode, name, MAY_READ); if (error) return error; @@ -292,7 +292,7 @@ vfs_removexattr(struct dentry *dentry, const char *name) if (!inode->i_op->removexattr) return -EOPNOTSUPP; - error = xattr_permission(inode, name, MAY_WRITE); + error = xattr_permission(dentry, inode, name, MAY_WRITE); if (error) return error; diff --git a/include/linux/fs.h b/include/linux/fs.h index c9fd8fb28c92..2350d8b10c18 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1552,7 +1552,7 @@ struct file_operations { struct inode_operations { struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); void * (*follow_link) (struct dentry *, struct nameidata *); - int (*permission) (struct inode *, int); + int (*permission) (struct dentry *, struct inode *, int); struct posix_acl * (*get_acl)(struct inode *, int); int (*readlink) (struct dentry *, char __user *,int); @@ -2280,7 +2280,7 @@ extern void emergency_remount(void); extern sector_t bmap(struct inode *, sector_t); #endif extern int notify_change(struct dentry *, struct iattr *, struct inode **); -extern int inode_permission(struct inode *, int); +extern int inode_permission(struct dentry *, struct inode *, int); extern int generic_permission(struct inode *, int); static inline bool execute_ok(struct inode *inode) diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 0ae5807480f4..f0e056cbe19e 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -345,7 +345,7 @@ extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fa extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); extern void nfs_access_set_mask(struct nfs_access_entry *, u32); -extern int nfs_permission(struct inode *, int); +extern int nfs_permission(struct dentry *, struct inode *, int); extern int nfs_open(struct inode *, struct file *); extern int nfs_release(struct inode *, struct file *); extern int nfs_attribute_timeout(struct inode *inode); diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 9c254d1e077f..a1c751b5858e 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -770,7 +770,7 @@ static struct file *do_open(struct path *path, int oflag) if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) return ERR_PTR(-EINVAL); acc = oflag2acc[oflag & O_ACCMODE]; - if (inode_permission(path->dentry->d_inode, acc)) + if (inode_permission(path->dentry, path->dentry->d_inode, acc)) return ERR_PTR(-EACCES); return dentry_open(path, oflag, current_cred()); } diff --git a/kernel/sys.c b/kernel/sys.c index c0a58be780a4..7346f9240571 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1650,7 +1650,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC) goto exit; - err = inode_permission(inode, MAY_EXEC); + err = inode_permission(exe.file->f_path.dentry, inode, MAY_EXEC); if (err) goto exit; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 53385cd4e6f0..597648160d73 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -6147,7 +6147,7 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css, /* the process need read permission on control file */ /* AV: shouldn't we check that it's been opened for read instead? */ - ret = inode_permission(file_inode(cfile.file), MAY_READ); + ret = inode_permission(cfile.file->f_path.dentry, file_inode(cfile.file), MAY_READ); if (ret < 0) goto out_put_cfile; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 93371f7b9f86..9509fbf1d3df 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -785,7 +785,7 @@ static struct sock *unix_find_other(struct net *net, if (err) goto fail; inode = path.dentry->d_inode; - err = inode_permission(inode, MAY_WRITE); + err = inode_permission(path.dentry, inode, MAY_WRITE); if (err) goto put_fail; diff --git a/virt/kvm/assigned-dev.c b/virt/kvm/assigned-dev.c index 8db43701016f..c12024692c0d 100644 --- a/virt/kvm/assigned-dev.c +++ b/virt/kvm/assigned-dev.c @@ -639,7 +639,7 @@ static int probe_sysfs_permissions(struct pci_dev *dev) inode = path.dentry->d_inode; - r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS); + r = inode_permission(path.dentry, inode, MAY_READ | MAY_WRITE | MAY_ACCESS); path_put(&path); if (r) return r;