SetUID – Fix SetUID Bit Not Working in Ubuntu

setuid

I suppose an executable file with SetUID bit set should be running as its owner but I cannot really reproduce it. I tried the following.

$ cat prepare.sh
cp /bin/bash .
chown root.root bash
chmod 4770 bash # Verified
$ sudo sh prepare.sh
$ ./bash
$ id -u
1000
$ exit
$
$ cat test.c
#include<stdio.h>
#include<unistd.h>
int main(){
    printf("%d,%d\n", getuid(), geteuid());
    return 0;
}
$ gcc -o test test.c
$ chmod 4770 test # Verified
$ sudo chown root.root test
$ ./test
1000,1000
$ # Why???

However

$ su
# ./bash
# id -u
0
# ./test
0,0
# exit
# exit
$

Note: The mount point has no nosuid nor noexec set.
Can anyone explain why it's failing to work on Ubuntu 16.04 LTS?

Best Answer

For the compiled executable, from man 2 chown:

When the owner or group  of  an  executable  file  are  changed  by  an
unprivileged user the S_ISUID and S_ISGID mode bits are cleared.  POSIX
does not specify whether this also should happen  when  root  does  the
chown();  the Linux behavior depends on the kernel version.

Reversing the chown and chmod order works for me:

$ sudo chmod 4770 foo
$ sudo chown root:root foo
$ stat foo
  File: 'foo'
  Size: 8712        Blocks: 24         IO Block: 4096   regular file
Device: 801h/2049d  Inode: 967977      Links: 1
Access: (0770/-rwxrwx---)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2017-04-18 15:15:15.074425000 +0900
Modify: 2017-04-18 15:15:15.074425000 +0900
Change: 2017-04-18 15:15:33.683725000 +0900
 Birth: -
$ sudo chmod 4777 foo
$ ./foo
1000,0