TL;DR
A child process spawned by a SUID program may not inherit the parent’s effective user ID (EUID) if certain conditions are met, particularly when using exec family functions. This guide explains why and how to fix it.
Understanding the Problem
When a program is set with the SUID bit, it runs with the permissions of the file owner (typically root). Normally, any child processes created by this program should also run with those elevated privileges. However, there are scenarios where this doesn’t happen.
Why Child Processes Might Not Inherit UID
execFamily Functions: Using functions likeexecve,execl, orexecvpcan cause the child process to lose the elevated privileges if not handled correctly.- Setuid/Setgid Issues: Incorrectly setting up setuid and setgid bits in the program’s environment can lead to privilege dropping.
- Shell Scripting: Shell scripts are interpreted, not directly executed, which affects how SUID works. Direct execution of binaries is preferred for SUID programs.
Solution Guide
- Use Direct Binary Execution (Preferred): Avoid using shell scripts as SUID programs whenever possible. Compile your program directly into an executable binary.
- Shells often reset the effective UID/GID of child processes, negating the SUID effect.
- Ensure Proper
execUsage: If you must useexecfunctions, make sure they are called correctly within your C code.#include <unistd.h> int main() { uid_t uid = geteuid(); if (uid != 0) { // Program is not running as root, handle error or exit return 1; } execl("/bin/bash", "bash", "-c", "whoami", NULL); perror("exec failed"); // Check for errors after exec return 1; } - Verify Effective UID After Fork: Immediately after a
fork()call, check the effective user ID of the child process.#include <unistd.h> #include <stdio.h> int main() { pid_t pid = fork(); if (pid == 0) { // Child Process uid_t uid = geteuid(); printf("Child process UID: %dn", uid); // Continue with your program logic } else if (pid > 0) { // Parent Process // ... } return 0; } - Avoid Unnecessary Privilege Dropping: Don’t explicitly call functions like
setuid()orsetgid()unless absolutely necessary. These can unintentionally lower the privileges. - Check Environment Variables: Ensure that environment variables aren’t interfering with the SUID behavior. Some variables might reset UID/GID.
- Use
getenv("HOME")to check if the HOME variable is set, as it can sometimes cause issues.
- Use
- Setuid Bit Verification: Confirm that the SUID bit is actually set on the executable file using
ls -l.ls -l /path/to/your/executableThe output should show an ‘s’ in the permissions field (e.g.,
-rwsr-xr-x). If it shows an ‘S’, the SUID bit is set but the program isn’t running as root.