Question

This is actually a three-part question, which I'll explain below, but the questions are:

  • Using gdb, how can I run part of a program with root authority, and the rest with normal?
  • Why would I get "permission denied" using mkstemp to create a file in /tmp in a setuid (to root) program?
  • Why would "sudo program_name" perform any differently from just ./program_name with setuid to root?

I have a C program running on Linux (multiple distributions) that normally is run by a user with normal privileges, but some parts of the program must run with root authority. For this, I have used the set-UID flag, and that works fine, as far as it goes.

However, now I would like to debug the program with normal user authority, and I find I have a catch-22. I have just added a function to create a temporary file (/tmp/my_name-XXXXXX), and that function is called from many points within the program. For whatever reason, this function issues the following message when running:

sh: /tmp/my_name-hhnNuM: Permission denied

(of course, the actual name varies.) And yet, the program is able to execute raw socket function that I absolutely know cannot be done by users other than root. (If I remove the setuid flag, the program fails miserably.)

If I run this program via gdb without sudo, it dies on the raw socket stuff (since gdb apparently doesn't --or probably cannot-- honor the setuid flag on the program). If I run it under "sudo gdb" then everything works fine. If I run it as "sudo ./my_name, everything works fine.

Here is the ls -l output for that program:

-rwsr-xr-x 1 root root 48222 Jun 23 08:14 my_name

So my questions, in no particular order:

  • (How) can I run different parts of a program with different effective UID under gdb?
  • Why is "sudo ./program" different from "./program" when ./program has set-uid to root?
  • Why would mkstemp fail when called by a normal user in a setuid (to root) program?
Was it helpful?

Solution

1 The only way to debug the setuid application properly under gdb is to run gdb as root. The most sensible way to do this for a setuid application is to attach to the application once it starts. A quick trick to doing this is to add a line into the setuid application:

kill(getpid(), SIGSTOP);

This causes it to stop at this point, then you attach gdb using:

sudo gdb <application> <pid>

Then you are attached to the application and can debug it as normal.

2 sudo changes the rules as it allows a variety of items from the current user's environment to be exported into the root user's environment. This is wholly dependent on the current sudo configuration and can leave you with a very different environment than a setuid application which is why you need to rely on tricks like stopping the application and then attaching to it at run time.

Additionally there may be logic in the application to detect if it's running in a setuid environment which is not actually the case when run under sudo - remember that sudo sets all the process's id fields (real uid, effective uid and saved uid) to the same value, which setuid doesn't (the real uid is still that of the original caller). You can use the getresuid() call to determine the state of the three variables.

3 The thing is that the Permission Denied message has a prefix of sh:; this seems to imply that another sub-process is being executed that is trying to access the file. After you've invoked mkstemp, you may want to loosen up the permission to read the file so that the subprocess is able to read the file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top