execve vs fexecve vs execveat
The primary difference between execve(), fexecve(), and execveat() lies in how you specify the target binary file to the Linux kernel. They all perform the exact same core function—wiping the current process memory space and executing a new program—but they accept different inputs to locate the file.
execve() — The Classic Path-Based Execution
- Input Signature:
int execve(const char *pathname, char *const argv[], char *const envp[]); - How it works: You must provide a standard string path to the binary (e.g.,
"/usr/bin/ls"). - The Catch: The kernel must resolve the path string manually. If a malicious user alters the directories or replaces the file after your program checks it but before the kernel runs it (a Time-of-Check to Time-of-Use or TOCTOU bug), you could execute the wrong file.
fexecve() — The Secure File-Descriptor Execution
- Input Signature:
int fexecve(int fd, char *const argv[], char *const envp[]); - How it works: Instead of a string path, you pass an already-open File Descriptor (
fd) pointing to the binary. - Why use it: This is incredibly secure. Once a process opens a file descriptor to a specific file on the disk, that descriptor locks onto that exact file. Even if an attacker renames, moves, or deletes the original file path on the disk, the file descriptor remains completely unaffected. It is highly favored in secure scripting runtimes, sandboxes, and cryptographic verification loops.
execveat() — The Flexible Hybrid (Relative Paths)
- Input Signature:
int execveat(int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags); - How it works: It combines paths and file descriptors. It evaluates the string
pathnamerelative to the directory represented by the open file descriptordirfd. - Special Superpowers (Flags):
- If you pass an absolute path (like
"/bin/ls"), it ignoresdirfdcompletely and acts exactly likeexecve(). - If you set
pathnameto an empty string""and pass the flagAT_EMPTY_PATH, it executes directly from thedirfdfile descriptor, acting exactly likefexecve(). Under the hood in Linux,fexecve()is actually implemented as a wrapper library function that callsexecveat().
- If you pass an absolute path (like
Summary Feature Comparison
| Function | Core Target Input | Main Use Case | Linux Kernel Introduction |
|---|---|---|---|
execve() |
String Path ("/bin/ls") |
Everyday standard process execution. | Since the beginning (POSIX) |
fexecve() |
File Descriptor (fd) |
Secure execution; prevents TOCTOU exploits. | Added in glibc 2.11 |
execveat() |
Directory Descriptor + Relative Path | Executing binaries within custom sandboxes or containers. | Linux Kernel 3.19 |
Are you looking to implement one of these to prevent a race condition security bug in your code, or are you building a sandbox/container system that restricts absolute paths?