A file descriptor number has meaning only inside its process descriptor table, but the kernel object behind that number can be shared across processes. Linux pidfd_getfd() bridges those two scopes: it takes a PID file descriptor plus a descriptor number from the referenced process and installs a duplicate descriptor in the caller. The new descriptor refers to the same open file description as the target descriptor.

That last property is the central boundary. pidfd_getfd() does not reopen a pathname, copy bytes, or create an independent file position. It duplicates an existing kernel reference and therefore inherits sharing semantics that can affect both processes.

Descriptor numbers remain process-local

Suppose process A has descriptor 7 and process B also has descriptor 7. Those integers do not imply any relationship. Each process owns a descriptor table that maps small integers to kernel-managed open file descriptions.

A PID file descriptor identifies a task without relying only on a numeric PID that can later be reused. Given such a pidfd, the operation has the form:

int localfd = syscall(SYS_pidfd_getfd, pidfd, targetfd, 0);

On success, localfd is a newly allocated descriptor number in the calling process. targetfd remains a number interpreted in the process referenced by pidfd. The two integers can differ, and no numeric equality is required.

The current flags contract requires zero. A nonzero value fails with EINVAL, leaving the argument reserved for future extensions.

The duplicate shares an open file description

Linux separates a file descriptor entry from the open file description to which it points. The open file description carries state such as the current file offset and file status flags. Since pidfd_getfd() points the new descriptor at the same open file description, changes to shared state are visible through both descriptors.

For a regular seekable file, an operation that advances the file offset through one descriptor changes the position subsequently observed through the other. File status flags associated with the open file description are shared as well. This is the same class of sharing produced by descriptor duplication, not the state isolation produced by a fresh open().

Descriptor flags are a different layer. The descriptor returned by pidfd_getfd() has FD_CLOEXEC set. That setting belongs to the newly installed descriptor entry rather than to the shared open file description, so it does not impose close-on-exec behavior on the target process descriptor.

The shared object can also be something other than a regular file. If the descriptor refers to a socket, operations available through that socket object can be performed through the duplicate subject to the normal API rules. The syscall therefore transfers usable access to an existing kernel object, not merely metadata describing it.

Access is gated by a ptrace-mode permission check

A process cannot use pidfd_getfd() as an unrestricted descriptor extractor. Linux applies a PTRACE_MODE_ATTACH_REALCREDS access-mode check against the process referenced by the pidfd. Failure of that check produces EPERM.

Ptrace access checks incorporate process credentials, capabilities, target dumpability, and Linux Security Module policy. The exact result can therefore depend on security configuration such as an enabled LSM in addition to UID relationships. Possession of a pidfd alone does not imply permission to duplicate arbitrary descriptors from the referenced process.

This distinction matters for privilege boundaries. A pidfd provides a stable process reference, while the separate access check governs this sensitive cross-process operation. Treating pidfd possession as a general capability for all pidfd-related operations would overstate its authority.

Target descriptor lifetime creates a race boundary

targetfd must still designate an open descriptor in the target process when the syscall executes. If it is not open, the operation fails with EBADF. A target process that concurrently closes and reuses descriptor numbers can therefore change which object a numeric targetfd denotes before the duplication attempt reaches the kernel operation.

The pidfd solves process-identity reuse, not descriptor-number reuse inside that process. A protocol that obtains a descriptor number from external observation still needs a synchronization or ownership rule if it requires that number to keep naming a particular object until duplication occurs.

Once pidfd_getfd() succeeds, later closure of the original target descriptor does not invalidate the caller’s duplicate. The successful call has installed another reference to the same open file description. Its lifetime then follows normal descriptor and underlying-object reference rules.

Resource limits still apply to the caller

Installing the duplicate consumes a descriptor slot in the caller. If the caller has reached its per-process open-descriptor limit, the syscall can fail with EMFILE. Exhaustion of the system-wide open-file resource can produce ENFILE.

These failures occur even when the target descriptor itself is valid and access checks permit duplication. Cross-process acquisition does not bypass descriptor accounting in the receiving process.

If the pidfd is not a valid PID file descriptor, EBADF is also possible. If the referenced process no longer exists after termination and reaping, the documented failure is ESRCH. These cases separate invalid process references from invalid descriptor numbers and permission failures.

SCM_RIGHTS and pidfd_getfd express different transfer models

UNIX domain sockets can transfer descriptors with SCM_RIGHTS. That mechanism requires a socket connection and cooperation from a process that sends the descriptor. The receiver obtains access because the sender explicitly participates in the transfer protocol.

pidfd_getfd() removes that cooperation requirement. The caller names a target process through a pidfd and a descriptor through its target-table number, then the kernel applies the ptrace-mode permission check. This makes it suitable for process supervisors and inspection infrastructure whose authority comes from process relationships or capabilities rather than an application-level descriptor-passing channel.

The difference does not make the two mechanisms interchangeable. SCM_RIGHTS embeds descriptor transfer in an explicit message protocol and can carry descriptors selected by the sender. pidfd_getfd() instead depends on external knowledge of a target descriptor number and on cross-process inspection authority.

Stable process identity does not imply isolated file state

pidfd_getfd() combines a stable process reference with cross-process descriptor duplication, but the result remains a shared reference. The caller receives its own descriptor-table entry and its own FD_CLOEXEC flag, while file offset, file status flags, and the underlying kernel object belong to the shared open file description or object.

That boundary is operationally significant. A supervisor that acquires a descriptor can affect state visible to the target process, and a target process can affect shared state visible to the supervisor. The syscall provides controlled access to an existing object; it does not create a snapshot or an independent handle with detached state.