diff mbox series

[1/1,SRU,Disco] shiftfs: fix passing of attrs to underaly for setattr

Message ID 20190414154422.7284-2-seth.forshee@canonical.com
State New
Headers show
Series [1/1,SRU,Disco] shiftfs: fix passing of attrs to underaly for setattr | expand

Commit Message

Seth Forshee April 14, 2019, 3:44 p.m. UTC
https://bugs.launchpad.net/bugs/1824717

shiftfs_setattr() makes a copy of the attrs it was passed to pass
to the lower fs. It then calls setattr_prepare() with the original
attrs, and this may make changes which are not reflected in the
attrs passed to the lower fs. To fix this, copy the attrs to the
new struct for the lower fs after calling setattr_prepare().

Additionally, notify_change() may have set ATTR_MODE when one of
ATTR_KILL_S[UG]ID is set, and passing this combination to
notify_change() will trigger a BUG(). Do as overlayfs and
ecryptfs both do, and clear ATTR_MODE if either of those bits
is set.

Reviewed-by: Christian Brauner <christian.brauner@ubuntu.com>
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
 fs/shiftfs.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/shiftfs.c b/fs/shiftfs.c
index e736fd6afcb4..8e064756ea0c 100644
--- a/fs/shiftfs.c
+++ b/fs/shiftfs.c
@@ -765,7 +765,7 @@  static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr)
 {
 	struct dentry *lowerd = dentry->d_fsdata;
 	struct inode *loweri = lowerd->d_inode;
-	struct iattr newattr = *attr;
+	struct iattr newattr;
 	const struct cred *oldcred;
 	struct super_block *sb = dentry->d_sb;
 	int err;
@@ -774,9 +774,17 @@  static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr)
 	if (err)
 		return err;
 
+	newattr = *attr;
 	newattr.ia_uid = KUIDT_INIT(from_kuid(sb->s_user_ns, attr->ia_uid));
 	newattr.ia_gid = KGIDT_INIT(from_kgid(sb->s_user_ns, attr->ia_gid));
 
+	/*
+	 * mode change is for clearing setuid/setgid bits. Allow lower fs
+	 * to interpret this in its own way.
+	 */
+	if (newattr.ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
+		newattr.ia_valid &= ~ATTR_MODE;
+
 	inode_lock(loweri);
 	oldcred = shiftfs_override_creds(dentry->d_sb);
 	err = notify_change(lowerd, &newattr, NULL);