Bug 1294650

Summary: chgrp behaviour when unseting the SGID bit differs between XFS and ext4 filesystem on RHEL 7.1
Product: Red Hat Enterprise Linux 7 Reporter: Gaurav <gkulkarn>
Component: coreutilsAssignee: Ondrej Vasik <ovasik>
Status: CLOSED NOTABUG QA Contact: qe-baseos-daemons
Severity: low Docs Contact:
Priority: unspecified    
Version: 7.1CC: esandeen, gkulkarn
Target Milestone: rc   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2016-03-29 14:14:22 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Strace output (for ext4 FS)
none
Strace output (for xfs FS)
none
FS attributes for EXT4
none
FS info for XFS
none
strace ran from normal user for EXT4
none
strace ran from normal user for XFS none

Description Gaurav 2015-12-29 12:40:27 UTC
Description of problem:

There is difference in behaviour between ext3/ext4 and xfs related to chgrp. The setgid is preserved on ext3/4 while on xfs it is unset after chgrp.

Version-Release number of selected component (if applicable):

RHEL 7.1; coreutils-8.22-11.el7.x86_64

How reproducible:

Create a test machine with below :

[root@client71 test-ext4]# cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 7.1 (Maipo)

[root@client71 test-ext4]# uname -a
Linux client71 3.10.0-229.el7.x86_64 #1 SMP Thu Jan 29 18:37:38 EST 2015 x86_64 x86_64 x86_64 GNU/Linux

usr1:x:1001:1001::/home/usr1:/bin/bash
usr2:x:1002:1002::/home/usr2:/bin/bash

[usr1@client71 ~]$ df -Th|grep 'test'
/dev/mapper/rhel-test--ext4  ext4      477M  2.3M  445M   1% /test-ext4
/dev/mapper/rhel-test--xfs   xfs       497M   26M  472M   6% /test-xfs


Steps to Reproduce:
1. Create two filesystems - one ext4 and other XFS
2. Create two test users - usr1 and usr2
3. In both the filesystems - Create a test directory and set SGID bit for it
4. Change the group owner for the test directory in both FS to some other user
5. The group owner will be modified but the SGID bit will be cleared in XFS, but the SGID bit will be preserved for ext4 FS.

Actual results:
  
    ====== For ext4 FS ======

[usr1@client71 test-ext4]$ ls -l
total 2
drwxrwsr-x. 2 usr1 usr1 1024 Dec 29 12:28 temp

[usr1@client71 test-ext4]$ chgrp usr2 temp

[usr1@client71 test-ext4]$ ls -l
total 2
drwxrwsr-x. 2 usr1 usr2 1024 Dec 29 12:28 temp

     ======= For XFS FS =======

[usr1@client71 test-ext4]$ cd /test-xfs/

[usr1@client71 test-xfs]$ ls -l
total 2
drwxrwsr-x. 2 usr1 usr1 6 Dec 29 12:30 temp

[usr1@client71 test-xfs]$ chgrp usr2 temp

[usr1@client71 test-xfs]$ ls -l
total 2
drwxrwxr-x. 2 usr1 usr2 6 Dec 29 12:30 temp


Expected results:

For XFS filesystem, the SGID bit should not be unset after the group ownership has been changed. 

Additional info:

In RHEL 6.5, the SGID is preserved for XFS filesystem even after changing the group ownership.

Comment 2 Ondrej Vasik 2015-12-29 19:32:56 UTC
Can you please provide strace of these two situations?
I believe on both filesystems the permissions bits should be adjusted by fchownat() syscall...
On my machine:
[Reset@unused-4-106 mnt]$ rpm -q coreutils
coreutils-8.22-11.el7.x86_64
[Reset@unused-4-106 mnt]$ ls -l
total 13
drwx------. 2 root root 12288 29. pro 20.25 lost+found
-rwxr-sr-x. 1 root root     0 29. pro 20.26 test
[Reset@unused-4-106 mnt]$ df -Th .  
Filesystem     Type  Size  Used Avail Use% Mounted on
/dev/loop0       ext4      30M  762K   27M   3% /home/Reset/koji/coreutils/coreutils-8.22/tests/cp/mnt
[Reset@unused-4-106 mnt]$ sudo chgrp test test
[Reset@unused-4-106 mnt]$ ls -l
total 13
drwx------. 2 root root 12288 29. pro 20.25 lost+found
-rwxr-xr-x. 1 root test     0 29. pro 20.26 test

