daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

linux-ptrace-exit-race-pidfd-getfd-fd-theft.md (6198B)


      1 ---
      2 title: "Linux ptrace exit-race pidfdgetfd() FD theft"
      3 section: "Linux"
      4 sectionSlug: "linux-hardening"
      5 sourcePath: "src/linux-hardening/main-system-information/kernel-lpe-cves/linux-ptrace-exit-race-pidfd_getfd-fd-theft.md"
      6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/linux-hardening/main-system-information/kernel-lpe-cves/linux-ptrace-exit-race-pidfd_getfd-fd-theft.md"
      7 sha: "188de82beb54e70956b2952367a0af91d26758b8"
      8 isIndex: false
      9 modified: true
     10 license: "CC-BY-NC-4.0"
     11 ---
     12 
     13 # Linux ptrace exit-race `pidfd_getfd()` FD theft
     14 
     15 A useful **Linux kernel privesc pattern** is to turn a **ptrace authorization bug** into **file descriptor theft** from a privileged process.
     16 
     17 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.<sup>[[1]](#references)[[2]](#references)</sup>
     18 
     19 ## Core idea
     20 
     21 `pidfd_getfd()` duplicates a file descriptor from another process, but first checks ptrace-style permissions against the target.<sup>[[3]](#references)</sup> If that authorization is incorrectly granted during a **teardown window**, an unprivileged attacker can copy:
     22 
     23 - FDs for **sensitive files** already opened by a privileged helper
     24 - FDs for **authenticated IPC channels** already authorized as root
     25 
     26 This transforms a kernel-side authorization bug into a very practical userspace primitive.<sup>[[1]](#references)</sup>
     27 
     28 ## Why the primitive is dangerous
     29 
     30 The attack does **not** need a bug in the privileged helper itself. The helper only needs to temporarily hold something valuable:
     31 
     32 - `/etc/shadow`
     33 - `/etc/ssh/*_key`
     34 - a privileged D-Bus / systemd connection
     35 - any other already-open secret or authorized channel
     36 
     37 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.<sup>[[2]](#references)[[3]](#references)</sup>
     38 
     39 ## Exploitation pattern
     40 
     41 1. Identify a **setuid / setgid / file-capability binary** or **root daemon** that opens sensitive files or keeps useful IPC connections.<sup>[[2]](#references)</sup>
     42 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).<sup>[[2]](#references)[[4]](#references)</sup>
     43 3. Race the process while it is **exiting**, **dropping credentials**, or otherwise entering a state where ptrace access should have become unavailable.<sup>[[2]](#references)</sup>
     44 4. Use `pidfd_open()` + `pidfd_getfd()` to duplicate the target FD during the narrow authorization window.<sup>[[2]](#references)[[3]](#references)[[5]](#references)</sup>
     45 5. Reuse the stolen FD from the unprivileged context.<sup>[[2]](#references)</sup>
     46    - `read()` secrets from a privileged file descriptor
     47    - send requests over a stolen authenticated IPC channel to get **root-side actions**
     48 
     49 Minimal primitive shape.<sup>[[1]](#references)[[3]](#references)[[5]](#references)</sup>
     50 
     51 ```c
     52 int p = pidfd_open(victim_pid, 0);
     53 int stolen = pidfd_getfd(p, victim_fd, 0);
     54 /* use stolen with read()/write()/sendmsg()/ioctl() depending on target */
     55 ```
     56 
     57 ## Practical targets to audit
     58 
     59 Prioritize binaries and daemons that, even briefly, do one of these:<sup>[[1]](#references)[[2]](#references)</sup>
     60 
     61 - open root-only files before finishing privilege transitions
     62 - connect to the **system bus** and keep an already-authorized channel
     63 - pass privileged FDs across helper boundaries
     64 - perform security-sensitive work during `do_exit()`-adjacent teardown
     65 
     66 Good hunting candidates:<sup>[[1]](#references)</sup>
     67 
     68 - password / account management helpers
     69 - SSH helpers
     70 - PolicyKit / D-Bus mediated helpers
     71 - root desktop daemons that expose D-Bus methods
     72 
     73 ## YAMA as an exploit gate
     74 
     75 `kernel.yama.ptrace_scope` is a major practical gate for ptrace-family abuse:<sup>[[3]](#references)[[4]](#references)</sup>
     76 
     77 - `0`: classical same-UID ptrace behavior
     78 - `1`: typically allows parent -> child tracing, which can keep some public exploit paths reachable
     79 - `2`: requires `CAP_SYS_PTRACE` for attach-style access and blocks unprivileged `pidfd_getfd()` abuse in this path
     80 - `3`: disables ptrace attach entirely until reboot
     81 
     82 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.<sup>[[1]](#references)[[2]](#references)[[3]](#references)</sup>
     83 
     84 ## Detection / review ideas
     85 
     86 When auditing privileged Linux software, look for these combinations:
     87 
     88 - **privileged child process** + **attacker-controlled parent**.<sup>[[2]](#references)[[4]](#references)</sup>
     89 - temporary access to **valuable open files**
     90 - temporary access to **authenticated D-Bus/systemd channels**.<sup>[[2]](#references)</sup>
     91 - security decisions that reuse **ptrace-style authorization** outside classic `ptrace(2)`
     92 - kernel APIs that can **duplicate, inherit, or re-export** existing privileged FDs
     93 
     94 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.<sup>[[2]](#references)</sup>
     95 
     96 ## References
     97 
     98 - [1] [CVE-2026-46333: Local Root Privilege Escalation and Credential Disclosure in the Linux Kernel ptrace Path (Qualys)](https://blog.qualys.com/vulnerabilities-threat-research/2026/05/20/cve-2026-46333-local-root-privilege-escalation-and-credential-disclosure-in-the-linux-kernel-ptrace-path)
     99 - [2] [Qualys advisory TXT](https://cdn2.qualys.com/advisory/2026/05/20/cve-2026-46333-ptrace.txt)
    100 - [3] [pidfd_getfd(2) manual page](https://man7.org/linux/man-pages/man2/pidfd_getfd.2.html)
    101 - [4] [Linux kernel Yama documentation](https://www.kernel.org/doc/html/latest/admin-guide/LSM/Yama.html)
    102 - [5] [pidfd_open(2) manual page](https://man7.org/linux/man-pages/man2/pidfd_open.2.html)