Skip to content

Commit e014f37

Browse files
author
Darrick J. Wong
committed
xfs: use setattr_copy to set vfs inode attributes
Filipe Manana pointed out that XFS' behavior w.r.t. setuid/setgid revocation isn't consistent with btrfs[1] or ext4. Those two filesystems use the VFS function setattr_copy to convey certain attributes from struct iattr into the VFS inode structure. Andrey Zhadchenko reported[2] that XFS uses the wrong user namespace to decide if it should clear setgid and setuid on a file attribute update. This is a second symptom of the problem that Filipe noticed. XFS, on the other hand, open-codes setattr_copy in xfs_setattr_mode, xfs_setattr_nonsize, and xfs_setattr_time. Regrettably, setattr_copy is /not/ a simple copy function; it contains additional logic to clear the setgid bit when setting the mode, and XFS' version no longer matches. The VFS implements its own setuid/setgid stripping logic, which establishes consistent behavior. It's a tad unfortunate that it's scattered across notify_change, should_remove_suid, and setattr_copy but XFS should really follow the Linux VFS. Adapt XFS to use the VFS functions and get rid of the old functions. [1] https://lore.kernel.org/fstests/CAL3q7H47iNQ=Wmk83WcGB-KBJVOEtR9+qGczzCeXJ9Y2KCV25Q@mail.gmail.com/ [2] https://lore.kernel.org/linux-xfs/[email protected]/ Fixes: 7fa294c ("userns: Allow chown and setgid preservation") Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Christian Brauner <[email protected]>
1 parent eba0549 commit e014f37

File tree

2 files changed

+5
-54
lines changed

2 files changed

+5
-54
lines changed

fs/xfs/xfs_iops.c

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -613,37 +613,6 @@ xfs_vn_getattr(
613613
return 0;
614614
}
615615

616-
static void
617-
xfs_setattr_mode(
618-
struct xfs_inode *ip,
619-
struct iattr *iattr)
620-
{
621-
struct inode *inode = VFS_I(ip);
622-
umode_t mode = iattr->ia_mode;
623-
624-
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
625-
626-
inode->i_mode &= S_IFMT;
627-
inode->i_mode |= mode & ~S_IFMT;
628-
}
629-
630-
void
631-
xfs_setattr_time(
632-
struct xfs_inode *ip,
633-
struct iattr *iattr)
634-
{
635-
struct inode *inode = VFS_I(ip);
636-
637-
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
638-
639-
if (iattr->ia_valid & ATTR_ATIME)
640-
inode->i_atime = iattr->ia_atime;
641-
if (iattr->ia_valid & ATTR_CTIME)
642-
inode->i_ctime = iattr->ia_ctime;
643-
if (iattr->ia_valid & ATTR_MTIME)
644-
inode->i_mtime = iattr->ia_mtime;
645-
}
646-
647616
static int
648617
xfs_vn_change_ok(
649618
struct user_namespace *mnt_userns,
@@ -742,16 +711,6 @@ xfs_setattr_nonsize(
742711
gid = (mask & ATTR_GID) ? iattr->ia_gid : igid;
743712
uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
744713

745-
/*
746-
* CAP_FSETID overrides the following restrictions:
747-
*
748-
* The set-user-ID and set-group-ID bits of a file will be
749-
* cleared upon successful return from chown()
750-
*/
751-
if ((inode->i_mode & (S_ISUID|S_ISGID)) &&
752-
!capable(CAP_FSETID))
753-
inode->i_mode &= ~(S_ISUID|S_ISGID);
754-
755714
/*
756715
* Change the ownerships and register quota modifications
757716
* in the transaction.
@@ -763,7 +722,6 @@ xfs_setattr_nonsize(
763722
olddquot1 = xfs_qm_vop_chown(tp, ip,
764723
&ip->i_udquot, udqp);
765724
}
766-
inode->i_uid = uid;
767725
}
768726
if (!gid_eq(igid, gid)) {
769727
if (XFS_IS_GQUOTA_ON(mp)) {
@@ -774,15 +732,10 @@ xfs_setattr_nonsize(
774732
olddquot2 = xfs_qm_vop_chown(tp, ip,
775733
&ip->i_gdquot, gdqp);
776734
}
777-
inode->i_gid = gid;
778735
}
779736
}
780737

781-
if (mask & ATTR_MODE)
782-
xfs_setattr_mode(ip, iattr);
783-
if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
784-
xfs_setattr_time(ip, iattr);
785-
738+
setattr_copy(mnt_userns, inode, iattr);
786739
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
787740

788741
XFS_STATS_INC(mp, xs_ig_attrchg);
@@ -1006,11 +959,8 @@ xfs_setattr_size(
1006959
xfs_inode_clear_eofblocks_tag(ip);
1007960
}
1008961

1009-
if (iattr->ia_valid & ATTR_MODE)
1010-
xfs_setattr_mode(ip, iattr);
1011-
if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME))
1012-
xfs_setattr_time(ip, iattr);
1013-
962+
ASSERT(!(iattr->ia_valid & (ATTR_UID | ATTR_GID)));
963+
setattr_copy(mnt_userns, inode, iattr);
1014964
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1015965

1016966
XFS_STATS_INC(mp, xs_ig_attrchg);

fs/xfs/xfs_pnfs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ xfs_fs_commit_blocks(
319319
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
320320
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
321321

322-
xfs_setattr_time(ip, iattr);
322+
ASSERT(!(iattr->ia_valid & (ATTR_UID | ATTR_GID)));
323+
setattr_copy(&init_user_ns, inode, iattr);
323324
if (update_isize) {
324325
i_size_write(inode, iattr->ia_size);
325326
ip->i_disk_size = iattr->ia_size;

0 commit comments

Comments
 (0)