oss-sec mailing list archives

Re: Logic bug in the Linux kernel's __ptrace_may_access() function


From: David Gonzalez <daferna3 () isovalent com>
Date: Fri, 15 May 2026 13:33:56 +0200

[Resending since I don't think my previous response
made it due to incorrect type]

Hi!

From my tests, yama.ptrace_scope of 2 and 3 should mitigate the attack
(as Qualys just confirmed)
Looking at the call graph for sys_pidfd_getfd we can see:

sys_pidfd_getfd ->
    pidfd_getfd ->
        __pidfd_fget ->
            ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS) ->
                __ptrace_may_access

If ptrace_may_access returns an error, the file is not returned.
https://elixir.bootlin.com/linux/v6.19/source/kernel/pid.c#L839

Inside __ptrace_may_access we can see that indeed if mm is NULL,
this end check is skipped (the race the exploit tries to win):
https://elixir.bootlin.com/linux/v6.19/source/kernel/ptrace.c#L341

This is still guarded by the LSM hook though (ptrace_access_check)
YAMA ptrace check yama_ptrace_access_check hooks there:

LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check)

And values 2 and 3 should be sufficient to deny the request:
https://elixir.bootlin.com/linux/v6.19/source/security/yama/yama_lsm.c#L370
(1 doesn't work since the attacker process is the parent
so the call is allowed)

$ ./chage_pwn
[*] round 0
fd 6 -> /etc/shadow (round=0 try=201)
[+] Success! Reading /etc/shadow...
================REDACTED===============
$ sudo sysctl -w kernel.yama.ptrace_scope=2
kernel.yama.ptrace_scope = 2
$ ./chage_pwn
[*] round 0
[!] no hit in this round
[*] round 1
[!] no hit in this round
[*] round 2
[!] no hit in this round
[*] round 3
[!] no hit in this round
[*] round 4
[!] no hit in this round
[*] round 5
...
^C
$ sudo sysctl -w kernel.yama.ptrace_scope=3
kernel.yama.ptrace_scope = 3
$ ./chage_pwne
[*] round 0
[!] no hit in this round
[*] round 1
[!] no hit in this round
[*] round 2
[!] no hit in this round
[*] round 3
[!] no hit in this round
[*] round 4
[!] no hit in this round
[*] round 5
...
^C

Also verified with eBPF (Tetragon) by hooking and blocking
in the same LSM hook:

$ cat /proc/sys/kernel/yama/ptrace_scope
cat: /proc/sys/kernel/yama/ptrace_scope: No such file or directory
$ ./chage_pwn
[*] round 0
fd 6 -> /etc/shadow (round=0 try=20)
[+] Success! Reading /etc/shadow...
================REDACTED===============
$ sudo tetra tp add ../policy.yaml
tracing policy "../policy.yaml" added
$ ./chage_pwn
[*] round 0
[!] no hit in this round
[*] round 1
[!] no hit in this round
[*] round 2
[!] no hit in this round
[*] round 3
[!] no hit in this round
[*] round 4
...

Any LSM using the security_ptrace_access_check should be able
to detect/block this attack as I understand it.
Let me know if I'm missing something or anything here is wrong.

Thanks!
David


Current thread: