execveat(2)
Execute a program via file descriptor instead of path, eliminating the TOCTOU race between verify and exec.
- Since
- Linux 3.19check your kernel →
- glibc
- 2.34
- System
- Linux
- Man page
- execveat(2)
Synopsis
#include <fcntl.h>
#include <unistd.h>
int execveat(int dirfd, const char *pathname,
const char *const argv[], const char *const envp[],
int flags);Rod's take
execveat(2) replaces execve(2)'s path argument with a file descriptor, closing the TOCTOU window between verification and execution. With AT_EMPTY_PATH and an O_PATH fd, you exec exactly the inode you opened, even if the file is later unlinked or replaced. Works with memfds for in-memory ELF execution. glibc wrapper arrived in 2.34; use syscall(2) on older systems.
Flags and arguments that matter
| Name | What it does |
|---|---|
| AT_EMPTY_PATH | When pathname is "", treat dirfd as the file to execute directly. dirfd must reference a regular file (O_PATH or O_RDONLY). Enables exec of an already-open, possibly-unlinked inode. |
| AT_SYMLINK_NOFOLLOW | Fail with ELOOP if the last component of pathname is a symlink. Not applicable with AT_EMPTY_PATH. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| ELOOP | AT_SYMLINK_NOFOLLOW set and last pathname component is a symlink. |
| ENOENT | AT_EMPTY_PATH not set and pathname resolves to nothing. |
| EACCES | Execute permission denied on the file; x bit checked even for O_PATH fds. |
Example
#include <fcntl.h>
#include <unistd.h>
int fd = open("/usr/local/bin/worker", O_PATH);
/* verify the binary here */
char *argv[] = { "worker", NULL };
char *envp[] = { NULL };
execveat(fd, "", argv, envp, AT_EMPTY_PATH);
/* not reached on success */Trimmed from the full walkthrough in execveat(2): execute a binary you already have open.
BSD equivalent
FreeBSD has fexecve(3), which achieves the same result via /dev/fd/N rather than a native syscall. OpenBSD does not expose fexecve.
The long version, from the console
Sources
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
