Message ID | 1533135451-15439-1-git-send-email-jose.pekkarinen@canonical.com |
---|---|
State | New |
Headers | show |
Series | This change is based in: | expand |
On 08/01/18 16:57, José Pekkarinen wrote: > fs: Avoid premature clearing of capabilities(030b533c4fd) > Reviewed-by: Christoph Hellwig <hch@lst.de> > by: Jan Kara <jack@suse.cz> > > It's applied on: > > UBUNTU: Ubuntu-lts-3.19.0-82.90~14.04.1(ceea1114793f68). > Signed-off-by: Brad Figg <brad.figg@canonical.com> > > Currently, notify_change() clears capabilities or IMA attributes by > calling security_inode_killpriv() before calling into ->setattr. Thus it > happens before any other permission checks in inode_change_ok() and user > is thus allowed to trigger clearing of capabilities or IMA attributes > for any file he can look up e.g. by calling chown for that file. This is > unexpected and can lead to user DoSing a system. > > Fix the problem by calling security_inode_killpriv() at the end of > inode_change_ok() instead of from notify_change(). At that moment we are > sure user has permissions to do the requested change. > > References: CVE-2015-1350 > Signed-off-by: José Pekkarinen <jose.pekkarinen@canonical.com> > --- > fs/9p/vfs_inode.c | 2 +- > fs/9p/vfs_inode_dotl.c | 2 +- > fs/adfs/inode.c | 2 +- > fs/affs/inode.c | 2 +- > fs/attr.c | 23 ++++++++++++++++------- > fs/btrfs/inode.c | 2 +- > fs/ceph/inode.c | 2 +- > fs/cifs/inode.c | 4 ++-- > fs/ecryptfs/inode.c | 2 +- > fs/exofs/inode.c | 2 +- > fs/ext2/inode.c | 2 +- > fs/ext3/inode.c | 2 +- > fs/ext4/inode.c | 2 +- > fs/f2fs/file.c | 2 +- > fs/fat/file.c | 2 +- > fs/fuse/dir.c | 13 +++++++------ > fs/fuse/file.c | 3 ++- > fs/fuse/fuse_i.h | 2 +- > fs/gfs2/inode.c | 2 +- > fs/hfs/inode.c | 2 +- > fs/hfsplus/inode.c | 2 +- > fs/hostfs/hostfs_kern.c | 2 +- > fs/hpfs/inode.c | 2 +- > fs/hugetlbfs/inode.c | 2 +- > fs/jffs2/fs.c | 2 +- > fs/jfs/file.c | 2 +- > fs/kernfs/inode.c | 2 +- > fs/libfs.c | 2 +- > fs/logfs/file.c | 2 +- > fs/minix/file.c | 2 +- > fs/ncpfs/inode.c | 2 +- > fs/nfsd/vfs.c | 7 ++++--- > fs/nilfs2/inode.c | 2 +- > fs/ntfs/inode.c | 2 +- > fs/ocfs2/dlmfs/dlmfs.c | 2 +- > fs/ocfs2/file.c | 2 +- > fs/omfs/file.c | 2 +- > fs/proc/base.c | 2 +- > fs/proc/generic.c | 2 +- > fs/proc/proc_sysctl.c | 2 +- > fs/ramfs/file-nommu.c | 2 +- > fs/reiserfs/inode.c | 2 +- > fs/sysv/file.c | 2 +- > fs/ubifs/file.c | 2 +- > fs/udf/file.c | 2 +- > fs/ufs/truncate.c | 2 +- > fs/xfs/xfs_iops.c | 6 ++++-- > include/linux/fs.h | 2 +- > mm/shmem.c | 2 +- > 49 files changed, 78 insertions(+), 64 deletions(-) > > diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c > index 711d744..65fcb86 100644 > --- a/fs/9p/vfs_inode.c > +++ b/fs/9p/vfs_inode.c > @@ -1094,7 +1094,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) > struct p9_wstat wstat; > > p9_debug(P9_DEBUG_VFS, "\n"); > - retval = inode_change_ok(dentry->d_inode, iattr); > + retval = inode_change_ok(dentry, iattr); > if (retval) > return retval; > > diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c > index 1254c7b..961a5b7 100644 > --- a/fs/9p/vfs_inode_dotl.c > +++ b/fs/9p/vfs_inode_dotl.c > @@ -560,7 +560,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) > > p9_debug(P9_DEBUG_VFS, "\n"); > > - retval = inode_change_ok(inode, iattr); > + retval = inode_change_ok(dentry, iattr); > if (retval) > return retval; > > diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c > index b9acada..fceb187 100644 > --- a/fs/adfs/inode.c > +++ b/fs/adfs/inode.c > @@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr) > unsigned int ia_valid = attr->ia_valid; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > > /* > * we can't change the UID or GID of any file - > diff --git a/fs/affs/inode.c b/fs/affs/inode.c > index d0609a2..e929583 100644 > --- a/fs/affs/inode.c > +++ b/fs/affs/inode.c > @@ -219,7 +219,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) > > pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid); > > - error = inode_change_ok(inode,attr); > + error = inode_change_ok(dentry,attr); > if (error) > goto out; > > diff --git a/fs/attr.c b/fs/attr.c > index 6530ced..72ec99f 100644 > --- a/fs/attr.c > +++ b/fs/attr.c > @@ -28,8 +28,9 @@ > * Should be called as the first thing in ->setattr implementations, > * possibly after taking additional locks. > */ > -int inode_change_ok(const struct inode *inode, struct iattr *attr) > +int inode_change_ok(struct dentry *dentry, struct iattr *attr) > { > + struct inode *inode = d_inode(dentry); > unsigned int ia_valid = attr->ia_valid; > > /* > @@ -44,7 +45,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) > > /* If force is set do it anyway. */ > if (ia_valid & ATTR_FORCE) > - return 0; > + goto kill_priv; > > /* Make sure a caller can chown. */ > if ((ia_valid & ATTR_UID) && > @@ -77,6 +78,16 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) > return -EPERM; > } > > +kill_priv: > + /* User has permission for the change */ > + if (ia_valid & ATTR_KILL_PRIV) { > + int error; > + > + error = security_inode_killpriv(dentry); > + if (error) > + return error; > + } > + > return 0; > } > EXPORT_SYMBOL(inode_change_ok); > @@ -217,13 +228,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de > if (!(ia_valid & ATTR_MTIME_SET)) > attr->ia_mtime = now; > if (ia_valid & ATTR_KILL_PRIV) { > - attr->ia_valid &= ~ATTR_KILL_PRIV; > - ia_valid &= ~ATTR_KILL_PRIV; > error = security_inode_need_killpriv(dentry); > - if (error > 0) > - error = security_inode_killpriv(dentry); > - if (error) > + if (error < 0) > return error; > + if (error == 0) > + ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV; > } > > /* > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index 508a4ca..47d3999 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -4805,7 +4805,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) > if (btrfs_root_readonly(root)) > return -EROFS; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c > index f61a741..4003158 100644 > --- a/fs/ceph/inode.c > +++ b/fs/ceph/inode.c > @@ -1727,7 +1727,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) > if (ceph_snap(inode) != CEPH_NOSNAP) > return -EROFS; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err != 0) > return err; > > diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c > index 5772aa0..0e0766c 100644 > --- a/fs/cifs/inode.c > +++ b/fs/cifs/inode.c > @@ -2092,7 +2092,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) > attrs->ia_valid |= ATTR_FORCE; > > - rc = inode_change_ok(inode, attrs); > + rc = inode_change_ok(direntry, attrs); > if (rc < 0) > goto out; > > @@ -2233,7 +2233,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) > if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) > attrs->ia_valid |= ATTR_FORCE; > > - rc = inode_change_ok(inode, attrs); > + rc = inode_change_ok(direntry, attrs); > if (rc < 0) { > free_xid(xid); > return rc; > diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c > index 1686dc2..3cf2cdd 100644 > --- a/fs/ecryptfs/inode.c > +++ b/fs/ecryptfs/inode.c > @@ -943,7 +943,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) > } > mutex_unlock(&crypt_stat->cs_mutex); > > - rc = inode_change_ok(inode, ia); > + rc = inode_change_ok(dentry, ia); > if (rc) > goto out; > if (ia->ia_valid & ATTR_SIZE) { > diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c > index f1d3d4e..4bb7077 100644 > --- a/fs/exofs/inode.c > +++ b/fs/exofs/inode.c > @@ -1039,7 +1039,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr) > if (unlikely(error)) > return error; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (unlikely(error)) > return error; > > diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c > index 36d35c3..c75bbd4 100644 > --- a/fs/ext2/inode.c > +++ b/fs/ext2/inode.c > @@ -1547,7 +1547,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > return error; > > diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c > index 2c6ccc4..421b537 100644 > --- a/fs/ext3/inode.c > +++ b/fs/ext3/inode.c > @@ -3244,7 +3244,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) > int error, rc = 0; > const unsigned int ia_valid = attr->ia_valid; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index 77c8ce1..51ea725 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -4482,7 +4482,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) > int orphan = 0; > const unsigned int ia_valid = attr->ia_valid; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > index 3c27e0e..1ca06de 100644 > --- a/fs/f2fs/file.c > +++ b/fs/f2fs/file.c > @@ -600,7 +600,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) > struct f2fs_inode_info *fi = F2FS_I(inode); > int err; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > diff --git a/fs/fat/file.c b/fs/fat/file.c > index 8429c68..626f9d4 100644 > --- a/fs/fat/file.c > +++ b/fs/fat/file.c > @@ -394,7 +394,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) > attr->ia_valid &= ~TIMES_SET_FLAGS; > } > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > attr->ia_valid = ia_valid; > if (error) { > if (sbi->options.quiet) > diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c > index 08e7b1a..7b2a04c 100644 > --- a/fs/fuse/dir.c > +++ b/fs/fuse/dir.c > @@ -1602,9 +1602,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff) > * vmtruncate() doesn't allow for this case, so do the rlimit checking > * and the actual truncation by hand. > */ > -int fuse_do_setattr(struct inode *inode, struct iattr *attr, > +int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, > struct file *file) > { > + struct inode *inode = d_inode(dentry); > struct fuse_conn *fc = get_fuse_conn(inode); > struct fuse_inode *fi = get_fuse_inode(inode); > FUSE_ARGS(args); > @@ -1619,7 +1620,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, > if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) > attr->ia_valid |= ATTR_FORCE; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > @@ -1710,17 +1711,17 @@ error: > return err; > } > > -static int fuse_setattr(struct dentry *entry, struct iattr *attr) > +static int fuse_setattr(struct dentry *dentry, struct iattr *attr) > { > - struct inode *inode = entry->d_inode; > + struct inode *inode = dentry->d_inode; > > if (!fuse_allow_current_process(get_fuse_conn(inode))) > return -EACCES; > > if (attr->ia_valid & ATTR_FILE) > - return fuse_do_setattr(inode, attr, attr->ia_file); > + return fuse_do_setattr(dentry, attr, attr->ia_file); > else > - return fuse_do_setattr(inode, attr, NULL); > + return fuse_do_setattr(dentry, attr, NULL); > } > > static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, > diff --git a/fs/fuse/file.c b/fs/fuse/file.c > index 60788e9..dbcc12a 100644 > --- a/fs/fuse/file.c > +++ b/fs/fuse/file.c > @@ -2782,6 +2782,7 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc, > static void fuse_do_truncate(struct file *file) > { > struct inode *inode = file->f_mapping->host; > + struct dentry *dentry = inode->i_sb->s_root; > struct iattr attr; > > attr.ia_valid = ATTR_SIZE; > @@ -2790,7 +2791,7 @@ static void fuse_do_truncate(struct file *file) > attr.ia_file = file; > attr.ia_valid |= ATTR_FILE; > > - fuse_do_setattr(inode, &attr, file); > + fuse_do_setattr(dentry, &attr, file); > } > > static inline loff_t fuse_round_up(loff_t off) > diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h > index 1cdfb07..195c942 100644 > --- a/fs/fuse/fuse_i.h > +++ b/fs/fuse/fuse_i.h > @@ -903,7 +903,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos); > int fuse_flush_times(struct inode *inode, struct fuse_file *ff); > int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); > > -int fuse_do_setattr(struct inode *inode, struct iattr *attr, > +int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, > struct file *file); > > void fuse_set_initialized(struct fuse_conn *fc); > diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c > index 9054002..c7fb53e 100644 > --- a/fs/gfs2/inode.c > +++ b/fs/gfs2/inode.c > @@ -1760,7 +1760,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) > if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) > goto out; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > goto out; > > diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c > index d0929bc..9b42ee0 100644 > --- a/fs/hfs/inode.c > +++ b/fs/hfs/inode.c > @@ -604,7 +604,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) > struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); > int error; > > - error = inode_change_ok(inode, attr); /* basic permission checks */ > + error = inode_change_ok(dentry, attr); /* basic permission checks */ > if (error) > return error; > > diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c > index 0cf786f..a74ff43 100644 > --- a/fs/hfsplus/inode.c > +++ b/fs/hfsplus/inode.c > @@ -247,7 +247,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c > index 75967b7e..bbf633f 100644 > --- a/fs/hostfs/hostfs_kern.c > +++ b/fs/hostfs/hostfs_kern.c > @@ -802,7 +802,7 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr) > > int fd = HOSTFS_I(inode)->fd; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c > index 7ce4b74..8e6942e 100644 > --- a/fs/hpfs/inode.c > +++ b/fs/hpfs/inode.c > @@ -272,7 +272,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) > if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) > goto out_unlock; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > goto out_unlock; > > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c > index 5eba47f..a4ddc94 100644 > --- a/fs/hugetlbfs/inode.c > +++ b/fs/hugetlbfs/inode.c > @@ -429,7 +429,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) > > BUG_ON(!inode); > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c > index 601afd1..870ed4f 100644 > --- a/fs/jffs2/fs.c > +++ b/fs/jffs2/fs.c > @@ -193,7 +193,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) > struct inode *inode = dentry->d_inode; > int rc; > > - rc = inode_change_ok(inode, iattr); > + rc = inode_change_ok(dentry, iattr); > if (rc) > return rc; > > diff --git a/fs/jfs/file.c b/fs/jfs/file.c > index 33aa0cc..2ede547 100644 > --- a/fs/jfs/file.c > +++ b/fs/jfs/file.c > @@ -103,7 +103,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) > struct inode *inode = dentry->d_inode; > int rc; > > - rc = inode_change_ok(inode, iattr); > + rc = inode_change_ok(dentry, iattr); > if (rc) > return rc; > > diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c > index 5b8ab29..325234f 100644 > --- a/fs/kernfs/inode.c > +++ b/fs/kernfs/inode.c > @@ -131,7 +131,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) > return -EINVAL; > > mutex_lock(&kernfs_mutex); > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > goto out; > > diff --git a/fs/libfs.c b/fs/libfs.c > index 3a5deb3..5509af4 100644 > --- a/fs/libfs.c > +++ b/fs/libfs.c > @@ -371,7 +371,7 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > return error; > > diff --git a/fs/logfs/file.c b/fs/logfs/file.c > index 8538752..bf8b09d 100644 > --- a/fs/logfs/file.c > +++ b/fs/logfs/file.c > @@ -244,7 +244,7 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int err = 0; > > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > diff --git a/fs/minix/file.c b/fs/minix/file.c > index a967de0..57bd2a4 100644 > --- a/fs/minix/file.c > +++ b/fs/minix/file.c > @@ -28,7 +28,7 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c > index e31e589..35a6d37 100644 > --- a/fs/ncpfs/inode.c > +++ b/fs/ncpfs/inode.c > @@ -885,7 +885,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) > /* ageing the dentry to force validation */ > ncp_age_dentry(server, dentry); > > - result = inode_change_ok(inode, attr); > + result = inode_change_ok(dentry, attr); > if (result < 0) > goto out; > > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > index 5685c67..38e5b6a 100644 > --- a/fs/nfsd/vfs.c > +++ b/fs/nfsd/vfs.c > @@ -300,7 +300,7 @@ commit_metadata(struct svc_fh *fhp) > * NFS semantics and what Linux expects. > */ > static void > -nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) > +nfsd_sanitize_attrs(struct dentry *dentry, struct iattr *iap) > { > /* > * NFSv2 does not differentiate between "set-[ac]time-to-now" > @@ -313,6 +313,7 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) > * We only call inode_change_ok as the last test as technically > * it is not an interface that we should be using. > */ > + struct inode *inode = d_inode(dentry); > #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) > #define MAX_TOUCH_TIME_ERROR (30*60) > if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && > @@ -328,7 +329,7 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) > if (delta < 0) > delta = -delta; > if (delta < MAX_TOUCH_TIME_ERROR && > - inode_change_ok(inode, iap) != 0) { > + inode_change_ok(dentry, iap) != 0) { > /* > * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. > * This will cause notify_change to set these times > @@ -435,7 +436,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, > if (!iap->ia_valid) > goto out; > > - nfsd_sanitize_attrs(inode, iap); > + nfsd_sanitize_attrs(dentry, iap); > > /* > * The size case is special, it changes the file in addition to the > diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c > index 8b59695..0791dd4 100644 > --- a/fs/nilfs2/inode.c > +++ b/fs/nilfs2/inode.c > @@ -840,7 +840,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) > struct super_block *sb = inode->i_sb; > int err; > > - err = inode_change_ok(inode, iattr); > + err = inode_change_ok(dentry, iattr); > if (err) > return err; > > diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c > index 898b994..6d51746 100644 > --- a/fs/ntfs/inode.c > +++ b/fs/ntfs/inode.c > @@ -2894,7 +2894,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) > int err; > unsigned int ia_valid = attr->ia_valid; > > - err = inode_change_ok(vi, attr); > + err = inode_change_ok(dentry, attr); > if (err) > goto out; > /* We do not support NTFS ACLs yet. */ > diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c > index 57c40e3..4473e95 100644 > --- a/fs/ocfs2/dlmfs/dlmfs.c > +++ b/fs/ocfs2/dlmfs/dlmfs.c > @@ -211,7 +211,7 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > > attr->ia_valid &= ~ATTR_SIZE; > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c > index 7e5aa39..9067886 100644 > --- a/fs/ocfs2/file.c > +++ b/fs/ocfs2/file.c > @@ -1143,7 +1143,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) > if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) > return 0; > > - status = inode_change_ok(inode, attr); > + status = inode_change_ok(dentry, attr); > if (status) > return status; > > diff --git a/fs/omfs/file.c b/fs/omfs/file.c > index 902e885..db6314c 100644 > --- a/fs/omfs/file.c > +++ b/fs/omfs/file.c > @@ -351,7 +351,7 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/proc/base.c b/fs/proc/base.c > index d022159..7abfc57 100644 > --- a/fs/proc/base.c > +++ b/fs/proc/base.c > @@ -509,7 +509,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) > if (attr->ia_valid & ATTR_MODE) > return -EPERM; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/proc/generic.c b/fs/proc/generic.c > index aaabab4..5f24651 100644 > --- a/fs/proc/generic.c > +++ b/fs/proc/generic.c > @@ -105,7 +105,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) > struct proc_dir_entry *de = PDE(inode); > int error; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > return error; > > diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c > index 3f7dc3e..be5b366 100644 > --- a/fs/proc/proc_sysctl.c > +++ b/fs/proc/proc_sysctl.c > @@ -753,7 +753,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) > if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) > return -EPERM; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c > index bbafbde..daba062 100644 > --- a/fs/ramfs/file-nommu.c > +++ b/fs/ramfs/file-nommu.c > @@ -163,7 +163,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) > int ret = 0; > > /* POSIX UID/GID verification for setting inode attributes */ > - ret = inode_change_ok(inode, ia); > + ret = inode_change_ok(dentry, ia); > if (ret) > return ret; > > diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c > index a7eec98..80f5192 100644 > --- a/fs/reiserfs/inode.c > +++ b/fs/reiserfs/inode.c > @@ -3312,7 +3312,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) > unsigned int ia_valid; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/sysv/file.c b/fs/sysv/file.c > index b00811c..09099b5 100644 > --- a/fs/sysv/file.c > +++ b/fs/sysv/file.c > @@ -35,7 +35,7 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c > index 538519e..b663d11 100644 > --- a/fs/ubifs/file.c > +++ b/fs/ubifs/file.c > @@ -1262,7 +1262,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) > > dbg_gen("ino %lu, mode %#x, ia_valid %#x", > inode->i_ino, inode->i_mode, attr->ia_valid); > - err = inode_change_ok(inode, attr); > + err = inode_change_ok(dentry, attr); > if (err) > return err; > > diff --git a/fs/udf/file.c b/fs/udf/file.c > index 08f3555..e2a382e 100644 > --- a/fs/udf/file.c > +++ b/fs/udf/file.c > @@ -258,7 +258,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr) > struct inode *inode = dentry->d_inode; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c > index f04f89f..926ba19 100644 > --- a/fs/ufs/truncate.c > +++ b/fs/ufs/truncate.c > @@ -496,7 +496,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr) > unsigned int ia_valid = attr->ia_valid; > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c > index 17d057c..ea6af4f 100644 > --- a/fs/xfs/xfs_iops.c > +++ b/fs/xfs/xfs_iops.c > @@ -530,6 +530,7 @@ xfs_setattr_nonsize( > { > xfs_mount_t *mp = ip->i_mount; > struct inode *inode = VFS_I(ip); > + struct dentry *dentry = inode->i_sb->s_root; > int mask = iattr->ia_valid; > xfs_trans_t *tp; > int error; > @@ -548,7 +549,7 @@ xfs_setattr_nonsize( > if (XFS_FORCED_SHUTDOWN(mp)) > return -EIO; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > return error; > } > @@ -736,6 +737,7 @@ xfs_setattr_size( > { > struct xfs_mount *mp = ip->i_mount; > struct inode *inode = VFS_I(ip); > + struct dentry *dentry = inode->i_sb->s_root; > xfs_off_t oldsize, newsize; > struct xfs_trans *tp; > int error; > @@ -751,7 +753,7 @@ xfs_setattr_size( > if (XFS_FORCED_SHUTDOWN(mp)) > return -EIO; > > - error = inode_change_ok(inode, iattr); > + error = inode_change_ok(dentry, iattr); > if (error) > return error; > > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 92c88b8..d12c959 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -2690,7 +2690,7 @@ extern int buffer_migrate_page(struct address_space *, > #define buffer_migrate_page NULL > #endif > > -extern int inode_change_ok(const struct inode *, struct iattr *); > +extern int inode_change_ok(struct dentry *, struct iattr *); > extern int inode_newsize_ok(const struct inode *, loff_t offset); > extern void setattr_copy(struct inode *inode, const struct iattr *attr); > > diff --git a/mm/shmem.c b/mm/shmem.c > index 993e6ba..fc6cab1 100644 > --- a/mm/shmem.c > +++ b/mm/shmem.c > @@ -553,7 +553,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) > struct shmem_inode_info *info = SHMEM_I(inode); > int error; > > - error = inode_change_ok(inode, attr); > + error = inode_change_ok(dentry, attr); > if (error) > return error; > > I'm NAK'ing this patch because it has been resent. Thanks, Kleber
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 711d744..65fcb86 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1094,7 +1094,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) struct p9_wstat wstat; p9_debug(P9_DEBUG_VFS, "\n"); - retval = inode_change_ok(dentry->d_inode, iattr); + retval = inode_change_ok(dentry, iattr); if (retval) return retval; diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index 1254c7b..961a5b7 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -560,7 +560,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) p9_debug(P9_DEBUG_VFS, "\n"); - retval = inode_change_ok(inode, iattr); + retval = inode_change_ok(dentry, iattr); if (retval) return retval; diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index b9acada..fceb187 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -303,7 +303,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr) unsigned int ia_valid = attr->ia_valid; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); /* * we can't change the UID or GID of any file - diff --git a/fs/affs/inode.c b/fs/affs/inode.c index d0609a2..e929583 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -219,7 +219,7 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid); - error = inode_change_ok(inode,attr); + error = inode_change_ok(dentry,attr); if (error) goto out; diff --git a/fs/attr.c b/fs/attr.c index 6530ced..72ec99f 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -28,8 +28,9 @@ * Should be called as the first thing in ->setattr implementations, * possibly after taking additional locks. */ -int inode_change_ok(const struct inode *inode, struct iattr *attr) +int inode_change_ok(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = d_inode(dentry); unsigned int ia_valid = attr->ia_valid; /* @@ -44,7 +45,7 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) /* If force is set do it anyway. */ if (ia_valid & ATTR_FORCE) - return 0; + goto kill_priv; /* Make sure a caller can chown. */ if ((ia_valid & ATTR_UID) && @@ -77,6 +78,16 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) return -EPERM; } +kill_priv: + /* User has permission for the change */ + if (ia_valid & ATTR_KILL_PRIV) { + int error; + + error = security_inode_killpriv(dentry); + if (error) + return error; + } + return 0; } EXPORT_SYMBOL(inode_change_ok); @@ -217,13 +228,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de if (!(ia_valid & ATTR_MTIME_SET)) attr->ia_mtime = now; if (ia_valid & ATTR_KILL_PRIV) { - attr->ia_valid &= ~ATTR_KILL_PRIV; - ia_valid &= ~ATTR_KILL_PRIV; error = security_inode_need_killpriv(dentry); - if (error > 0) - error = security_inode_killpriv(dentry); - if (error) + if (error < 0) return error; + if (error == 0) + ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV; } /* diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 508a4ca..47d3999 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4805,7 +4805,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) if (btrfs_root_readonly(root)) return -EROFS; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index f61a741..4003158 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1727,7 +1727,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) if (ceph_snap(inode) != CEPH_NOSNAP) return -EROFS; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err != 0) return err; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 5772aa0..0e0766c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -2092,7 +2092,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) attrs->ia_valid |= ATTR_FORCE; - rc = inode_change_ok(inode, attrs); + rc = inode_change_ok(direntry, attrs); if (rc < 0) goto out; @@ -2233,7 +2233,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) attrs->ia_valid |= ATTR_FORCE; - rc = inode_change_ok(inode, attrs); + rc = inode_change_ok(direntry, attrs); if (rc < 0) { free_xid(xid); return rc; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 1686dc2..3cf2cdd 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -943,7 +943,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) } mutex_unlock(&crypt_stat->cs_mutex); - rc = inode_change_ok(inode, ia); + rc = inode_change_ok(dentry, ia); if (rc) goto out; if (ia->ia_valid & ATTR_SIZE) { diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index f1d3d4e..4bb7077 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -1039,7 +1039,7 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr) if (unlikely(error)) return error; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (unlikely(error)) return error; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 36d35c3..c75bbd4 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1547,7 +1547,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) return error; diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 2c6ccc4..421b537 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3244,7 +3244,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) int error, rc = 0; const unsigned int ia_valid = attr->ia_valid; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 77c8ce1..51ea725 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4482,7 +4482,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) int orphan = 0; const unsigned int ia_valid = attr->ia_valid; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 3c27e0e..1ca06de 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -600,7 +600,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) struct f2fs_inode_info *fi = F2FS_I(inode); int err; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; diff --git a/fs/fat/file.c b/fs/fat/file.c index 8429c68..626f9d4 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -394,7 +394,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~TIMES_SET_FLAGS; } - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); attr->ia_valid = ia_valid; if (error) { if (sbi->options.quiet) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 08e7b1a..7b2a04c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1602,9 +1602,10 @@ int fuse_flush_times(struct inode *inode, struct fuse_file *ff) * vmtruncate() doesn't allow for this case, so do the rlimit checking * and the actual truncation by hand. */ -int fuse_do_setattr(struct inode *inode, struct iattr *attr, +int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, struct file *file) { + struct inode *inode = d_inode(dentry); struct fuse_conn *fc = get_fuse_conn(inode); struct fuse_inode *fi = get_fuse_inode(inode); FUSE_ARGS(args); @@ -1619,7 +1620,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr, if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) attr->ia_valid |= ATTR_FORCE; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; @@ -1710,17 +1711,17 @@ error: return err; } -static int fuse_setattr(struct dentry *entry, struct iattr *attr) +static int fuse_setattr(struct dentry *dentry, struct iattr *attr) { - struct inode *inode = entry->d_inode; + struct inode *inode = dentry->d_inode; if (!fuse_allow_current_process(get_fuse_conn(inode))) return -EACCES; if (attr->ia_valid & ATTR_FILE) - return fuse_do_setattr(inode, attr, attr->ia_file); + return fuse_do_setattr(dentry, attr, attr->ia_file); else - return fuse_do_setattr(inode, attr, NULL); + return fuse_do_setattr(dentry, attr, NULL); } static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry, diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 60788e9..dbcc12a 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2782,6 +2782,7 @@ int fuse_notify_poll_wakeup(struct fuse_conn *fc, static void fuse_do_truncate(struct file *file) { struct inode *inode = file->f_mapping->host; + struct dentry *dentry = inode->i_sb->s_root; struct iattr attr; attr.ia_valid = ATTR_SIZE; @@ -2790,7 +2791,7 @@ static void fuse_do_truncate(struct file *file) attr.ia_file = file; attr.ia_valid |= ATTR_FILE; - fuse_do_setattr(inode, &attr, file); + fuse_do_setattr(dentry, &attr, file); } static inline loff_t fuse_round_up(loff_t off) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1cdfb07..195c942 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -903,7 +903,7 @@ bool fuse_write_update_size(struct inode *inode, loff_t pos); int fuse_flush_times(struct inode *inode, struct fuse_file *ff); int fuse_write_inode(struct inode *inode, struct writeback_control *wbc); -int fuse_do_setattr(struct inode *inode, struct iattr *attr, +int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, struct file *file); void fuse_set_initialized(struct fuse_conn *fc); diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 9054002..c7fb53e 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -1760,7 +1760,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr) if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) goto out; diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index d0929bc..9b42ee0 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -604,7 +604,7 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); int error; - error = inode_change_ok(inode, attr); /* basic permission checks */ + error = inode_change_ok(dentry, attr); /* basic permission checks */ if (error) return error; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 0cf786f..a74ff43 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -247,7 +247,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 75967b7e..bbf633f 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -802,7 +802,7 @@ static int hostfs_setattr(struct dentry *dentry, struct iattr *attr) int fd = HOSTFS_I(inode)->fd; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 7ce4b74..8e6942e 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -272,7 +272,7 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) goto out_unlock; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) goto out_unlock; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 5eba47f..a4ddc94 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -429,7 +429,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) BUG_ON(!inode); - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 601afd1..870ed4f 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -193,7 +193,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) struct inode *inode = dentry->d_inode; int rc; - rc = inode_change_ok(inode, iattr); + rc = inode_change_ok(dentry, iattr); if (rc) return rc; diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 33aa0cc..2ede547 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -103,7 +103,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) struct inode *inode = dentry->d_inode; int rc; - rc = inode_change_ok(inode, iattr); + rc = inode_change_ok(dentry, iattr); if (rc) return rc; diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 5b8ab29..325234f 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -131,7 +131,7 @@ int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) return -EINVAL; mutex_lock(&kernfs_mutex); - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) goto out; diff --git a/fs/libfs.c b/fs/libfs.c index 3a5deb3..5509af4 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -371,7 +371,7 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) return error; diff --git a/fs/logfs/file.c b/fs/logfs/file.c index 8538752..bf8b09d 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c @@ -244,7 +244,7 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int err = 0; - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; diff --git a/fs/minix/file.c b/fs/minix/file.c index a967de0..57bd2a4 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -28,7 +28,7 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index e31e589..35a6d37 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -885,7 +885,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) /* ageing the dentry to force validation */ ncp_age_dentry(server, dentry); - result = inode_change_ok(inode, attr); + result = inode_change_ok(dentry, attr); if (result < 0) goto out; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 5685c67..38e5b6a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -300,7 +300,7 @@ commit_metadata(struct svc_fh *fhp) * NFS semantics and what Linux expects. */ static void -nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) +nfsd_sanitize_attrs(struct dentry *dentry, struct iattr *iap) { /* * NFSv2 does not differentiate between "set-[ac]time-to-now" @@ -313,6 +313,7 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) * We only call inode_change_ok as the last test as technically * it is not an interface that we should be using. */ + struct inode *inode = d_inode(dentry); #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET) #define MAX_TOUCH_TIME_ERROR (30*60) if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET && @@ -328,7 +329,7 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) if (delta < 0) delta = -delta; if (delta < MAX_TOUCH_TIME_ERROR && - inode_change_ok(inode, iap) != 0) { + inode_change_ok(dentry, iap) != 0) { /* * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME. * This will cause notify_change to set these times @@ -435,7 +436,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (!iap->ia_valid) goto out; - nfsd_sanitize_attrs(inode, iap); + nfsd_sanitize_attrs(dentry, iap); /* * The size case is special, it changes the file in addition to the diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 8b59695..0791dd4 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -840,7 +840,7 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) struct super_block *sb = inode->i_sb; int err; - err = inode_change_ok(inode, iattr); + err = inode_change_ok(dentry, iattr); if (err) return err; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 898b994..6d51746 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -2894,7 +2894,7 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) int err; unsigned int ia_valid = attr->ia_valid; - err = inode_change_ok(vi, attr); + err = inode_change_ok(dentry, attr); if (err) goto out; /* We do not support NTFS ACLs yet. */ diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 57c40e3..4473e95 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -211,7 +211,7 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; attr->ia_valid &= ~ATTR_SIZE; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 7e5aa39..9067886 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1143,7 +1143,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) return 0; - status = inode_change_ok(inode, attr); + status = inode_change_ok(dentry, attr); if (status) return status; diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 902e885..db6314c 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c @@ -351,7 +351,7 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/proc/base.c b/fs/proc/base.c index d022159..7abfc57 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -509,7 +509,7 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_valid & ATTR_MODE) return -EPERM; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index aaabab4..5f24651 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -105,7 +105,7 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) struct proc_dir_entry *de = PDE(inode); int error; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) return error; diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 3f7dc3e..be5b366 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -753,7 +753,7 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) return -EPERM; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index bbafbde..daba062 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -163,7 +163,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) int ret = 0; /* POSIX UID/GID verification for setting inode attributes */ - ret = inode_change_ok(inode, ia); + ret = inode_change_ok(dentry, ia); if (ret) return ret; diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index a7eec98..80f5192 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3312,7 +3312,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) unsigned int ia_valid; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/sysv/file.c b/fs/sysv/file.c index b00811c..09099b5 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -35,7 +35,7 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 538519e..b663d11 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1262,7 +1262,7 @@ int ubifs_setattr(struct dentry *dentry, struct iattr *attr) dbg_gen("ino %lu, mode %#x, ia_valid %#x", inode->i_ino, inode->i_mode, attr->ia_valid); - err = inode_change_ok(inode, attr); + err = inode_change_ok(dentry, attr); if (err) return err; diff --git a/fs/udf/file.c b/fs/udf/file.c index 08f3555..e2a382e 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -258,7 +258,7 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr) struct inode *inode = dentry->d_inode; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index f04f89f..926ba19 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -496,7 +496,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr) unsigned int ia_valid = attr->ia_valid; int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 17d057c..ea6af4f 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -530,6 +530,7 @@ xfs_setattr_nonsize( { xfs_mount_t *mp = ip->i_mount; struct inode *inode = VFS_I(ip); + struct dentry *dentry = inode->i_sb->s_root; int mask = iattr->ia_valid; xfs_trans_t *tp; int error; @@ -548,7 +549,7 @@ xfs_setattr_nonsize( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) return error; } @@ -736,6 +737,7 @@ xfs_setattr_size( { struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); + struct dentry *dentry = inode->i_sb->s_root; xfs_off_t oldsize, newsize; struct xfs_trans *tp; int error; @@ -751,7 +753,7 @@ xfs_setattr_size( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; - error = inode_change_ok(inode, iattr); + error = inode_change_ok(dentry, iattr); if (error) return error; diff --git a/include/linux/fs.h b/include/linux/fs.h index 92c88b8..d12c959 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2690,7 +2690,7 @@ extern int buffer_migrate_page(struct address_space *, #define buffer_migrate_page NULL #endif -extern int inode_change_ok(const struct inode *, struct iattr *); +extern int inode_change_ok(struct dentry *, struct iattr *); extern int inode_newsize_ok(const struct inode *, loff_t offset); extern void setattr_copy(struct inode *inode, const struct iattr *attr); diff --git a/mm/shmem.c b/mm/shmem.c index 993e6ba..fc6cab1 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -553,7 +553,7 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) struct shmem_inode_info *info = SHMEM_I(inode); int error; - error = inode_change_ok(inode, attr); + error = inode_change_ok(dentry, attr); if (error) return error;