pidfd_getfd(2)
Duplicate a file descriptor out of another process, addressed by its pidfd.
- Since
- Linux 5.6check your kernel →
- glibc
- glibc 2.36
- System
- Linux
- Man page
- pidfd_getfd(2)
Synopsis
#include <sys/syscall.h>
#include <unistd.h>
int syscall(SYS_pidfd_getfd, int pidfd, int targetfd,
unsigned int flags);Rod's take
The /proc/<pid>/fd/N trick is a path lookup keyed on a PID, so it inherits every reuse race PIDs have. pidfd_getfd goes through the stable handle and drops a duplicate of the target's descriptor into your table, sharing offset and flags exactly like dup(2). Unlike SCM_RIGHTS, the other process doesn't get a vote, which is precisely why it's gated on a ptrace attach check. Supervisors and container runtimes want this. Everyone else should be mildly alarmed that it exists.
Flags and arguments that matter
| Name | What it does |
|---|---|
| targetfd | The descriptor number in the target process to duplicate; the copy shares its open file description. |
| flags | Reserved; must be 0, otherwise EINVAL. |
| FD_CLOEXEC | Always set on the returned descriptor. |
| PTRACE_MODE_ATTACH_REALCREDS | Permission check applied: you need ptrace-attach rights over the target. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| EPERM | Caller lacks PTRACE_MODE_ATTACH_REALCREDS permission over the target process. |
| EBADF | pidfd is not a PID fd, or targetfd is not open in the target process. |
| ESRCH | The target process has terminated and been waited on. |
| EINVAL | flags is not 0. |
| EMFILE | Per-process open file descriptor limit reached. |
Example
int pfd = syscall(SYS_pidfd_open, pid, 0);
if (pfd < 0)
err(1, "pidfd_open");
/* copy the target's fd 0; needs ptrace-attach rights over it */
int fd = syscall(SYS_pidfd_getfd, pfd, 0, 0);
if (fd < 0)
err(1, "pidfd_getfd"); /* EPERM, EBADF, ESRCH */
/* fd shares the open file description; FD_CLOEXEC is set */
close(pfd);Trimmed from the full walkthrough in pidfd: Unix finally has a handle on your processes (only took 50 years).
BSD equivalent
none; on FreeBSD and OpenBSD the closest is passing the descriptor with SCM_RIGHTS over a unix(4) socket, which needs the owner's cooperation.
The long version, from the console
Sources
- pidfd_getfd(2), man7.org
- unix(4), FreeBSD
- unix(4), OpenBSD
- glibc 2.36 NEWS (pidfd_open, pidfd_getfd, pidfd_send_signal added)
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
