aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2013-05-27 02:38:25 -0400
committerBen Myers <bpm@sgi.com>2013-05-30 14:43:52 -0400
commit56c19e89b38618390addfc743d822f99519055c6 (patch)
tree3aeb4998ac2f3b6529d149770c9759a26bec9eba
parent74137fff067961c9aca1e14d073805c3de8549bd (diff)
xfs: kill suid/sgid through the truncate path.
XFS has failed to kill suid/sgid bits correctly when truncating files of non-zero size since commit c4ed4243 ("xfs: split xfs_setattr") introduced in the 3.1 kernel. Fix it. Fix it. cc: stable kernel <stable@vger.kernel.org> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/xfs_iops.c47
1 files changed, 32 insertions, 15 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index d82efaa2ac73..ca9ecaa81112 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -455,6 +455,28 @@ xfs_vn_getattr(
455 return 0; 455 return 0;
456} 456}
457 457
458static void
459xfs_setattr_mode(
460 struct xfs_trans *tp,
461 struct xfs_inode *ip,
462 struct iattr *iattr)
463{
464 struct inode *inode = VFS_I(ip);
465 umode_t mode = iattr->ia_mode;
466
467 ASSERT(tp);
468 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
469
470 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
471 mode &= ~S_ISGID;
472
473 ip->i_d.di_mode &= S_IFMT;
474 ip->i_d.di_mode |= mode & ~S_IFMT;
475
476 inode->i_mode &= S_IFMT;
477 inode->i_mode |= mode & ~S_IFMT;
478}
479
458int 480int
459xfs_setattr_nonsize( 481xfs_setattr_nonsize(
460 struct xfs_inode *ip, 482 struct xfs_inode *ip,
@@ -606,18 +628,8 @@ xfs_setattr_nonsize(
606 /* 628 /*
607 * Change file access modes. 629 * Change file access modes.
608 */ 630 */
609 if (mask & ATTR_MODE) { 631 if (mask & ATTR_MODE)
610 umode_t mode = iattr->ia_mode; 632 xfs_setattr_mode(tp, ip, iattr);
611
612 if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
613 mode &= ~S_ISGID;
614
615 ip->i_d.di_mode &= S_IFMT;
616 ip->i_d.di_mode |= mode & ~S_IFMT;
617
618 inode->i_mode &= S_IFMT;
619 inode->i_mode |= mode & ~S_IFMT;
620 }
621 633
622 /* 634 /*
623 * Change file access or modified times. 635 * Change file access or modified times.
@@ -714,9 +726,8 @@ xfs_setattr_size(
714 return XFS_ERROR(error); 726 return XFS_ERROR(error);
715 727
716 ASSERT(S_ISREG(ip->i_d.di_mode)); 728 ASSERT(S_ISREG(ip->i_d.di_mode));
717 ASSERT((mask & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| 729 ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET|
718 ATTR_MTIME_SET|ATTR_KILL_SUID|ATTR_KILL_SGID| 730 ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
719 ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
720 731
721 if (!(flags & XFS_ATTR_NOLOCK)) { 732 if (!(flags & XFS_ATTR_NOLOCK)) {
722 lock_flags |= XFS_IOLOCK_EXCL; 733 lock_flags |= XFS_IOLOCK_EXCL;
@@ -860,6 +871,12 @@ xfs_setattr_size(
860 xfs_inode_clear_eofblocks_tag(ip); 871 xfs_inode_clear_eofblocks_tag(ip);
861 } 872 }
862 873
874 /*
875 * Change file access modes.
876 */
877 if (mask & ATTR_MODE)
878 xfs_setattr_mode(tp, ip, iattr);
879
863 if (mask & ATTR_CTIME) { 880 if (mask & ATTR_CTIME) {
864 inode->i_ctime = iattr->ia_ctime; 881 inode->i_ctime = iattr->ia_ctime;
865 ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec; 882 ip->i_d.di_ctime.t_sec = iattr->ia_ctime.tv_sec;