linuxpermissionssetuid

Why the setuid program does not have the privilege to execute system()


I have the following program:

$ cat cat.c
#include <err.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
  char buf[32];

  if(argc == 1) {
    errx(1, "please specify an argument.");
  }

  sprintf(buf, "cat %s", argv[1]);
  system(buf);
  return 0;
}
$ gcc cat.c -o mycat
$ chmod +s mycat; sudo chown root mycat
$ ls -lth mycat
-rwsr-sr-x 1 root ... 11:12 mycat
$ ls -lth secret
-rw------- 1 root ... 11:10 secret

I thought ./mycat secret should be able to read the secret file because mycat is a setuid program, and its owner is root. However, here is what I get:

$ ./mycat secret
cat: secret: Permission denied
$ sudo chown user1 secret
$ ./mycat secret
4ea6f17dd6818

Anything I misunderstood?


Solution

  • This program demonstrates what's working and what doesn't :

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    int main(int argc, char *argv[])
    {
      char buf[64];
      if (fork() == 0){
        char *newargv[] = { "cat", argv[1], NULL };
        execve("/usr/bin/cat", newargv, NULL); // This call directly `cat` without spawning a `shell`, so works as expected.
        return 0;
      }
      sprintf(buf, "cat %s", argv[1]);
      system(buf); // `system` spawns a shell which then calls `cat`, as the `shell` lost setuid privilaege, `cat` fails with `Permission denied`.
      return 0;
    }