Compare commits
12 Commits
892d9a31d3
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| aab16fcada | |||
| cb2bc342d1 | |||
| 5bb21af6dd | |||
| 8beafb186f | |||
| 882707286f | |||
| 07995be9d9 | |||
| f3dd525bf6 | |||
| 4bc7ffe2fb | |||
| 7f0f3a1390 | |||
| 979a5d992d | |||
| beeb925e30 | |||
| f2796739b2 |
@@ -8,13 +8,17 @@
|
||||
|
||||

|
||||
|
||||
This document describes the Dirty Frag vulnerability class, first discovered and reported by [Hyunwoo Kim (@v4bel)](https://x.com/v4bel), which can obtain root privileges on major Linux distributions by chaining the `xfrm-ESP Page-Cache Write` vulnerability and the `RxRPC Page-Cache Write` vulnerability.
|
||||
This document describes the Dirty Frag vulnerability class, first discovered and reported by [Hyunwoo Kim (@v4bel)](https://x.com/v4bel), which can obtain root privileges on major Linux distributions by chaining the `xfrm-ESP Page-Cache Write (CVE-2026-43284)` vulnerability and the `RxRPC Page-Cache Write (CVE-2026-43500)` vulnerability.
|
||||
|
||||
Dirty Frag is a case that extends the bug class to which [Dirty Pipe](https://dirtypipe.cm4all.com/) and [Copy Fail](https://copy.fail/) belong. Because it is a deterministic logic bug that does not depend on a timing window, no race condition is required, the kernel does not panic when the exploit fails, and the success rate is very high.
|
||||
|
||||
For detailed technical information and the timeline, [see here](assets/write-up.md).
|
||||
|
||||
Because the embargo has currently been broken, no patch or CVE exists. After consultation with the maintainers on linux-distros@vs.openwall.org and at their request, this Dirty Frag document is being published. For the disclosure timeline, refer to the technical details.
|
||||
- `xfrm-ESP Page-Cache Write (CVE-2026-43284)` was patched in mainline [f4c50a4034e6](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4).
|
||||
- `RxRPC Page-Cache Write (CVE-2026-43500)` was patched in mainline [aa54b1d27fe0](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71).
|
||||
|
||||
> [!NOTE]
|
||||
> At the time this document was first made public (2026-05-07), the embargo had been broken due to external factors, so no patch or CVE existed yet. After consultation with the maintainers on linux-distros@vs.openwall.org at that time, the Dirty Frag document was published at their request. For the disclosure timeline, refer to the technical details.
|
||||
|
||||
# Exploiting
|
||||
|
||||
@@ -26,9 +30,20 @@ git clone https://github.com/V4bel/dirtyfrag.git && cd dirtyfrag && gcc -O0 -Wal
|
||||
|
||||
This PoC is provided as accurate information following consultation with linux-distros. Do not use it on systems that you are not authorized to test.
|
||||
|
||||
## Cleanup
|
||||
|
||||
⚠️ **Important:** After running this exploit, the page cache is contaminated. To clear the polluted page cache and ensure system stability, either run:
|
||||
|
||||
```bash
|
||||
echo 3 > /proc/sys/vm/drop_caches
|
||||
```
|
||||
|
||||
or reboot the system.
|
||||
|
||||
# Affected Versions
|
||||
|
||||
The xfrm-ESP Page-Cache Write vulnerability is in scope from cac2661c53f3 (2017-01-17) up to upstream, and the RxRPC Page-Cache Write vulnerability is in scope from 2dc334f1a63a (2023-06) up to upstream.
|
||||
- **CVE-2026-43284**: xfrm-ESP Page-Cache Write vulnerability is in scope from [cac2661c53f3 (2017-01-17)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cac2661c53f3) up to [f4c50a4034e6 (2026-05-05)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4).
|
||||
- **CVE-2026-43500**: RxRPC Page-Cache Write vulnerability is in scope from [2dc334f1a63a (2023-06-08)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2dc334f1a63a) up to [aa54b1d27fe0 (2026-05-10)](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71).
|
||||
|
||||
In other words, the effective lifetime of the vulnerabilities is about 9 years.
|
||||
|
||||
@@ -44,10 +59,9 @@ This Dirty Frag has been tested on the following distribution versions.
|
||||
|
||||
# Mitigation
|
||||
|
||||
|
||||
1. Because the responsible disclosure schedule and the embargo have been broken, no patch exists for any distribution. Use the following command to remove the modules in which the vulnerabilities occur.
|
||||
```
|
||||
sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; true"
|
||||
1. Use the following command to remove the modules in which the vulnerabilities occur and clear the page cache.
|
||||
```bash
|
||||
sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\ninstall rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; rmmod esp4 esp6 rxrpc 2>/dev/null; echo 3 > /proc/sys/vm/drop_caches; true"
|
||||
```
|
||||
|
||||
2. Once each distribution backports a patch, update accordingly.
|
||||
@@ -72,4 +86,4 @@ Copy Fail was the motivation for starting this research. In particular, xfrm-ESP
|
||||
|
||||
## So, how do I fix my Linux?
|
||||
|
||||
Refer to the Mitigation and [Disclosure Timeline sections](assets/write-up.md). Due to external factors, the embargo has been broken, so no patch exists for any distribution.
|
||||
Refer to the Mitigation section above.
|
||||
|
||||
+18
-13
@@ -30,7 +30,7 @@ Dirty Frag is a vulnerability where the same pattern is reproduced on top of the
|
||||
|
||||
Note that Dirty Frag can be triggered regardless of whether the `algif_aead` module is available. In other words, even on systems where the publicly known Copy Fail mitigation (algif_aead blacklist) is applied, your Linux is still vulnerable to Dirty Frag.
|
||||
|
||||
# xfrm-ESP Page-Cache Write
|
||||
# CVE-2026-43284: xfrm-ESP Page-Cache Write
|
||||
|
||||
## Root Cause
|
||||
|
||||
@@ -178,7 +178,7 @@ By cycling i over 0..47, the 192-byte ELF is fully assembled on top of the page
|
||||
|
||||
## Patch
|
||||
|
||||
The [patch](https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4) sets the `SKBFL_SHARED_FRAG` flag on page frags that came in via `splice` in the IPv4/IPv6 datagram append paths, and in the skip_cow branch of ESP input (`esp_input` / `esp6_input`) it checks this flag so that an skb with externally pinned pages is always routed to the `skb_cow_data` path. As a result, attacker-pinned page cache pages can no longer enter the dst SGL of the in-place AEAD, and page cache modification is blocked.
|
||||
The [patch](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4) sets the `SKBFL_SHARED_FRAG` flag on page frags that came in via `splice` in the IPv4/IPv6 datagram append paths, and in the skip_cow branch of ESP input (`esp_input` / `esp6_input`) it checks this flag so that an skb with externally pinned pages is always routed to the `skb_cow_data` path. As a result, attacker-pinned page cache pages can no longer enter the dst SGL of the in-place AEAD, and page cache modification is blocked.
|
||||
|
||||
```diff
|
||||
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
|
||||
@@ -249,8 +249,10 @@ My v1 patch took the approach of calling `skb_cow_data()` directly in the input
|
||||
- 2026-05-07: Submitted detailed information about the vulnerability and the exploit to the linux-distros mailing list. The embargo was set to 5 days, with an agreement that if a third party publishes the exploit on the internet during the embargo period, the Dirty Frag exploit would be published publicly.
|
||||
- 2026-05-07: Detailed information and the exploit for this vulnerability were published publicly by an unrelated third party, breaking the embargo.
|
||||
- 2026-05-07: After obtaining agreement from distribution maintainers to fully disclose Dirty Frag, the entire Dirty Frag document was published.
|
||||
- 2026-05-08: The [f4c50a4034e6](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f4c50a4034e62ab75f1d5cdd191dd5f9c77fdff4) patch was merged into mainline.
|
||||
- 2026-05-08: This vulnerability was assigned CVE-2026-43284.
|
||||
|
||||
# RxRPC Page-Cache Write
|
||||
# CVE-2026-43500: RxRPC Page-Cache Write
|
||||
|
||||
## Root Cause
|
||||
|
||||
@@ -382,40 +384,41 @@ recvmsg(rxsk_cli, &m, 0)
|
||||
fcrypt_decrypt(page_address(P) + splice_off, ct, K) // 8 byte STORE: page P[splice_off..+8] = fcrypt_decrypt(C, K)
|
||||
```
|
||||
|
||||
Each STORE plants exactly 8 bytes at file offset (`splice_off`). The HMAC/sechdr verification afterward returns `-EPROTO`, but the STORE is already done.
|
||||
Each STORE plants exactly 8 bytes at file offset (`splice_off`). The sechdr verification afterward returns `-EPROTO`, but the STORE is already done.
|
||||
|
||||
For each of the three positions (off = 4, 6, 8), the exploit runs the following sequence in turn: update K, `add_key`, socket setup, handshake, cksum computation, splice + recvmsg. With last-write-wins, chars 4..15 of `/etc/passwd` line 1 are replaced with the shape `"::0:0:GGGGGG:"`. Finally, when the parent process execs `/usr/bin/su -` along with a PTY, `pam_unix.so nullok` of PAM common-auth accepts the empty passwd field and lets it through without a prompt. su then performs `setresuid(0, 0, 0)` and execs `/bin/bash`, dropping into a root shell. This variant does not use `unshare()`, and `add_key()`, `socket(AF_RXRPC)`, `socket(AF_ALG)` (for cksum computation), `splice()`, and `recvmsg()` are all APIs available to unprivileged users.
|
||||
|
||||
## Patch
|
||||
|
||||
A patch for this vulnerability does not exist upstream. The [patch](https://lore.kernel.org/all/afKV2zGR6rrelPC7@v4bel/) that I submitted is as follows:
|
||||
|
||||
The existing code only checked `skb_cloned(skb)` right before the in-place decrypt, so a non-linear skb pinned into the frag via splice reached the decrypt sink as is. This patch adds `|| skb->data_len` to the gate so that non-linear skbs are also isolated via `skb_copy()`.
|
||||
The [patch](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71) extends the gate before in-place decryption from a single `skb_cloned(skb)` check to also catch `skb_has_frag_list(skb) || skb_has_shared_frag(skb)`, so that skbs carrying a chained frag list or externally-shared paged frags are isolated via `skb_copy()` instead of reaching the decrypt sink directly.
|
||||
|
||||
```diff
|
||||
diff --git a/net/rxrpc/call_event.c b/net/rxrpc/call_event.c
|
||||
index fdd683261226..6c924ef55208 100644
|
||||
index fdd683261226..2b19b252225e 100644
|
||||
--- a/net/rxrpc/call_event.c
|
||||
+++ b/net/rxrpc/call_event.c
|
||||
@@ -334,7 +334,7 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)
|
||||
@@ -334,7 +334,9 @@ bool rxrpc_input_call_event(struct rxrpc_call *call)
|
||||
|
||||
if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&
|
||||
sp->hdr.securityIndex != 0 &&
|
||||
- skb_cloned(skb)) {
|
||||
+ (skb_cloned(skb) || skb->data_len)) {
|
||||
+ (skb_cloned(skb) ||
|
||||
+ skb_has_frag_list(skb) ||
|
||||
+ skb_has_shared_frag(skb))) {
|
||||
/* Unshare the packet so that it can be
|
||||
* modified by in-place decryption.
|
||||
*/
|
||||
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
|
||||
index a2130d25aaa9..eab7c5f2517a 100644
|
||||
index a2130d25aaa9..442414d90ba1 100644
|
||||
--- a/net/rxrpc/conn_event.c
|
||||
+++ b/net/rxrpc/conn_event.c
|
||||
@@ -245,7 +245,7 @@ static int rxrpc_verify_response(struct rxrpc_connection *conn,
|
||||
@@ -245,7 +245,8 @@ static int rxrpc_verify_response(struct rxrpc_connection *conn,
|
||||
{
|
||||
int ret;
|
||||
|
||||
- if (skb_cloned(skb)) {
|
||||
+ if (skb_cloned(skb) || skb->data_len) {
|
||||
+ if (skb_cloned(skb) || skb_has_frag_list(skb) ||
|
||||
+ skb_has_shared_frag(skb)) {
|
||||
/* Copy the packet if shared so that we can do in-place
|
||||
* decryption.
|
||||
*/
|
||||
@@ -428,6 +431,8 @@ index a2130d25aaa9..eab7c5f2517a 100644
|
||||
- 2026-05-07: Submitted detailed information about the vulnerability and the exploit to the linux-distros mailing list. The embargo was set to 5 days, with an agreement that if a third party publishes the exploit on the internet during the embargo period, the Dirty Frag exploit would be published publicly.
|
||||
- 2026-05-07: Detailed information and the exploit for the esp vulnerability were published publicly by an unrelated third party, breaking the embargo.
|
||||
- 2026-05-07: After obtaining agreement from distribution maintainers to fully disclose Dirty Frag, the entire Dirty Frag document was published.
|
||||
- 2026-05-08: CVE-2026-43500 was reserved for tracking this vulnerability.
|
||||
- 2026-05-10: The [aa54b1d27fe0](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aa54b1d27fe0c2b78e664a34fd0fdf7cd1960d71) patch was merged into mainline.
|
||||
|
||||
# Chaining
|
||||
|
||||
|
||||
Reference in New Issue
Block a user