// HackTricks · Linux

Linux ptrace exit-race pidfdgetfd() FD theft

Linux ptrace exit-race pidfd_getfd() FD theft

A useful Linux kernel privesc pattern is to turn a ptrace authorization bug into file descriptor theft from a privileged process.

In the Qualys __ptrace_may_access() case study (CVE-2026-46333), the attacker races a privileged process that is exiting or dropping credentials and uses pidfd_getfd() to duplicate an FD into the attacker process.[1][2]

Core idea

pidfd_getfd() duplicates a file descriptor from another process, but first checks ptrace-style permissions against the target.[3] If that authorization is incorrectly granted during a teardown window, an unprivileged attacker can copy:

  • FDs for sensitive files already opened by a privileged helper
  • FDs for authenticated IPC channels already authorized as root

This transforms a kernel-side authorization bug into a very practical userspace primitive.[1]

Why the primitive is dangerous

The attack does not need a bug in the privileged helper itself. The helper only needs to temporarily hold something valuable:

  • /etc/shadow
  • /etc/ssh/*_key
  • a privileged D-Bus / systemd connection
  • any other already-open secret or authorized channel

Once duplicated into the attacker process, the duplicate refers to the same open file description, so subsequent reads or IPC requests use the already-open FD rather than reopening the original pathname or starting a fresh authentication flow.[2][3]

Exploitation pattern

  1. Identify a setuid / setgid / file-capability binary or root daemon that opens sensitive files or keeps useful IPC connections.[2]
  2. Gain a relationship that satisfies the relevant ptrace policy checks for the target path (for example, being the parent of a spawned privileged child under permissive YAMA settings).[2][4]
  3. Race the process while it is exiting, dropping credentials, or otherwise entering a state where ptrace access should have become unavailable.[2]
  4. Use pidfd_open() + pidfd_getfd() to duplicate the target FD during the narrow authorization window.[2][3][5]
  5. Reuse the stolen FD from the unprivileged context.[2]
    • read() secrets from a privileged file descriptor
    • send requests over a stolen authenticated IPC channel to get root-side actions

Minimal primitive shape.[1][3][5]

int p = pidfd_open(victim_pid, 0);
int stolen = pidfd_getfd(p, victim_fd, 0);
/* use stolen with read()/write()/sendmsg()/ioctl() depending on target */

Practical targets to audit

Prioritize binaries and daemons that, even briefly, do one of these:[1][2]

  • open root-only files before finishing privilege transitions
  • connect to the system bus and keep an already-authorized channel
  • pass privileged FDs across helper boundaries
  • perform security-sensitive work during do_exit()-adjacent teardown

Good hunting candidates:[1]

  • password / account management helpers
  • SSH helpers
  • PolicyKit / D-Bus mediated helpers
  • root desktop daemons that expose D-Bus methods

YAMA as an exploit gate

kernel.yama.ptrace_scope is a major practical gate for ptrace-family abuse:[3][4]

  • 0: classical same-UID ptrace behavior
  • 1: typically allows parent -> child tracing, which can keep some public exploit paths reachable
  • 2: requires CAP_SYS_PTRACE for attach-style access and blocks unprivileged pidfd_getfd() abuse in this path
  • 3: disables ptrace attach entirely until reboot

For this technique, ptrace_scope=2 is a strong temporary mitigation because it breaks the public pidfd_getfd() exploitation path with -EPERM for unprivileged users.[1][2][3]

Detection / review ideas

When auditing privileged Linux software, look for these combinations:

  • privileged child process + attacker-controlled parent.[2][4]
  • temporary access to valuable open files
  • temporary access to authenticated D-Bus/systemd channels.[2]
  • security decisions that reuse ptrace-style authorization outside classic ptrace(2)
  • kernel APIs that can duplicate, inherit, or re-export existing privileged FDs

When auditing the kernel, treat any path that does ptrace-equivalent authorization during task teardown as high risk, especially if success yields direct access to task->files or other already-authorized process resources.[2]

References