# CVE-2026-43503 (DirtyClone) – Patch Analysis

## Patch Under Analysis

- **Upstream fix:** `net: skbuff: propagate shared-frag marker through frag-transfer helpers`  
  Commit `48f6a5356a33dd78e7144ae1faef95ffc990aae0` (mainline v7.1-rc5, merged 2026-05-21).  
- **Stable backport tested:** Ubuntu mainline `7.0.10-070010-generic` (package timestamp 2026-05-23).  
- **Files changed (upstream diffstat):**  
  - `net/core/gro.c` (+4 lines)  
  - `net/core/skbuff.c` (+9 lines)  
  - `net/ipv4/tcp_output.c` (+1 line)  

## What the Fix Changes

The patch adds a single flag-propagation line to every helper that moves socket-buffer fragment descriptors from one `sk_buff` to another without also copying the page data:

```c
skb_shinfo(dst)->flags |= skb_shinfo(src)->flags & SKBFL_SHARED_FRAG;
```

Specifically:

1. **`net/core/skbuff.c:__pskb_copy_fclone()`**  
   After copying the source fragment array into the new skb, OR the destination `shinfo->flags` with the source's `SKBFL_SHARED_FRAG` bit.  This is the path used by the netfilter `TEE` target (`nf_dup_ipv4` → `pskb_copy_fclone()`), which is the original DirtyClone trigger.

2. **`net/core/skbuff.c:skb_shift()`**  
   After shifting paged tail bytes from `skb` to `tgt`, propagate the shared-frag marker to `tgt`.  Used by TCP receive coalescing and other paged-data rebalancing paths.

3. **`net/core/skbuff.c:skb_segment()`**  
   Three new propagation points: from the head skb, from the frag-list skb, and from list-skbs during segmentation.  GSO/TSO segmentation therefore no longer drops the marker.

4. **`net/core/gro.c:skb_gro_receive()`**  
   Two propagation points: to the GRO accumulator `p` and, when list processing is involved, to `lp`.  Generic Receive Offload merges fragments from the same flow into an accumulator skb; the merged skb now preserves the shared-frag marker.

5. **`net/core/gro.c:skb_gro_receive_list()`**  
   When a GRO packet is appended as a child of an existing list skb, propagate the marker to the parent.

6. **`net/ipv4/tcp_output.c:tcp_clone_payload()`**  
   When TCP clones payload fragments for a probe or retransmit, preserve the shared-frag marker on the clone.

## Fix Assumptions

The fix relies on the following invariant:

> **Any skb that holds a reference to externally-owned or file-backed page-cache pages must have `SKBFL_SHARED_FRAG` set in `skb_shinfo()->flags`.**

The flag is set by the original DirtyFrag mitigation (`f4c50a4034e6`) when a page-cache page is spliced into a socket via `vmsplice()`/`splice()` zero-copy.  Subsystems that perform in-place writes (XFRM ESP input, `rxrpc`, etc.) call `skb_has_shared_frag()` and, if true, force a copy through `skb_cow_data()` before writing.  The CVE-2026-43503 fix therefore assumes that the only way a destination skb can end up referencing shared pages is through one of these six fragment-transfer helpers, and that adding the OR to each helper is sufficient to maintain the invariant.

The commit message explicitly notes that `skb_copy()` and `skb_copy_expand()` do **not** need changes because they linearize paged data into freshly allocated head storage, emerging with `nr_frags == 0` and therefore `skb_has_shared_frag()` returning false naturally.

## What the Fix Does NOT Cover

### 1. `skb_try_coalesce()` (Fragnesia, CVE-2026-46300)

The CVE-2026-43503 commit does **not** touch `skb_try_coalesce()`.  That helper is fixed by a separate, earlier patch (`[PATCH net] net: skbuff: preserve shared-frag marker during coalescing`, 2026-05-13) which adds the same one-line OR inside `skb_try_coalesce()`.  The two fixes are siblings in the same vulnerability family.

In the tested Ubuntu `7.0.10` stable build, the Fragnesia backport is present, so a Fragnesia-style trigger (ESP-in-TCP over `veth`, using `skb_try_coalesce()` in the TCP receive path) is **blocked**.  If a distro had applied only the CVE-2026-43503 commit without the CVE-2026-46300 commit, Fragnesia would remain exploitable.  That is not a gap in the CVE-2026-43503 patch itself, but it is a gap in any partial backport strategy.

### 2. `skb_zerocopy()` and related zerocopy helpers

