Impacted Products
-
CubeCOS
Product Status: CubeCOS 3.2.0: not affected. CubeCOS releases prior to 3.2.0: affected.
Fixed In: CubeCOS 3.2.0.
Introduction
This advisory covers CVE-2026-98432
A critical use-after-free vulnerability in the Linux kernel's IPv4 TCP handshake code.
1. Executive Summary
A critical-severity vulnerability (CVE-2026-98432) was identified in the Linux kernel's IPv4 networking subsystem.tcp_v4_syn_recv_sock()hands the IP options of an inbound connection request (ireq->ireq_opt) to the child socket withoobut copying them, while another CPU can still be reading them for a retransmitted SYN or a socket migration. A remote, unauthenticated attacker who sends TCP connection requests that carry IPv4 options, with precise timing, can trigger the race. The result is a kernel crash (denial of service), memory corruption or remote code execution in the kernel. No privileges and no user interaction are needed.
CubeCOS 3.2.0 is not affected.
CubeCOS releases prior to 3.2.0 are affected. Their kernels predate the fix, so every node of such a deployment is exposed as described below. The fix is to update to CubeCOS 3.2.0. The mitigations of Section 5 only reduce exposure until the update is done. Also in scope whatever the release: service images that carry their own kernel (Octavia amphora, Manila share server), and tenant instances, whose guest kernels are the tenants' own.
Impact on an affected release: Every TCP listener served by that kernel is a way in, whatever service owns it. On a cloud node this includes listeners that tenant instances reach directly (the OVN metadata proxy in each ovnmeta-* network namespace) and the listeners of Kubernetes pods. A successful exploit runs in the host kernel, so network namespaces and containers do not contain it.
Description
2. Vulnerability Details
Affected Component:kernel (IPv4 TCP stack,net/ipv4)
Detected Version(s): kernel-7.2.11-1.el9.x86_64 (Vendor: CentOS Kmods SIG, built 2026-10-16), on CentOS Stream release 9; uname -r = 7.2.11-1.el9.x86_64
Patched Version(s): CubeCOS 3.2.0, which ships kernel 7.2.11. The kernel fix itself is in upstream stable 7.2.10 (released 2026-10-11, commit 26d4c36d318c, "ipv4: free inet_opt and ireq_opt after an RCU grace period", upstream e3f33b0a1d89).
Vulnerability Type: CWE-825 (expired pointer dereference; a use-after-free)
Exploitability Status: Exploitation has been demonstrated by the reporters in a Multipath TCP configuration (RHSB-2026-016); whether a public exploit exists requires manual triage (EPSS: 0.76% probability of exploitation in the next 30 days, 55.5th percentile as of 2026-11-08.
Risk Assessment and Exposure
The risk to CubeCOS users
3. Scope of Impact & Runtime Assessment
| Infrastructure Layer | Runtime Component (path) | Affected? | Current Runtime Status / Exposure |
|---|---|---|---|
| Host kernel, root network namespace | Control plane listeners: about 80 TCP ports on a control node (22, 80, 443, 3306, 5672, 6443, 6789, 8774, 9696, ...) | 3.2.0: NO (7.2.11). Prior to 3.2.0: YES | Reachable from the management network. |
| Host kernel, ovnmeta-* namespaces | OVN metadata proxy (169.254.169.254:80), one namespace per tenant network with a port on the node | 3.2.0: NO. Prior to 3.2.0: YES | None existed on the node checked (no instance runs there). Present on nodes that host instances; reachable directly by every tenant instance on that network. |
| Host kernel, Kubernetes pod namespaces (k3s, flannel) | 13 pod namespaces on the node checked (rancher, ceph-csi, fleet, ...) | 3.2.0: NO. Prior to 3.2.0: YES | No NodePort or LoadBalancer service is published; pods are reached from other pods and through the host's own proxies. |
| Service instances built from CubeCOS images | Octavia amphora, Manila share server: their own kernels | (check each image's kernel) | Amphorae terminate tenant and external TCP by design. |
| Tenant instances | Guest kernels | Tenant's own OS | Not in the product's patch scope; see Section 5, Option C. |
Reviewer checklist (answers from the node checked):
- Is the vulnerable feature actually enabled? IPv4 TCP cannot be turned off. Multipath TCP: net.mptcp.enabled = 1, with 40 MPTCP listeners (ss -HMln), 17 of them not on loopback: k3s-server, etcd, thanos, prometheus, cube-cos-api and several exporters.
- Is the real running version what the scan flagged?>uname -r and rpm -q kernel both give 7.2.11-1.el9.x86_64.Repeat on every node of every deployment: a node below 7.2.10 is affected.
- Is any pre-condition the CVE depends on actually configured? The only pre-condition is an inbound TCP connection request carrying IPv4 options reaching a listener. Verified that such packets do reach the node from another network, across a router, when nothing filters them.
- Network Exposure: Internet-Facing | Internal Only | Air-Gapped — (assign manually per deployment and per network: management, provider/public, tenant)
- Privilege Level in Container/Host: Not relevant to the outcome: the flaw is in the kernel, so the privilege of the listening process does not limit the impact.
- Process Execution Path: Not reachable on 3.2.0. On a release prior to 3.2.0, reachable wherever a listener exists.
Customer Actions Required
4. Remediation & Patching Plan
Primary Fix (Permanent)
Update to CubeCOS 3.2.0. That is the fix for every release prior to 3.2.0: 3.2.0 ships kernel 7.2.11, which contains the upstream correction, and every node must be rebooted into it. A deployment already on 3.2.0 needs no change for this CVE. The mitigations in Section 5 reduce exposure until the update is done and do not remove the flaw.
- Target Version: CubeCOS 3.2.0
- Patch Deployment Window: expedited / out-of-band for deployments on a release prior to 3.2.0 (Critical, remote, unauthenticated, reachable from tenant instances): apply Section 5 at once and schedule the update to 3.2.0. None for deployments already on 3.2.0. (decide for the service images after checking their kernels)
- Redeployment Action: Update to 3.2.0 node by node: live-migrate instances away, update, reboot, verify uname -r shows 7.2.11 or later. Rebuild the Octavia amphora and other service images if their kernel is affected, and fail over existing amphorae onto the new image.
5. Temporary Mitigations & Workarounds
For releases prior to 3.2.0, until they are updated to 3.2.0. Source: Red Hat RHSB-2026-016, which recommends dropping inbound IPv4 TCP packets that carry IP options. The rule matches the IPv4 header length, not TCP options, so ordinary TCP (window scaling, SACK, timestamps) is untouched. It is TCP-only: IGMP, which legitimately uses the Router Alert option, and the Geneve overlay (UDP) are not affected.
All three host-side options below were applied, tested and removed again on a 3.2.0 node on 2026-11-09 (nftables 1.0.9, iptables 1.8.10 nf_tables). The exact commands and results are in Section 8.
- Option A — Host filter, root namespace (Red Hat's rule): works as published. With the rule loaded, a TCP connection whose packets carry IPv4 options timed out (from outside and from the node to itself, ports 22 and 443), a normal connection still connected, and the rule's counter rose. It lives in its own nftables table beside the seven iptables-nft tables of the product and Kubernetes and does not change them. It is not persistent: it has to be re-applied at every boot.
- Option B — The listeners Option A does not see: confirmed as gaps, and each closing measure works.
- Another network namespace. With Option A active, a connection with IPv4 options from the root namespace and from a neighbouring pod to a pod's listener still connected. The root table does not apply inside another namespace. Loading the same table inside that namespace made the same connection time out. This is the measure for the ovnmeta-* namespaces; it was tested on a pod namespace because the node checked has no metadata namespace. The metadata agent creates those namespaces on demand, so a new one is unprotected until the rule is loaded into it.
- Forwarded traffic. A prerouting chain with the same rule in the root table stopped pod-to-pod connections with IPv4 options, both on the same node (bridged on cni0; br_netfilter is loaded and bridge-nf-call-iptables = 1) and to a pod on another node (routed through flannel). Normal connections were unaffected. Connections the host itself opens are not filtered by it.
- At the device. An nftables netdev ingress chain on one host-side interface dropped every TCP packet with IPv4 options coming from the workload behind it, before it reached anything else. Tested on a pod's veth as a stand-in for an instance tap device. For instances it needs a hook at port plug, since taps come and go.
- Option C — Network boundary and tenants: Drop IPv4 TCP packets with IP options at the firewall or router in front of the cloud. This also protects tenant instances from outside, which no host rule in the root namespace does: with distributed floating IPs their traffic goes through Open vSwitch and never crosses the host's netfilter hooks. Notify tenants that their guest kernels need their vendor's fix. (not tested)
Not a mitigation: sysctl -w net.mptcp.enabled=0. On an affected kernel it removes the demonstrated way of exploitation only, and only for sockets created afterwards, so the 40 listeners above would need their services restarted.
6. Detection & Indicators of Compromise (IoCs)
(No public IoCs for this CVE are known to this draft — the following are starting points.)
- Log Signatures: Kernel crashes or warnings in the TCP/IPv4 paths on any node: journalctl -k and the crash dumps for general protection fault, KASAN: slab-use-after-free, BUG: or Oops with ip_options_build, ip_build_and_send_pkt, tcp_v4_send_synack, tcp_check_req, tcp_v4_syn_recv_sock or inet_csk_route_req in the trace. An unexplained node reboot counts until explained.
- Runtime Behavior: Legitimate TCP with IPv4 options is rare, so seeing any deserves a look. This capture filter was used in the verification and shows exactly the packets the rule drops: tcpdump -l -ni any 'tcp and tcp[tcpflags] & tcp-syn != 0 and (ip[0] & 0x0f) > 5'. Where the mitigation is loaded, its counter is the detector: nft list table inet cve_2026_98432.
8. Mitigation Steps & Verification
Run as root on the node. Every command below was run on a 3.2.0 node on 2026-11-09; the outputs quoted are the ones observed.
Step 1 — Check whether the running kernel is affected
uname -r # the running kernel: this is what counts
rpm -q kernel
Observed: 7.2.11-1.el9.x86_64 for both. A 7.2 kernel at 7.2.10 or later contains the fix and needs none of the steps below. Continue only for a node below the fixed version, which is the case on releases prior to 3.2.0. The fix for those is the update to 3.2.0; the steps below are the interim mitigation.
Step 2 — Published Mitigation Guidance (Option A)
Save Red Hat's table as cve-2026-98432.nft:
table inet cve_2026_98432 {
chain input {
type filter hook input priority -310; policy accept;
ip protocol tcp ip hdrlength > 5 counter drop
}
}
Check and load it:
nft --check --file cve-2026-98432.nft
nft --file cve-2026-98432.nft
nft list table inet cve_2026_98432
nft list shows the priority as raw - 10, which is the same value as -310.
Additional measures, where they apply (Option B):
# a) the same table inside every OVN metadata namespace (compute nodes)
for ns in $(ip netns list | awk '/^ovnmeta-/ {print $1}'); do
ip netns exec "$ns" nft --file cve-2026-98432.nft
done
# b) traffic forwarded to pods: a prerouting chain in the same table
nft add chain inet cve_2026_98432 prerouting '{ type filter hook prerouting priority -310; policy accept; }'
nft add rule inet cve_2026_98432 prerouting ip protocol tcp ip hdrlength '>' 5 counter drop
# c) at one workload's host-side device (DEV = its tap or veth)
nft -f - <<NFT
table netdev cve_2026_98432_dev {
chain ingress { type filter hook ingress device "$DEV" priority -500; policy accept;
ip protocol tcp ip hdrlength > 5 counter drop
}
}
NFT
None of this survives a reboot. Re-apply it at boot until the kernel is updated.
Step 3 — Services and reboot
The packet filter takes effect at once, for new and existing connections; no service was restarted in the verification. A kernel update takes effect only after a reboot into the new kernel.
Step 4 — Verify the mitigation is active
The test opens an ordinary TCP connection whose packets, the SYN included, carry four bytes of IPv4 options (NOP NOP NOP EOL, header length 6). Save as synopt.py:
#!/usr/bin/env python3
# usage: synopt.py HOST PORT [opt|plain] [timeout]
import socket, sys
host, port = sys.argv[1], int(sys.argv[2])
mode = sys.argv[3] if len(sys.argv) > 3 else 'opt'
tmo = float(sys.argv[4]) if len(sys.argv) > 4 else 4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if mode == 'opt':
s.setsockopt(socket.IPPROTO_IP, socket.IP_OPTIONS, b'\x01\x01\x01\x00')
s.settimeout(tmo)
try:
s.connect((host, port)); print(mode, 'CONNECTED')
except socket.timeout:
print(mode, 'TIMEOUT')
except OSError as e:
print(mode, 'ERROR', e)
finally:
s.close()
Results on the test node (<node-ip>), from a machine outside the cluster unless noted:
| Rules loaded | Test | Result |
|---|---|---|
| none (baseline) | synopt.py <node-ip> 22 opt, also from the node to itself | CONNECTED; tcpdump on the node shows the SYN with header length 6 |
| Option A | synopt.py <node-ip> 22 opt and ... 443 opt | TIMEOUT |
| Option A | synopt.py <node-ip> 22 plain and ... 443 plain | CONNECTED |
| Option A | from the node to itself, opt / plain | TIMEOUT / CONNECTED; counter packets 12 bytes 768 |
| Option A | root namespace to a pod's listener (:80), opt | CONNECTED: not covered |
| Option A | pod to pod on the same node (ip netns exec <pod ns> python3 synopt.py <pod-ip> 80 opt) | CONNECTED: not covered |
| A + table inside the pod's namespace | the two tests above, opt / plain | TIMEOUT / CONNECTED; counter packets 6 in that namespace |
| A + prerouting chain | pod to pod, same node, opt / plain | TIMEOUT / CONNECTED |
| A + prerouting chain | pod to a pod on another node, opt / plain | TIMEOUT / CONNECTED |
| A + prerouting chain | root namespace to a pod, opt | CONNECTED (locally opened connections do not pass prerouting) |
| A + netdev ingress on the pod's veth | from that pod to another pod and to the host's port 22, opt | TIMEOUT; counter packets 6 on the device chain |
| A + netdev ingress on the pod's veth | from that pod to another pod, plain | CONNECTED |
A timed-out test sends the SYN three times in three seconds, so each adds 3 to a counter.
Step 5 — Remove the mitigation
After the update to 3.2.0, or after a test:
nft delete table inet cve_2026_98432 # removes the input and the prerouting chain
nft delete table netdev cve_2026_98432_dev # if c) was used
for ns in $(ip netns list | awk '/^ovnmeta-/ {print $1}'); do
ip netns exec "$ns" nft delete table inet cve_2026_98432
done
nft list tables | grep -c cve # 0
State of the node after removal: the seven original tables only, no cve table in any namespace. iptables-save outside the Kubernetes chains and ip6tables-save were identical to the copy taken before the test. Inside the KUBE-* chains the number of rules was unchanged (518) and their order differed, which is Kubernetes' network policy controller rewriting them for its cron-job pods.
References
Change Log
- Upstream fix released: 2026-10-11 (stable 7.2.10)
- CVE published: 2026-10-15
- Fixed in CubeCOS: 3.2.0 (build CUBE_3.2.0_20261028-1148_d29636ca, kernel 7.2.11)
- Advisory drafted: 2026-11-09
