Debugging a setuid program / "Permission denied" with setuid - c

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?

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.

Related

Redirecting C system() output fails only with yq

I'm using yq to convert a YAML document into JSON for use in a C program. In my program, I convert the file to JSON using the command
system("yq ea \'[.]\' -o=json .cache/BT_nginx-ingress.yaml > .cache/package.json")
However this causes the error:
Error: write /dev/stdout: permission denied
Thoughout my program, I've used redirection several times with the system() command, but it fails in this specific instance.
I can run the command normally from the terminal, without root. I'm using bash on PopOS, so I've also added bash -c to the above system() call, but it fails this way too.
Can anyone help me with this? Thanks!
Edit: More details on my configuration. The current working directory is the same as the program's location which is one directory above .cache. The working directory is never changed. I am the owner of .cache and the files inside. The permissions are r/w for me, and the group. I am running the process but not with sudo. system("echo foo > .cache/package.json") works!
I have managed to fix this issue by adding the yq_linux_amd64 binary with the C program itself, rather than using the yq package from snap. It works fine now, and can redirect outputs without any issue.

Eclipse C: Error Starting Process - Launching Failed Cannot Run Program

I've been trying to setup Eclipse for some C developing. I manage to get the example "hello world" program (provided by Eclipse) to compile, however I am unable to run or debug it. Since I am able to compile, I assume that the setup for the compiler is correct, I can also find the executable file in the workspace (which will not run manually).
While trying to run it through Eclipse I get the error "Error Starting Process - Launching Failed, Cannot run program".
While trying to debug it from Eclipse, I get the error "Error in final launch sequence: Failed to execute MI command: -exec-run" and "Error creating process %path to executable%(error 5)".
I've tried changing workspace to one that has no spaces and to reinstall the compiler (MinGW) with no success.
If anyone could provide some insight on the problem I'd be very grateful.
Edit: Attempting to run the executable returns the following error: "Windows cannot access the specified device, path or file. You may not have the appropriate permissions to access the item." This is strange as I am running it as an admin on my machine.
Furthermore, attempting to run the executable from an administrator permission level command prompt window returns "access is denied".
It turned out my anti-virus software was blocking the file's execution, disabled it and the program ran just fine.

How to send an snmp trap as a non-root user?

I'm trying to send a trap using snmptrap. It works fine if I run as root.
If I run as a non-root user, I get lots of errors about "Cannot find module (XYZ): At line 0 in (none)". eg, HOST-RESOURCES-MIG, HOST-RESOURCES-TYPES, UCD-DISKIO-MIB, ...
I assume there's some files it can't read. Is there a simple way to run snmptrap as non-root? Or is there a better alternative?
Those errors don't look related to requiring root privileges. Likely you have different environment (specifically net-snmp default paths to MIBs) for the different users ?
Try
net-snmp-config --default-mibdirs
for each users. In my own setup I see output something like this:
/Users/some_user/.snmp/mibs:/usr/share/snmp/mibs
See netsnmp page for more detail on use of -M and -m flags to set up environment per user.

popen: 'sh: permission denied"

I'm trying to use popen. When I execute some system command (e.g. let's say ls or whatever) all works fine. But when I'm trying to execute my executable:
pipe = popen("./ <path>","r");
I get an error:
sh: permission denied.
Both executables (which uses popen and that one which I want to launch from first one) belong to my user accound and have "x" permissions.
I'd double check that error message, since it should say what the permission denied relates too. i.e. if path was empty, and you just passed ./, or had an extra space like in your example, you should see
sh: ./: Permission denied
As you describe it, it sounds like your getting a permission denied error trying to run /bin/sh; it seems more likely that you misread the error.

How to bind root (/) to itself with fuse on linux?

I'm writing a fuse file system that mount one directory to itself. I want to log some calls (flush for example). I've started to adapt fuse tutorial sample code. If I try to bind any directory it works great:
./bbfs -o nonempty ./test ./test
but if I try to bind particular root directory ("/"):
sudo ./bbfs -o nonempty / /
no one line is in logfile.
Is it possible?
My mangled version of sample program. I've changed only bbfs.c file.
You can't mount a FUSE filesystem (or any other type of filesystem, for that matter) at /, because your root filesystem is already there.
Doing so would be disastrous anyway, as mounting a filesystem at a path makes any files which previously existed under that path inaccessible. You can't use FUSE as a filter like this -- you will need to find another solution to whatever it is you're trying to do.

Resources