ArticlesRocky Linux

Mitigating CVE-2026-46331 (act_pedit / "Pedit COW") on Rocky Linux 8, 9, 10, and LTS Variants

cvecve-2026-46331securitykernelnetworkingtraffic controlact_peditrocky linuxltsmitigationtroubleshooting

Arian Cabrera
Customer Support Engineer

Jun 26, 2026

Introduction

CVE-2026-46331 ("Pedit COW") is a local privilege escalation vulnerability in the Linux kernel's traffic control (tc) packet-editing action, act_pedit (net/sched/act_pedit.c). The packet-edit action function, tcf_pedit_act(), computes the copy-on-write (COW) range for skb_ensure_writable() once, before the per-key loop, using the precomputed tcfp_off_max_hint. That hint does not account for the runtime header offset added by typed keys, so part of the target write region is edited without a proper copy-on-write. The result is an out-of-bounds write that can corrupt page-cache memory and be leveraged for root.

Red Hat rates this as Important (CVSS 3.1 base score 7.8, vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H, CWE-787). A public proof-of-concept was released within roughly a day of the CVE being assigned, so treat exposed systems as exploitable until patched or mitigated.

This article covers Rocky Linux 8, 9, and 10 and the CIQ RLC Pro and RLC Pro LTS variants. It describes what is affected, current patch status, how to confirm exposure, and how to reduce risk until a patched kernel is installed.

Problem

act_pedit is the tc action that rewrites bytes in packet headers/payloads. To exploit the flaw, an actor with CAP_NET_ADMIN configures a qdisc/filter with a pedit action whose typed keys push the effective write offset past the region that tcf_pedit_act() made writable. Because skb_ensure_writable() was only asked to COW up to tcfp_off_max_hint — which omits the per-key runtime header offset — the subsequent write lands outside the copied region, an out-of-bounds write into adjacent (potentially page-cache-backed) memory. This is the classic CWE-787 primitive that exploit chains turn into local root.

Two facts drive triage:

  • Capability requirement. Creating the qdisc/filter requires CAP_NET_ADMIN. On a default system that means root. However, an unprivileged user can obtain CAP_NET_ADMIN inside a user+network namespace (unshare -Urn) when unprivileged user namespaces are enabled — which is the default on Rocky Linux 8, 9, and 10. That is the path the public PoC uses, and it is what makes this a meaningful unprivileged-to-root escalation rather than a root-only issue.
  • Module reachability. The vulnerable code lives in act_pedit.ko. The module is auto-loaded the first time a pedit action is created, including from inside a namespace, so "we don't use tc pedit" is not on its own a guarantee that the module cannot be loaded.

This is a networking/kernel flaw, not architecture-specific. It affects x86_64 and arm64 alike. RHEL 7 and earlier (and CIQ Bridge / CentOS 7.9) are not affected by this code path.

Treat the following as affected unless they are running a patched kernel (see Status):

  • Rocky Linux 8, 9, and 10 community releases
  • RLC Pro LTS 8.6, 9.2, and 9.6 (kernel branches CIQLTS-8.6, CIQLTS-9.2, CIQLTS-9.6)
  • RLC Pro 8 (el8_10) and RLC Pro 9 (el9_8) (kernel branches RLC-8, RLC-9)
  • RLC Pro FIPS and Hardened variants built on the affected kernels

Status

  • Fix status: The upstream fix was posted to the netdev list on 2026-05-16 and has landed in mainline and the affected stable branches; Red Hat has shipped errata (RHSA-2026:27704, bulletin RHSB-2026-008). For reference, the Red Hat fixed kernels are kernel-4.18.0-553.136.1.el8_10 (RHEL 8), kernel-5.14.0-687.17.1.el9_8 (RHEL 9), and kernel-6.12.0-211.26.1.el10_2 (RHEL 10).
  • CIQ kernels: CIQ is backporting the fix to the maintained RLC and CIQ LTS kernels. Exact patched CIQ build numbers (NVRs) are tracked in the Patched Kernels table below and will be filled in as builds are released.
  • Recommended action: install the patched kernel for your variant via dnf update kernel* and reboot (see Resolution). If you cannot update immediately, see Mitigation for two verified interim workarounds.
  • Open a support case if you need help confirming exposure on your fleet, validating a patched kernel against your workload, or tracking patch availability for a CIQ variant not yet listed below.

Patched Kernels

Note (awaiting CIQ build numbers): The CIQ NVRs below are pending and will be populated from engineering once the backported builds are released. The RHEL versions in Status are provided as a reference only.

Variant Patched Kernel Version Released
RLC Pro LTS 8.6 (CIQLTS-8.6) pending pending
RLC Pro LTS 9.2 (CIQLTS-9.2) pending pending
RLC Pro LTS 9.6 (CIQLTS-9.6) pending pending
RLC Pro 8 (RLC-8, el8_10) pending pending
RLC Pro 9 (RLC-9, el9_8) pending pending
Rocky Linux 8 (Community) pending pending
Rocky Linux 9 (Community) pending pending
Rocky Linux 10 (Community) pending pending

Confirm what is running on a given system with:

uname -r

If your system reports one of the patched versions above (or newer), the fix is in place and any interim mitigation can be reverted. See Resolution.

Confirming Exposure

Check whether the module is loaded and whether any pedit actions are configured:

lsmod | grep -E '^act_pedit'
tc actions ls action pedit