IOW - setgid bit cleared even on ext4 device.

Comment 3 Gaurav 2015-12-30 07:30:28 UTC
Created attachment 1110461 [details]
Strace output (for ext4 FS)

command: #strace -o strace_ext4 chgrp usr2 temp

Command executed successfully, preserving the SGID bit.

Comment 4 Gaurav 2015-12-30 07:31:43 UTC
Created attachment 1110462 [details]
Strace output (for xfs FS)

command: #strace -o strace_xfs chgrp usr2 temp

Command executed successfully, clearing the SGID bit.

Comment 5 Ondrej Vasik 2015-12-30 19:36:00 UTC
Strange, I don't see anything obvious - no difference - any special flags on ext4 when mounting? (output of mount...)
When I tried this on my dummy loopback device with ext4 filesystem, it cleared the SGID bit (as shown in comment #2). Adding Eric Sandeen to cc - as he is expert on ext4 filesystem. Eric - do you have any idea what might be the difference? fchownat() seems to behave differently on ext4 and xfs in Gaurav's case.

Comment 6 Eric Sandeen 2015-12-30 23:58:56 UTC
It seems like xfs is doing the appropriate thing here, from the Open Group:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/chgrp.html

> Unless chgrp is invoked by a process with appropriate privileges, the set-user-ID and set-group-ID bits of a regular file shall be cleared upon successful completion; the set-user-ID and set-group-ID bits of other file types may be cleared.

Emphasis on "may be" here ...

XFS code does:

        /*
         * Change file ownership.  Must be the owner or privileged.
         */
        if (mask & (ATTR_UID|ATTR_GID)) {
                /*
                 * CAP_FSETID overrides the following restrictions:
                 *
                 * The set-user-ID and set-group-ID bits of a file will be
                 * cleared upon successful return from chown()
                 */
                if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
                    !capable(CAP_FSETID))
                        ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);

In comment #3 it seems that the chgrp was performed by root ("#strace -o strace_ext4 chgrp usr2 temp" - IOWS I think the permissions of the user calling chgrp matter here and that needs to be clarified in the testcases...

Comment 7 Gaurav 2015-12-31 13:35:30 UTC
No special flags on ext4 while mounting. Both the filesystems are mounted in default way. I have attached the filesystem attribute/details and ran strace by normal user.

[usr1@client71 test-xfs]$ cat /proc/mounts |grep test
/dev/mapper/rhel-test--ext4 /test-ext4 ext4 rw,seclabel,relatime,data=ordered 0 0
/dev/mapper/rhel-test--xfs /test-xfs xfs rw,seclabel,relatime,attr2,inode64,noquota 0 0

[usr1@client71 ~]$ tail -3 /etc/passwd
usr1:x:1001:1001::/home/usr1:/bin/bash
usr2:x:1002:1002::/home/usr2:/bin/bash
usr3:x:1003:1003::/home/usr3:/bin/bash

[usr1@client71 ~]$ df -h | grep test
/dev/mapper/rhel-test--ext4  477M  2.3M  445M   1% /test-ext4
/dev/mapper/rhel-test--xfs   497M   26M  472M   6% /test-xfs

usr1 and usr2 are normal users, and showed same behaviour :

============= For EXT4 ================

[usr1@client71 test-ext4]$ ls -l
total 2
drwxrwsr-x. 2 usr1 usr1 1024 Dec 30 12:37 temp

[usr1@client71 test-ext4]$ strace -o strace_ext4_new chgrp usr2 temp

