## https://sploitus.com/exploit?id=296ACC10-E41B-5DEC-9F18-8C94AA58D927
# CVE-2026-46331 (pedit COW) – Linux net/sched Packet-Editor Page-Cache Poisoning Vulnerability
## Executive Summary
CVE-2026-46331 (nicknamed **“pedit COW”**) is a local Linux kernel privilege-escalation flaw in the traffic-control subsystem. An unprivileged user (in an unprivileged network namespace) can configure the **`act_pedit`** (packet editor) filter to trigger a *partial copy-on-write (COW) write* into the page cache. In effect, the kernel writes attacker-controlled data into a file’s in-memory image **without marking the page private**, corrupting the cached copy of that file. Crucially, the exploit requires only CAP_NET_ADMIN (obtainable in a user namespace) and does not modify the on-disk file. In practice, a working proof-of-concept (PoC) called *packet_edit_meme* was published on June 17, 2026, demonstrating how to overwrite the page-cache image of a setuid binary (e.g. `/bin/su`) to spawn a root shell. The vulnerability stems from incorrect COW-range calculation in **`tcf_pedit_act()`** and has been fixed upstream (June 4, 2026) by moving the writable-region check into the per-key loop.
- **Affected**: Linux kernels (approx. v5.18 through 7.1-rc6) with `act_pedit`. Unpatched stable releases (including many distro kernels) are vulnerable.
- **Impact**: Local privilege escalation to root by corrupting page cache (page-cache poisoning). CVSS v3.1: 6.0 (Medium, AV:L/AC:L/PR:H/UI:N/C:N/I:H/A:H).
- **Exploit**: The PoC leverages an unprivileged user+network namespace to gain CAP_NET_ADMIN, sets up a `tc` pedit filter, and overwrites the ELF entry point of a setuid binary in memory with shellcode.
- **Mitigation**: Update the kernel (upstream patch moved `skb_ensure_writable()` inside the key loop). As a workaround, block or unload the `act_pedit` module or disable unprivileged user namespaces (e.g. `sysctl user.max_user_namespaces=0`). After mitigation, drop caches (`echo 3 > /proc/sys/vm/drop_caches`) to evict any poisoned pages.
This report provides a detailed technical analysis of CVE-2026-46331: its cause, exploitation, detection, and remediation strategies, with references to vendor advisories, CVEs, and the public exploit.
## Vulnerability Overview
**Definition:** CVE-2026-46331 is an out-of-bounds write bug in the Linux kernel’s *Traffic Control* (`net/sched`) subsystem, specifically in the **`act_pedit`** (packet editor) action. The function **`tcf_pedit_act()`** computes a “copy-on-write” range for packet-edit operations *before* iterating over typed keys, using a static hint `tcfp_off_max_hint`. However, some keys (e.g. TCP/UDP header edits) determine their final byte offset only at runtime. The code never re-checks writability for these dynamic offsets. As a result, writes can occur outside the pre-COW’d region: *part of the packet write is never made private*, leading to a *partial COW*. This erroneous write propagates into the shared page-cache memory of a file (if the packet buffers happen to reference file pages), corrupting the cached file image.
**Background:** The Linux **packet editor (`pedit`)** action allows administrators to rewrite arbitrary bytes within packet headers (link, network, or transport layers) as packets traverse a configured *tc* filter. It works by specifying an offset (possibly anchored to a header) and a 32-bit value/mask. Internally, `pedit` operates on socket-buffers (`sk_buff`) and must make the target packet memory writable before modifying it (via `skb_ensure_writable()` in COW fashion). Ideally, the kernel should clone (private-copy) any shared pages before writing to avoid altering memory used elsewhere.
**Root Cause:** In `tcf_pedit_act()`, the code mistakenly calculates the writable range only once upfront, using `tcfp_off_max_hint` (the maximum static offset). This hint does not include any *runtime header offset* that typed keys add when the packet is being processed. Keys like TCP or UDP can compute an offset based on the position of the IP header at runtime (for example, if an earlier key shifts the network header). Thus, during the per-key loop, the actual offset for a key may exceed the range that was pre-allocated as writable. The code then writes into packet memory via `skb_store_bits()`, but since the page beyond the pre-COW’d region was not made private, the write corrupts a page that is still shared with the page cache. In short, **“calculating the writable packet range too early”** causes an out-of-bounds, cross-page write. Negative offsets (e.g. editing Ethernet headers on ingress) are also mishandled, and even `offset_valid()` lacked a guard for `INT_MIN`, compounding the flaw.
**Why It Happens:** This bug is essentially a logic error in copy-on-write range calculation. The kernel assumed the *static* maximum offset (known at load time) was sufficient for all edits. It failed to update the COW range when keys with dynamic offsets were actually applied. After a series of queued edits, the final write could lie outside the pre-checked region. Because packet buffers may reference memory-mapped file pages (e.g. via zero-copy mechanisms), this “partial COW” write can reach the page cache of a file on disk. In practice, the packet editor action may receive pages from a sendfile or splice; thus a single packet filter operation can indirectly write attacker-chosen data into a file’s in-memory image, without altering the disk.
## Technical Analysis
**Components and Data Flow:** The vulnerable code resides in the Linux **net/sched** subsystem (`act_pedit.c`). When a packet matches a configured `pedit` rule, `tcf_pedit_act()` is invoked. Internally it calls `skb_ensure_writable(skb, X)` exactly once, where `X = tcfp_off_max_hint`. This makes the first `X` bytes of the packet private (COW’d). Then, in a loop over each *key* (edit operation), it computes the key’s actual write offset by adding the *runtime header offset* to the key’s specified offset, and writes a 32-bit value into the packet. In pseudocode:
```c
u32 off_max = action->tcfp_off_max_hint;
skb_ensure_writable(skb, off_max);
for (i = 0; i “Because the skb can reference zero-copy pages pulled in via sendfile, that out-of-bounds write can land in shared page-cache memory backing a real file. The kernel believes it has made the packet memory safe to modify; in reality, the later write reaches outside the region it actually privatized.”
**Trust Boundaries:** The kernel wrongly assumed that `skb_ensure_writable()` (fast-path COW) would guarantee safety for all subsequent writes. It did not re-check for each key. The user only controls packet filter configuration and packet content; the kernel granted that (through network namespaces). Once that trust was breached, the write escaped into file-backed memory that should have been protected.
## Root Cause Analysis
The root cause is **incorrect COW-range calculation in the pedit action**. In code terms, a single `skb_ensure_writable()` was called with a length based on `tcfp_off_max_hint`, then inside the loop the actual offsets could exceed this. A small patch (May 2026) fixes it by moving `skb_ensure_writable()` *inside* the loop, after the true offset is known, and by adding checks and special handling for negative offsets. In other words:
- **Buggy code:**
```c
skb_ensure_writable(skb, action->tcfp_off_max_hint);
for each key:
// compute offset (hdr_off + key_offset)
skb_store_bits(skb, write_off, ...);
```
- **Fixed code:**
```c
for each key:
// compute offset (hdr_off + key_offset)
skb_ensure_writable(skb, write_off + 3);
skb_store_bits(skb, write_off, ...);
```
Additionally, the fix ensures that for negative offsets (Ethernet header edits) it uses `skb_cow()` on headroom, and guards against `INT_MIN` cases. The commit message (stack.watch summary) states: *“Fix by moving skb_ensure_writable() inside the per-key loop where the actual write offset is known, and add overflow checking on the offset arithmetic.”*.
Thus, **why it exists**: during code review or design, the per-key re-calculation was overlooked. The static hint optimization bypassed the need to re-evaluate per key. It appears to be an honest bug rather than a malicious oversight, but its effect is severe because it violates the COW assumption. As TuxCare notes, this bug was merged under the guise of a routine “data corruption” fix, without immediate security context.
## Discovery Process
The vulnerability was introduced by kernel commit **8b796475fd78** (May 2022) and remained unnoticed until early 2026. According to sources, the fix (commit **899ee91156e5** on May 31, 2026) was submitted to the netdev mailing list as an ordinary data-corruption patch. The kernel maintainers merged the fix (net-7.1-rc7) on June 4, 2026. Only on June 16, 2026 was CVE-2026-46331 formally assigned (about two weeks after the patch appeared). A fully weaponized public exploit appeared on June 17, 2026 (the *packet_edit_meme* PoC).
In practice, the sequence was:
- **Fix submitted (mailing list):** May 17, 2026 (Zhang Cen patch)
- **Fix merged upstream:** June 4, 2026 (net-7.1-rc7)
- **CVE assignment:** June 16, 2026 (CNA entered CVE-2026-46331)
- **Public PoC:** June 17, 2026 (packet_edit_meme)
- **Patch rollout:** Late June 2026 in most distros (Red Hat, Debian, Ubuntu, etc.)
Multiple parties noticed the bug by the open patch. For example, Massimiliano Oldani (cybersecurity researcher) published a detailed write-up and exploit shortly after, noting that *“a public, working proof-of-concept exploit named packet_edit_meme appeared on GitHub within 24 hours of CVE assignment”*. CloudLinux, TuxCare, and SentinelOne published analyses once the PoC was public and CVEs assigned. The Debian security tracker and PT DBugs also summarized the issue and available advisories (see References).
## Attack Scenario
A realistic attack requires minimal preconditions:
- **Attacker capabilities:** A local unprivileged user on the target machine. The user must be able to create a new user namespace with network namespace (via `unshare(CLONE_NEWUSER|CLONE_NEWNET)`), which grants CAP_NET_ADMIN inside that namespace without real root privileges. Unprivileged user namespaces are enabled by default on many kernels (e.g. RHEL, Debian) and can be re-enabled on Ubuntu with an `aa-exec` workaround.
- **Target conditions:** The target must be running a vulnerable Linux kernel (approx. 5.18–7.1-rc6) with the `act_pedit` module available. If `act_pedit` is built-in or already loaded, it is immediately exploitable. If it is a module, it auto-loads when a `tc pedit` rule is configured. The target should not have applied the upstream patch. Notably, it is *not* necessary for the attacker to have write access to any file; the exploit works by writing through packet filters.
- **Attack chain:**
1. **Obtain CAP_NET_ADMIN:** The attacker runs something like `unshare --map-root-user --net --pid bash` to create a new user+net namespace. This grants CAP_NET_ADMIN in that namespace (user mapped to root inside).
2. **Set up networking:** The attacker brings up the loopback interface (`ifconfig lo up`) and optionally spawns a listener (e.g. `nc -l 127.0.0.1 9999`). This provides a packet flow to use for TC actions.
3. **Configure TC pedit action:** Using the `tc` command or netlink, the attacker creates a qdisc and filter on `lo` that matches all packets (e.g. `match u32 0 0`) and attaches a `pedit` action with specially crafted keys. Each key has a dynamic header type (e.g. IP header for an L4 offset) and an offset chosen so that the actual write position (header start + offset) lies just beyond the range `skb_ensure_writable()` covered.
4. **Generate traffic:** The attacker sends data (for example, via `echo '' > /dev/udp/127.0.0.1/53`) to trigger the filter. The kernel calls `tcf_pedit_act()`, allocates a COW range, then iterates the keys. At least one key’s write falls outside the pre-COW’d region, causing the write to go into the shared pagecache.
5. **Page-cache poisoning:** In parallel, the attacker has opened a target file (typically a setuid binary) in the socket. For instance, the published PoC mmaps `/bin/su` into the socket via `sendfile` or similar, so the packet buffer references that file’s pages. The out-of-bounds write then corrupts the in-memory copy of `/bin/su` (specifically the ELF entry point).
6. **Privilege escalation:** After the exploit writes its payload, the attacker (or parent process in the original namespace) executes the poisoned binary (`/bin/su`). Because the kernel has inadvertently injected shellcode that does `setgid(0); setuid(0); execve("/bin/sh")`, running `su` drops a root shell. The file on disk was never altered, so no on-disk file integrity tools will show a change.
**Impact:** If successful, the attacker gains full root privileges locally. The exploit can be done in one command and is deterministic. Additionally, corruption of arbitrary file-backed pages could cause denial-of-service (system crash) if used differently. The published PoC specifically overwrote `/bin/su`’s entrypoint with shellcode, but any file the attacker can map could be targeted. The chain requires no special timing or race and has been demonstrated on many distros (RHEL, Ubuntu, Debian, etc.).
## Proof of Concept (PoC)
A public exploit, *packet_edit_meme*, is available on GitHub (sgkdev/packet_edit_meme) and targets `/bin/su`. We describe its essential logic without destructive payloads:
```c
/* Pseudocode outline of the exploit (simplified) */
int main() {
/* 1. Identify a setuid binary (su) and its ELF entry offset */
int fd = open("/bin/su", O_RDONLY);
long entry = elf_entry_offset(fd);
if (entry 1" to /proc/self/uid_map and gid_map, and deny setgroups)
/* 3. Setup environment: bring up loopback and listener */
if (system("ip link set lo up") B[Unshare into user+net namespace(gains CAP_NET_ADMIN)]
B --> C[Configure TC pedit filter on lo]
C --> D{Packet processing by kernel}
D --> E[act_pedit computes wrong COW range]
E --> F[skb_store_bits writes beyond COW'd region]
F --> G[Page cache of target file is corrupted]
G --> H[Attacker executes poisoned setuid binary]
H --> I[Root shell obtained]
```
## Indicators of Compromise (IoCs)
- **Unexpected page-cache writes:** System files (especially executables) showing in-memory alterations without on-disk changes (e.g. hashing tools or integrity monitors would see a mismatch in memory).
- **Module loads:** The `act_pedit` module appears in `lsmod` unexpectedly on systems that don’t normally use tc pedit. (E.g. `lsmod | grep act_pedit` being non-empty on web servers.)
- **`tc` usage:** Unusual `tc` commands or netlink messages from unprivileged processes. Auditing logs may show `CAP_NET_ADMIN` granted to a non-root process.
- **Network listen:** A listener on loopback ports (as the exploit binds a socket to force packet processing). For example, `netstat -tulnp` showing `nc` or custom listener on 127.0.0.1 could be a sign.
- **Kernel logs:** Oops or warnings involving `tcf_pedit_act`, `skb_ensure_writable`, or soft lockups during heavy traffic on loopback or errors in tc processing. (These would be unusual and indicative of corruption.)
- **Dropped privileges logs:** Linux audit logs (`auditd`) showing programs gaining CAP_NET_ADMIN via userns or writing to `/proc/[pid]/uid_map`.
For example, one IOA is **corrupted files in page cache**: a triage checklist might include verifying in-memory file content vs disk, especially for setuid binaries after heavy tc activity. Another is **new namespace creation**: monitoring calls to `unshare(CLONE_NEWUSER|CLONE_NEWNET)` could be flagged. In short, defenders should watch for *any* of: `act_pedit` usage, userns usage, and sudden modifications of executables in RAM.
## Detection
To detect exploitation attempts:
- **SIEM/Log Analysis:** Alert on `tc` configurations or netlink messages that add an `act_pedit` filter. For instance, Sigma rules could look for events containing `TCA_ACT_KIND: pedit` or similar. Monitor audit logs for `capset CAP_NET_ADMIN` from non-root processes, or writes to `/proc/*/uid_map`.
- **IDS/IPS:** Unlikely to have specific signatures (no network signature for a local exploit), but heuristics: traffic with unexpected TCP/UDP packets on loopback concurrent with host integrity alerts. Possibly detect the specific packet edits if instrumentation is possible.
- **EDR:** Watch for processes reading `/bin/su` (or other sensitive binaries) and suddenly executing them in tandem with namespace/unshare syscalls. Alert on any process that both opens a setuid binary and creates a userns.
- **WAF/Network devices:** Not applicable (local attack).
- **File integrity monitoring:** Compare in-memory image of critical binaries to their checksums on disk. If discrepancies occur (and no updates), trigger alert. (As CloudLinux notes, dropping caches after compromise is only containment; real remediation requires rebuilding the host.)
- **Kernel Integrity Tools:** Use Linux Security Modules or eBPF to enforce that only certain processes can attach TC filters, or that `skb_ensure_writable()` cannot be fooled (though no known built-in check exists).
In summary, defenders should log and audit user namespace usage, `tc` commands, and module loads. One key approach: **reject or log any invocation of `tc pedit` by untrusted users**. On compromised hosts, check if `/etc/modprobe.d/disable-act_pedit.conf` has been applied (it should be pre-emptively).
## Mitigation
**Apply Patches:** The primary fix is a kernel update. All major distributions have released updates in June 2026. Upgrading to a patched kernel (Linux 7.1.0 or later, or distro backports) is the definitive solution.
**Configuration Changes:** If patching is not immediately possible, implement mitigations:
- **Disable `act_pedit`:** If your workloads do not require `tc pedit`, blacklist the module. For example:
```
echo 'install act_pedit /bin/true' | sudo tee /etc/modprobe.d/disable-act_pedit.conf
lsmod | grep -w act_pedit && sudo rmmod act_pedit
```
This ensures the action cannot be loaded. (This is recommended by CloudLinux and TuxCare.) Do not apply on hosts that legitimately use `tc pedit`.
- **Restrict User Namespaces:** Remove the unprivileged namespace attack vector. On RHEL/Alma/Debian:
```
sudo sysctl -w user.max_user_namespaces=0
echo 'user.max_user_namespaces = 0' | sudo tee /etc/sysctl.d/99-pedit-cow.conf
```
On Ubuntu 22.04+:
```
sudo sysctl -w kernel.unprivileged_userns_clone=0
echo 'kernel.unprivileged_userns_clone = 0' | sudo tee /etc/sysctl.d/99-pedit-cow.conf
```
This prevents unprivileged users from creating the necessary user namespace to gain CAP_NET_ADMIN. Note: disabling namespaces may break rootless containers and some sandboxed applications.
- **Drop Page Cache (Containment):** If you suspect the exploit ran, the in-memory copies of binaries may be poisoned. Immediately drop caches to evict them:
```
sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
```
This forces pages to be reloaded from disk. *Caveat:* If an attacker already had root, dropping caches won’t remove any persistence they installed. Treat such hosts as compromised.
- **Least Privilege:** Audit and restrict who can use `tc`. The exploit only needs CAP_NET_ADMIN; ensure only trusted admins have this capability. Use RBAC or containerization to limit capability grants.
- **Network Controls:** While not directly networkable, ensure loopback usage is monitored. Firewalling `127.0.0.1` is impractical, but ensure that only localhost traffic is used for TC manipulations.
- **Vendor Advisories:** Refer to official advisories for your OS. Red Hat has RHSA-2026:27354 (and related) for RHEL 8/9/10, Debian has DSA-6355-1, Ubuntu’s CVE page lists fixed kernels, etc. (See References.)
## Remediation
Long-term remediation involves ensuring that all affected systems are on updated kernels. Kernel packages that contain the fix should be installed and systems rebooted. For containers or systems unable to reboot, consider livepatch solutions (e.g. KernelCare) which have prepared patches.
Additionally, system design should assume that user-space accessible kernel interfaces can change over time. Restricting CAP_NET_ADMIN and filtering `tc` usage are good practices beyond this bug.
If a compromise occurred, rebuild the system. The vulnerability *poisons the page cache only*, but an attacker with root may have done other malicious actions; forensic validation is needed. **Do not rely on file-integrity scans after the exploit,** because as noted the PoC leaves on-disk files intact. Rebooting and patching is the safe remediation path.
## Impact Assessment
- **Confidentiality:** *No direct data leak*, since this bug does not read sensitive data out of kernel. It only writes attacker data into memory. CVSS v3.1 rates Confidentiality Impact as **None (C:N)**.
- **Integrity:** **High (I:H)**. An attacker can alter the in-memory contents of arbitrary file-backed pages (e.g. executables, config files) without permission. This allows complete integrity violation of those files in the current running system.
- **Availability:** **High (A:H)**. Overwriting kernel-managed memory or critical data structures could crash processes or the whole system. Even if not exploited for shellcode, the bug could be used to corrupt vital pages and cause denial-of-service.
- **Scope:** Unchanged (vulnerable component = attack vector = victim scope) as the exploit is local.
Given these factors, a typical CVSS v3.1 vector is AV:L/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:H, yielding a **Base Score of 6.0 (Medium)**. Note however that CVSS does not capture that this vulnerability grants *privilege escalation to root*, which in practice is critical. (Some sources computed CVSSv4 for similar bugs; e.g. PT DBugs lists 8.5 on CVSSv4.)
The severity is often rated as **Important/Critical by vendors**. Red Hat’s advisory for this CVE labels it *Important*, and AWS marks it *Medium* (CVSS 6.0). In any case, because root is gained, the practical risk is highest on multi-user or shared systems.
## Related CVEs
This vulnerability belongs to a family of *page-cache poisoning* bugs. Other notable CVEs include:
- **CVE-2022-0847 (“Dirty Pipe”):** A similar LPE bug in Linux 5.8+ where `splice()` on a pipe could write to page cache beyond COW boundaries. It also allowed overwriting files in memory (without disk change).
- **CVE-2016-5195 (“Dirty COW”):** An older flaw in `/proc/self/mem` copy-on-write that allowed local write to read-only mappings.
- **CVE-2020-14386 (“Dirty Frag”):** A flaw in XFRM/ESP packet processing (crypto) that led to cross-page writes in pagecache.
- **CVE-2023-4099 (“Dirty Clone”):** Another netfilter-related kernel bug.
Each of these involves a kernel fast-path writing to memory it believed it exclusively owned, but did not. CVE-2026-46331 is unique in that it occurs in **net/sched pedit action** and leverages user namespaces to bypass privilege restrictions. Unlike DirtyPipe or Dirty COW, no auxiliary privileged process (like a misbehaving system) is needed – a single unprivileged user can trigger it.
## Timeline
- **2022-05-10:** Bug introduced by commit 8b7964… in upstream kernel.
- **2026-05-17:** Patch submitted to netdev mailing list (Zhang Cen).
- **2026-05-31:** Upstream patch (commit 899ee91156e5) completed.
- **2026-06-04:** Patch merged into mainline (net-7.1-rc7).
- **2026-06-16:** CVE-2026-46331 officially assigned.
- **2026-06-17:** Public PoC (*packet_edit_meme*) released.
- **2026-06-19 to 06-26:** Patches and advisories published by vendors (Red Hat RHSA-2026:27xxx series, Debian DSA-6355, Ubuntu USNs, etc.). CloudLinux livepatch and KernelCare updates announced.
- **After 06-26:** Coverage in news, blogs, technical analysis (TuxCare, SentinelOne, etc.) and timeline analysis (Oldani’s write-up).
## References
- Linux kernel patch and NVD summary
- Red Hat/CISA/Ubuntu advisories (via NVD/OSV)
- CloudLinux (CVE-2026-46331 mitigation blog)
- TuxCare analysis (pedit-COW blog)
- SentinelOne Vulnerability DB entry
- CyberPress article on pedit COW
- Positive Technologies DB (dbugs) summary
- Amazon Linux CVE page
- Debian security tracker
- CloudLinux mitigation blog (module blacklist, drop_caches)
*All references are from reputable sources (vendor advisories, published analyses, CVE/NVD entries).*
## Key Takeaways
- **Partial COW is perilous:** Always update COW range for dynamic offsets. In `act_pedit`, calculating writability too early enabled page-cache corruption.
- **User namespaces bypass privileges:** Unprivileged namespaces allowed CAP_NET_ADMIN, letting a local user reach the TC subsystem. Disabling userns can mitigate many emerging kernel exploits.
- **Page cache poisoning is potent:** Unlike disk-based exploits, these attacks leave no traces on disk. File-integrity tools cannot detect them.
- **Defense in depth:** Monitoring TC usage, restricting CAP_NET_ADMIN, and promptly applying kernel patches are essential. Mitigations such as blacklisting modules can buy time before full patch deployment.
- **Vulnerability lifecycle:** The CVE was assigned *after* the fix was public (an “N-day”). This highlights the risk gap between upstream patch and stable release adoption. Organizations should track upstream commits, not just CVEs.