`skb_zerocopy()` (used by XDP socket TX, Open vSwitch datapath, and `nfnetlink_queue`) creates references to source fragments without propagating `SKBFL_SHARED_FRAG`.  It relies on `skb_zerocopy_clone()`, which only handles `SKBFL_ZEROCOPY_ENABLE`, not `SKBFL_SHARED_FRAG`.  However, none of the known `skb_zerocopy()` consumers feed the resulting skb into the XFRM ESP input path under the same unprivileged local trust boundary.  Exploiting this would require either:

- a root-configured bridge/router that forwards an XDP/OVS/nfqueue skb into an ESP receive tunnel, or
- a new unprivileged entry point that pushes a zero-copy skb through the ESP input path.

No such entry point is known or tested in this run.

### 3. Future fragment-transfer helpers

The fix is point-solution for the six helpers audited in 2026-05.  Any new kernel code that moves `skb_shared_info` fragments (e.g., new offloads, new tunneling paths, new GRO types) could reintroduce the same bug if the author forgets to copy `SKBFL_SHARED_FRAG`.  The underlying problem is not structural: the kernel still allows a single flag to silently separate "owns the data" from "references external data," and every new fragment-transfer site is a potential regression point.

## Completeness Assessment

For the **specific code paths named in the CVE-2026-43503 advisory**, the patch is complete.  The original DirtyClone trigger (`__pskb_copy_fclone()` via netfilter TEE) and the other five named helpers are now protected.

For the **broader DirtyFrag family**, the patch is incomplete unless paired with the CVE-2026-46300 `skb_try_coalesce()` fix.  The Ubuntu `7.0.10` stable kernel tested here includes both, so the runtime is protected.  A system that cherry-picks only commit `48f6a5356a33` would remain vulnerable to Fragnesia.

For **unknown future variants**, the patch is a heuristic point fix, not a structural invariant.  A more robust long-term fix would be to make the shared-frag marker part of the fragment descriptor itself (or to force `skb_cow_data()` automatically whenever a writer touches a fragment that `skb_has_shared_frag()` could have missed), but that is outside the scope of the CVE-2026-43503 commit.

## Comparison: Before vs After

| Helper | Pre-fix behavior | Post-fix behavior |
|---|---|---|
| `__pskb_copy_fclone()` | clones fragment refs; `SKBFL_SHARED_FRAG` lost on clone | ORs source shared-frag flag into clone |
| `skb_shift()` | moves frags; flag lost on target | ORs source shared-frag flag into target |
| `skb_gro_receive()` | merges frags; flag lost on accumulator | ORs source shared-frag flag into accumulator and `lp` |
| `skb_gro_receive_list()` | appends list skb; flag lost on parent | ORs source shared-frag flag into parent |
| `tcp_clone_payload()` | clones payload frags; flag lost on clone | ORs source shared-frag flag into clone |
| `skb_segment()` | segments frags; flag lost on segments | ORs source shared-frag flag into head/list segments |
| `skb_try_coalesce()` (not in this commit) | coalesces frags; flag lost | Fixed by separate CVE-2026-46300 commit |

## Threat-Model Considerations

The Linux kernel's security model treats local privilege escalation via unprivileged user namespaces as in-scope.  The DirtyClone/Fragnesia family relies on:

1. Unprivileged user+network namespaces (enabled by default on Ubuntu, Debian, Fedora).
2. `CAP_NET_ADMIN` inside the namespace to configure XFRM/ESP and netfilter/veth.
3. `vmsplice()`/`splice()` to attach a page-cache page to a socket as zero-copy data.

The fix does not remove any of these capabilities; it only restores the `SKBFL_SHARED_FRAG` invariant so that the in-place ESP writer knows to copy.  Disabling unprivileged user namespaces remains a valid mitigation, but the patch itself is the intended fix.

## Recommendation for the Coding Stage

If the coding stage is extending the CVE-2026-43503 fix, it should:

1. Ensure the same six propagation lines are present in the target branch (they are in `48f6a5356a33`).
2. Pair the CVE-2026-43503 commit with the CVE-2026-46300 `skb_try_coalesce()` commit, because a partial backport leaves the Fragnesia window open.
3. Add a regression test or static check that warns when `nr_frags` is increased by moving fragment descriptors without a corresponding `SKBFL_SHARED_FRAG` propagation.  This would catch future variants early.
4. Consider hardening `skb_zerocopy()` to propagate `SKBFL_SHARED_FRAG` as well, even though no public exploit path currently reaches the ESP sink from there, because it is a similarly-shaped frag-transfer helper.

## Verdict

The CVE-2026-43503 patch is **complete for the functions it targets**, but it is **not a complete structural fix** for the DirtyFrag family.  The tested `7.0.10` stable kernel is protected because it also carries the CVE-2026-46300 backport.  No bypass of the combined `7.0.10` runtime was demonstrated in this run.