If lsmod shows nothing and tc actions ls action pedit lists no actions, the vulnerable code is not currently active — but note that the module can still be auto-loaded later (including from inside an unprivileged namespace), so this is a point-in-time check, not a guarantee of safety.

Check whether unprivileged user namespaces are enabled, since that is the path that turns this into an unprivileged escalation:

# Rocky/RHEL 8 (Debian-style toggle is absent; use the max count)
sysctl user.max_user_namespaces
# Quick functional test: succeeds (returns to a shell) if unprivileged userns is allowed
unshare -Urn true && echo "unprivileged user namespaces ENABLED"

Mitigation

The right mitigation depends on whether you use tc pedit and whether you rely on unprivileged user namespaces (e.g. rootless Podman). The two options below can be used independently or together.

Option 1 — Block the act_pedit module (for systems that do not use tc pedit)

⚠️ WARNING This disables the tc pedit packet-editing action entirely. Do not apply it on any system that uses pedit for traffic shaping or header rewriting. It does not affect ordinary networking, other tc actions, GRE, WireGuard, or IPsec. Validate against your network configuration before applying fleet-wide. This is a mitigation, not a fix — revert it once a patched kernel is installed.

Prevent the module from loading so the vulnerable function cannot be reached:

echo "install act_pedit /bin/false" | sudo tee /etc/modprobe.d/cve-2026-46331.conf

If the module is already loaded but no pedit action is active, unload it so the override takes effect immediately:

sudo rmmod act_pedit

If rmmod reports the module is in use, a pedit action still exists. Do not force the unload on a production system; remove the offending tc action during a maintenance window, or install the patched kernel instead.

Option 2 — Restrict unprivileged user namespaces (defense-in-depth)

The unprivileged-to-root path depends on an unprivileged user obtaining CAP_NET_ADMIN inside a user namespace. Disabling unprivileged user namespaces closes that path while leaving legitimate root use of tc pedit intact.

⚠️ WARNING This breaks rootless containers (Podman/Buildah run as a non-root user) and any other workload that relies on unprivileged user namespaces. Only apply where those workloads are absent. Revert once a patched kernel is installed.

echo "user.max_user_namespaces = 0" | sudo tee /etc/sysctl.d/cve-2026-46331.conf
sudo sysctl --system

After applying, the functional test from Confirming Exposure should fail:

unshare -Urn true || echo "unprivileged user namespaces DISABLED"

Verification

If you applied the module block (Option 1), confirm the module is not loaded and the override is honored:

lsmod | grep -E '^act_pedit'
cat /etc/modprobe.d/cve-2026-46331.conf
sudo modprobe -n -v act_pedit

No lsmod output means the module is not currently loaded. modprobe -n -v act_pedit should print install /bin/false. If it instead resolves to a .ko path, re-check that the override file is present and readable.

Resolution

When the patched kernel for your variant is available, install it and reboot.

On Rocky Linux 8, 9, and 10 and the RLC Pro LTS, FIPS, and Hardened variants, the patched kernel comes from the configured CIQ or BaseOS repositories with no additional setup:

sudo dnf update kernel*
sudo reboot

If your RLC Pro variant draws the kernel from the Core Repo via depot channels, refresh metadata and enable the channel that matches your product before updating:

sudo dnf clean all && sudo dnf makecache
sudo depot enable rlc-pro-8   # RLC Pro 8   (use rlc-pro-9 for RLC Pro 9)
sudo dnf update kernel*
sudo reboot

After the reboot, confirm the running kernel matches the published patched version:

uname -r

If you applied either mitigation and you actually need the affected functionality, revert it once the patched kernel is running:

# Revert Option 1 (module block)
sudo rm /etc/modprobe.d/cve-2026-46331.conf
sudo modprobe act_pedit

# Revert Option 2 (user namespaces)
sudo rm /etc/sysctl.d/cve-2026-46331.conf
sudo sysctl --system

Root Cause

The vulnerability is in tcf_pedit_act() in net/sched/act_pedit.c. The function calls skb_ensure_writable() once before the per-key loop, sizing the writable/COW region from tcfp_off_max_hint. That hint is computed without the runtime header offset that typed keys add at execution time, so for a crafted key the actual write offset exceeds the region that was made writable — an out-of-bounds write past the copy-on-write boundary (CWE-787). The upstream fix moves skb_ensure_writable() inside the per-key loop, where the real write offset for each key is known, and adds overflow checking on the offset arithmetic so an oversized offset is rejected rather than written.

Notes

  • Triage tip for scanner hits. Exposure requires the ability to create a pedit action (CAP_NET_ADMIN). The practical unprivileged path is unprivileged user namespaces, which are enabled by default on Rocky 8/9/10. A scanner flagging the kernel version is accurate; the real-world risk is highest where untrusted local users can run code and user namespaces are unrestricted (multi-tenant nodes, shared dev hosts, CI runners).
  • OpenShift. Red Hat notes OpenShift severity is Low because the module is not loaded by default in that environment.
  • Not the same as the page-cache fragmentation CVEs. Although this is also a page-cache corruption primitive, it is unrelated to the Dirty Frag / Fragnesia ESP issues. The act_pedit mitigations here do not address those, and their mitigations do not address this one.
  • Mitigations are interim. Install the patched kernel and revert the workaround as soon as a build is available for your variant.

References & related articles