[PATCH] This change is based in:

José Pekkarinen jose.pekkarinen at canonical.com
Wed Aug 1 14:57:31 UTC 2018


fs: Avoid premature clearing of capabilities(030b533c4fd)
Reviewed-by: Christoph Hellwig <hch at lst.de>
by: Jan Kara <jack at 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 at 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 at 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;
 
-- 
2.7.4





More information about the kernel-team mailing list