Mitigating CVE-2026-53264 (Kernel Traffic Control Use-After-Free) on Rocky Linux and RLC Variants
Introduction
CVE-2026-53264 is a use-after-free in the Linux kernel traffic control action layer (net/sched/act_api.c). When a traffic control action is looked up by index, tcf_idr_check_alloc() finds it in the action idr and raises its reference count while holding only the RCU read lock. A concurrent path that drops the last reference removes the action from the idr and frees it immediately, with no RCU grace period. If the two overlap, the lookup raises a reference count on memory that has already been returned to the allocator.
A public writeup describing the flaw, along with a proof of concept, has been published. This article does not assess whether any particular Rocky Linux or RLC build can be exploited, and no proof of concept was run against a CIQ kernel to produce it.
This article covers Rocky Linux 9 and 10 and the CIQ RLC Pro, RLC Pro LTS, RLC Plus, RLC Pro AI, and RLC Pro Hardened variants. It describes what is affected, current patch status, how to confirm exposure, and how to reduce risk until a patched kernel is available.
Problem
Two ingredients are needed for the race. One thread must be able to reach the action lookup, and another must be able to free an action at the same moment. The kernel normally prevents this by holding the RTNL lock across the whole operation, which serialises every path that touches an action.
There is one exception. Filter operations (RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER) are registered so they can run without RTNL, but they only actually do so when both the queueing discipline and the classifier are flagged as safe to run unlocked. In every affected branch, cls_flower is the only classifier carrying that flag, and sch_ingress (which provides the ingress and clsact queueing disciplines) is the only provider of an unlocked queueing discipline.
That is what makes the mitigation below work. Remove cls_flower and no classifier qualifies for the unlocked path, so the filter handlers fall back to taking RTNL, and the racing pair can no longer form.
Two facts drive triage:
- Capability requirement. Configuring a queueing discipline and filter requires
CAP_NET_ADMIN. On a default system that means root. An unprivileged user can obtainCAP_NET_ADMINinside a user and network namespace (unshare -Urn) when unprivileged user namespaces are enabled, which is the default on Rocky Linux 9 and 10 and on every RLC variant checked for this article. - Module auto-loading. Both
cls_flowerandact_gactare built as modules and are auto-loaded the first time a matching filter or action is created, including from inside a namespace. "We do not usetc" is not by itself a guarantee that the modules cannot be loaded.
This is a networking and kernel flaw and is not architecture-specific.
Treat the following as affected unless they are running a patched kernel:
- Rocky Linux 9.8 and 10.2 community releases
- RLC Pro LTS 8.6, 9.2, and 9.6
- RLC Pro 9 and RLC Pro 10
- RLC Plus 10.2, RLC Pro AI 9.8, and RLC Pro Hardened 9.6
The following are not affected. Their version of tcf_idr_check_alloc() holds the idrinfo lock across both the lookup and the reference count increment, so the racing window does not exist:
- RLC Pro LTS 8.10 and 9.4
- RLC Pro 8
Status
- Fix status: The upstream fix is commit
5057e1aca011,net/sched: act_api: use RCU with deferred freeing for action lifecycle. It defers the free to an RCU callback so the lookup can no longer observe freed memory. It does not change the lookup itself. - CIQ kernels: Patched kernels for the affected RLC and LTS variants are not yet available. Work to land the fix in those branches is in progress. The two CIQ Linux Kernel channels already carry the fix (see the table below).
- Recommended action: apply the module mitigation below if the affected hosts do not rely on
flowerfilters, and install the patched kernel for your variant as soon as it is published. - Open a support case if you need help confirming exposure on your fleet or deciding whether the mitigation is safe for your workload.
Patched Kernels
| Variant | Patched Kernel Version | Status |
|---|---|---|
| RLC Pro LTS 8.6 | Not yet published | Pending |
| RLC Pro LTS 9.2 | Not yet published | Pending |
| RLC Pro LTS 9.6 | Not yet published | Pending |
| RLC Pro 9 (el9_8) | Not yet published | Pending |
| RLC Pro 10 (el10_2) | Not yet published | Pending |
| CIQ Linux Kernel 6.12 | kernel-clk6.12-6.12.98-1.1.el9_clk |
Available |
| CIQ Linux Kernel 6.18 | kernel-clk6.18-6.18.40-1.1.el9_clk |
Available |
For Rocky Linux community releases, check Rocky Linux Errata for patched kernel availability.
Confirming Exposure
Check whether your kernel builds the relevant pieces as modules. On every affected variant checked, both are modules, which is what makes the mitigation applicable:
grep -E '^CONFIG_(NET_CLS_FLOWER|NET_ACT_GACT|NET_CLS_ACT)=' /boot/config-$(uname -r)
Expected output on an affected host:
CONFIG_NET_ACT_GACT=m
CONFIG_NET_CLS_ACT=y
CONFIG_NET_CLS_FLOWER=m
CONFIG_NET_CLS_ACT=y means the action framework itself is built into the kernel and cannot be blocked by any module rule. Only the classifier and the individual actions are modules.
Check whether unprivileged user namespaces are available, since that is how an unprivileged user reaches CAP_NET_ADMIN:
sysctl user.max_user_namespaces
unshare -Urn true && echo "unprivileged userns available"
Check whether the modules are currently resident. This matters for the mitigation, as explained in the next section:
lsmod | grep -E 'cls_flower|act_gact'
Mitigation
Two options. The first is targeted at this flaw. The second is broader defence in depth. Neither replaces the patched kernel.
Option 1: Block the cls_flower and act_gact modules
Suitable for systems that do not use flower filters. See the warning below before applying this to a host running Open vSwitch, anything layered on it, or tc-based traffic shaping.
Create /etc/modprobe.d/blacklist-cve-2026-53264.conf:
blacklist act_gact
blacklist cls_flower
install act_gact /bin/false
install cls_flower /bin/false
The two install lines are the load-bearing part. The kernel requests these modules by name rather than through an alias, and a blacklist line on its own does not stop a by-name request.
This file does not take effect until the modules are unloaded or the host is rebooted. A modprobe.d rule has no effect on a module that is already resident. If cls_flower or act_gact were loaded when the file was written, the host remains exposed until it reboots. This was reproduced on every variant tested. Reboot the host, or if a reboot is not possible and no traffic control configuration is in use, remove the filters and unload the modules:
sudo tc qdisc del dev <interface> clsact
sudo rmmod cls_flower
sudo rmmod act_gact
⚠️ Removing cls_flower is not free. Open vSwitch uses flower filters for its hardware offload path, anything layered on Open vSwitch inherits that, and tc-based filtering and shaping can use flower directly. On a host that uses any of them, this drop-in will break that functionality. Confirm what the host actually does before rolling this out, and test on a non-production host first.
Option 2: Restrict unprivileged user namespaces (defence in depth)
The published attack path relies on obtaining CAP_NET_ADMIN inside an unprivileged user namespace. Disabling them closes that path for unprivileged local users. It does not address the flaw for a process that already holds CAP_NET_ADMIN.
echo 'user.max_user_namespaces = 0' | sudo tee /etc/sysctl.d/99-disable-userns.conf
sudo sysctl --system
⚠️ This breaks rootless containers (Podman and Apptainer) and anything else that relies on user namespaces. Only apply it where nothing on the host uses them.
Verification
After a reboot, confirm the override is being honoured:
modprobe -n -v cls_flower
modprobe -n -v act_gact
Both should print:
install /bin/false
Confirm neither module can be loaded explicitly, and that neither is resident:
sudo modprobe cls_flower ; echo "rc=$?"
lsmod | grep -E 'cls_flower|act_gact' ; echo "resident=$?"
The modprobe should return non-zero and lsmod should match nothing.
Confirm the auto-load path is closed. On an unmitigated host the following succeeds and loads both modules. On a mitigated host it fails:
sudo tc qdisc add dev lo clsact
sudo tc filter add dev lo ingress protocol ip flower action gact drop
Expected output on a mitigated host:
Error: TC classifier not found.
We have an error talking to the kernel
Clean up the test queueing discipline afterwards:
sudo tc qdisc del dev lo clsact
Note that the action framework remains reachable through other classifiers and actions. With the drop-in in place, a filter using the u32 classifier with a mirred action still installs. This is expected. Those classifiers all run under RTNL, so they cannot form the racing pair, but it does mean the mitigation contains the flaw rather than removing the code.
Resolution
Install the patched kernel for your variant when it is published, then reboot:
sudo dnf update kernel*
sudo reboot
Confirm the running kernel afterwards:
uname -r
Once a patched kernel is running, the module drop-in can be removed:
sudo rm /etc/modprobe.d/blacklist-cve-2026-53264.conf
sudo reboot
For hosts that can move to a CIQ Linux Kernel channel, the 6.12 and 6.18 kernels listed above already carry the fix.
Root Cause
tcf_idr_check_alloc() performs its lookup under rcu_read_lock() and then calls refcount_inc_not_zero() on the action it found. The teardown path, __tcf_action_put(), drops the last reference, removes the action from the idr under the idrinfo lock, and then frees it synchronously through tcf_action_cleanup() and free_tcf(), which ends in a bare kfree(). Because the free is not deferred to an RCU grace period, a reader that has already obtained the pointer can raise a reference count on freed memory.
The upstream fix defers that free so it cannot land while a reader still holds the RCU read lock. In branches that are not affected, the reader holds the idrinfo lock across both the lookup and the reference count increment, which excludes the teardown path outright.
Notes
- The
act_gacthalf of the mitigation blocks only the one action the published proof of concept uses. Every other action module reaches the same framework code. Thecls_flowerhalf is what closes the race, because it removes the only classifier that can run a filter operation without RTNL. CONFIG_NET_CLS_ACT=yon all affected variants, so the action framework cannot be blocked with a module rule.- Blocking
sch_ingressinstead would also close the unlocked path, since it is the only provider of an unlockedqdisc, but it is more disruptive because it removes theingressandclsactqueueing disciplines entirely.