Ubuntu – SUID bit on binary file still yielding “Permission denied” error

permissionsUbuntu

alice and bob both belong to the staff group.

I've got the following folder:

drwxrwxr-x 2 alice staff 4096 Oct 30 14:45 share

with the following files inside the folder:

-rwsr-xr-x 1 alice alice 8768 Oct 30 14:45 display-foo
-rw------- 1 alice alice 24 Oct 30 14:45 foo.txt

display-foo is a binary file that essentially displays the contents of foo.txt using the cat command.

When alice runs ./display-foo, the binary file executes successfully and the contents of foo.txt are displayed. However, when bob runs ./display-foo, the binary file executes successfully but the contents of the foo.txt are not displayed, yielding the error /bin/cat: /home/alice/share/foo.txt: Permission denied.


From my understanding, setting the setuid bit allows the binary executable to be executed with the privileges of the file's owner (in this case, alice). Why, then, was bob not allowed to view the contents of foo.txt?


ADDENDUM: I have recompiled my binary file with the geteuid() function so that it prints out the effective user ID (EUID). Indeed, when bob executes the binary file, the EUID is that of alice. Yet, permission is denied. Here's a snippet of the source code:

printf("%d", geteuid());
system("/bin/cat /home/alice/share/foo.txt");

Best Answer

I read through the manual page for the system function and came across the following passage which offers an explanation:

Do not use system() from a program with set-user-ID or set-group-ID
privileges, because strange values for some environment variables
might be used to subvert system integrity.  Use the exec(3) family of
functions instead, but not execlp(3) or execvp(3).  system() will
not, in fact, work properly from programs with set-user-ID or set-
group-ID privileges on systems on which /bin/sh is bash version 2,
since bash 2 drops privileges on startup.  (Debian uses a modified
bash which does not do this when invoked as sh.)

Here are some other StackExchange posts that I read through on my way to that passage:

For posterity, and because the given example might be useful for diagnosing this or similar issues in other contexts, I've kept my original below.


Is it possible that you're running into a bug? I was unable to reproduce your problem in a Docker container running Debian 9 with gcc 6.3. Here is how I went about trying to recreate the scenario described in your post.

First create the "alice" and "bob" users and them to the "staff" group:

useradd -m -G staff alice
useradd -m -G staff bob

Next create the file and set its ownership and permissions:

# Create a subdirectory to hold the text file
sudo -u alice mkdir -p /home/alice/share/

# Create the text file
sudo -u alice bash -c 'echo "This is foo.txt" > /home/alice/share/foo.txt'

# Set restrictive permissions on the text file
chmod u=rw,g=,o= /home/alice/share/foo.txt

Let's check the results:

$ ls -l /home/alice/share/foo.txt
-rw------- 1 alice alice 16 Nov  4 15:33 /home/alice/share/foo.txt

Now let's create a version of display-foo which uses the system function:

$ cat <<HEREDOC > /usr/local/src/display-foo.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>

int main(int argc, char **argv) {

    struct passwd *r_pwd = getpwuid(getuid());
    printf("Real user: %s\n", r_pwd->pw_name);

    struct passwd *e_pwd = getpwuid(geteuid());
    printf("Effective user: %s\n", e_pwd->pw_name);

    system("/bin/cat /home/alice/share/foo.txt");
}
HEREDOC

$ gcc /usr/local/src/display-foo.c -o /usr/local/bin/display-foo

And let's set ownership and permissions on display-foo, including setting the setuid bit:

chown alice:alice /usr/local/bin/display-foo
chmod u=rwx,g=rx,o=rx /usr/local/bin/display-foo
chmod u+s /usr/local/bin/display-foo

Let's also check the result:

$ ls -l /usr/local/bin/display-foo
-rwsr-xr-x 1 alice alice 8640 Nov  4 15:40 /usr/local/bin/display-foo

Now we run the program both as alice and as bob:

$ sudo -u alice display-foo

Real user: alice
Effective user: alice
This is foo.txt

$ sudo -u bob display-foo

Real user: bob
Effective user: alice
This is foo.txt

As you can see, it looks like everything is working as expected.

Related Question