diff options
| author | Dave Chinner <dchinner@redhat.com> | 2013-05-27 02:38:25 -0400 |
|---|---|---|
| committer | Ben Myers <bpm@sgi.com> | 2013-05-30 18:17:35 -0400 |
| commit | 2962f5a5dcc56f69cbf62121a7be67cc15d6940b (patch) | |
| tree | bd6e72c1c65e2e2c897e0e214528cf750c06ae27 | |
| parent | 08fb39051f5581df45ae2a20c6cf2d0c4cddf7c2 (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>
(cherry picked from commit 56c19e89b38618390addfc743d822f99519055c6)
| -rw-r--r-- | fs/xfs/xfs_iops.c | 47 |
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 | ||
| 458 | static void | ||
| 459 | xfs_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 | |||
| 458 | int | 480 | int |
| 459 | xfs_setattr_nonsize( | 481 | xfs_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; |
