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)