[usr1@client71 test-ext4]$ ls -l
total 8
-rw-rw-r--. 1 usr1 usr1 4197 Dec 31 18:29 strace_ext4_new
drwxrwsr-x. 2 usr1 usr2 1024 Dec 30 12:37 temp


============== For XFS ================

[usr1@client71 test-xfs]$ ls -l
total 0
drwxrwsr-x. 2 usr1 usr1 6 Dec 29 12:30 temp

[usr1@client71 test-xfs]$ strace -o strace_ext4_new chgrp usr2 temp

[usr1@client71 test-xfs]$ ls -l
total 8
-rw-rw-r--. 1 usr1 usr1 4194 Dec 31 18:26 strace_ext4_new
drwxrwxr-x. 2 usr1 usr2    6 Dec 29 12:30 temp

Comment 8 Gaurav 2015-12-31 13:36:53 UTC
Created attachment 1110782 [details]
FS attributes for EXT4

Comment 9 Gaurav 2015-12-31 13:37:29 UTC
Created attachment 1110783 [details]
FS info for XFS

Comment 10 Gaurav 2015-12-31 13:44:48 UTC
Created attachment 1110784 [details]
strace ran from normal user for EXT4

Comment 11 Gaurav 2015-12-31 13:45:15 UTC
Created attachment 1110785 [details]
strace ran from normal user for XFS

Comment 12 Ondrej Vasik 2016-01-01 11:18:31 UTC
Thanks Eric for the comment. Yes, I read the POSIX for chgrp/chown befoere  and I agree xfs is doing right thing here. However, chgrp cleared the bit on my testing ext4 loopback device - so the question is more what is causing ext4 on Gaurav's system to keep SGID bit. Will take closer look early next week when back in the office...

Comment 13 Gaurav 2016-01-01 12:53:10 UTC
One thing => usr1 is group member of usr2 in my case.

I then removed usr1 from group usr2 and performed the same :

============ For EXT4 ==============

[usr1@client71 test-ext4]$ ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 14:57 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 14:57 temp

[usr1@client71 test-ext4]$ chown usr2 file 
chown: changing ownership of ‘file’: Operation not permitted

[usr1@client71 test-ext4]$ chgrp usr2 temp
chgrp: changing group of ‘temp’: Operation not permitted

[usr1@client71 test-ext4]$ ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 14:57 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 14:57 temp

============= For XFS ===============

[usr1@client71 test-xfs]$ ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 15:03 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 15:03 temp

[usr1@client71 test-xfs]$ chown usr2 file 
chown: changing ownership of ‘file’: Operation not permitted

[usr1@client71 test-xfs]$ chgrp usr2 temp
chgrp: changing group of ‘temp’: Operation not permitted

[usr1@client71 test-xfs]$ ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 15:03 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 15:03 temp

So, there was no change in SGID/SUID bit in both cases. 

I tried the same thing with root user :

============ For EXT4 ==============

[root@client71 test-ext4]# ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 14:57 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 14:57 temp

[root@client71 test-ext4]# chown usr2 file 
[root@client71 test-ext4]# chgrp usr2 temp 

[root@client71 test-ext4]# ls -l
total 0
-rwxrwxr-x. 1 usr2 usr1 0 Jan  1 14:57 file
drwxrwsr-x. 2 usr1 usr2 6 Jan  1 14:57 temp

============ For XFS ==============

[root@client71 test-xfs]# ls -l
total 0
-rwsrwxr-x. 1 usr1 usr1 0 Jan  1 15:03 file
drwxrwsr-x. 2 usr1 usr1 6 Jan  1 15:03 temp

[root@client71 test-xfs]# chown usr2 file 

[root@client71 test-xfs]# chgrp usr2 temp 

[root@client71 test-xfs]# ls -l
total 0
-rwxrwxr-x. 1 usr2 usr1 0 Jan  1 15:03 file
drwxrwsr-x. 2 usr1 usr2 6 Jan  1 15:03 temp

Here, the SGID bit is preserved, but the SUID is cleared.