Huny's Dev Blog
huny.dev

Linux Kernel UDP Socket UAF (CVE-2026-98276): How sock_gettstamp() and bind() Race to Drop SOCK_RCU_FREE and How to Patch

Understand how CVE-2026-98276 races sock_gettstamp() against bind() to overwrite SOCK_RCU_FREE on Linux UDP sockets, why sysctl and firewalls cannot mitigate it, and how to verify kernel and livepatch fixes.

Hun Jang
Hun Jang Nov 9, 2026

A conceptual illustration showing the socket lock serializing bind() (SOCK_RCU_FREE) and sock_gettstamp() (SOCK_TIMESTAMP) updates on the shared sk_flags word so the RCU grace period is preserved on socket teardown. This is not an actual debugger screenshot.

On November 7, 2026, security teams disclosed active in-the-wild exploitation of CVE-2026-98276 (CVSS 3.1 7.8 High per the Linux Kernel CNA; 7.0 per Red Hat)—a race condition in the Linux kernel's UDP socket implementation that lets an unprivileged local user trigger a deterministic kernel Use-After-Free (crashing the host or escalating privileges to root). Although upstream Linux fixed the flaw in commit 9ed55f3dbef4 ("net: lock the socket in sock_gettstamp()"), an attacker exploited the race on November 4 to crash a production CloudLinux 8 server 12 consecutive times before enterprise distribution patches had rolled out. CVE-2026-98276 Record, CloudLinux Advisory, TuxCare Incident Analysis, AlmaLinux Testing Announcement

The core operational takeaway: there is no sysctl toggle, boot parameter, firewall rule, or filesystem sandbox (such as CageFS) that mitigates CVE-2026-98276. Because any local process or compromised web/container account can trigger the race through its own UDP socket system calls (bind() racing against SIOCGSTAMP / SIOCGSTAMPNS_NEW), you must apply a patched kernel or rebootless livepatch—and verify livepatch status using kcarectl --patch-info | grep CVE-2026-98276 rather than kcarectl --info.

This guide examines the non-atomic bitfield race on sk->sk_flags, the distribution patch matrix, and crash-log forensics based on the NVD CVE-2026-98276 detail, SentinelOne's technical breakdown, and advisories from CloudLinux and TuxCare. It does not execute kernel exploit binaries; the local Python checks below model the read-modify-write lost update on sk_flags and verify livepatch inspection commands.

1. How Racing sock_gettstamp() Against bind() Drops SOCK_RCU_FREE

In the Linux kernel, a socket's behavioral flags share a single memory word (sk->sk_flags) modified via sock_set_flag() and sock_reset_flag(). Because those helpers use non-atomic bit operations (__set_bit() and __clear_bit()), kernel invariants require every caller mutating sk->sk_flags to hold the socket lock.

sock_gettstamp()—the handler behind SIOCGSTAMP and SIOCGSTAMPNS_NEW ioctl requests—violated this rule when enabling timestamping on a socket for the first time:

Timeline Step
CPU 0: bind() → udp_lib_get_port()
CPU 1: ioctl(SIOCGSTAMPNS_NEW) → sock_gettstamp()
Kernel State & Resulting Use-After-Free
Step 1: Concurrent Read
Reads initial sk_flags word F into a register
Reads the same initial sk_flags word F without acquiring the socket lock
Both CPUs start from F (where neither SOCK_RCU_FREE nor SOCK_TIMESTAMP is set)
Step 2: Independent Bitwise OR
Computes F | BIT(SOCK_RCU_FREE), stores it to sk_flags, and publishes the socket to the UDP hash table via sk_add_node_rcu()
Inside sock_enable_timestamp(), computes F | BIT(SOCK_TIMESTAMP)
The UDP socket is now visible to lockless RCU readers in the UDP receive path
Step 3: Lost Update
bind() completes
Writes its stale word F | BIT(SOCK_TIMESTAMP) back to sk_flags
SOCK_RCU_FREE is overwritten and lost! The socket remains published in the RCU hash table without its RCU teardown flag
Step 4: Immediate Free on Close
User space closes the socket; sk_destruct() inspects SOCK_RCU_FREE
Seeing SOCK_RCU_FREE cleared, sk_destruct() frees the socket immediately instead of waiting for an RCU grace period
An in-flight UDP packet in udp_queue_rcv_one_skb → ipv4_pktinfo_prepare dereferences the freed struct sock, causing a slab-use-after-free

How commit 9ed55f3dbef4 fixes the bug: Authored by Eric Dumazet (following a report by Jungwoo Lee and Wongi Lee), the upstream fix acquires the socket lock inside sock_gettstamp() only when SOCK_TIMESTAMP is not yet set—serializing the flag mutation against bind() while keeping subsequent timestamp reads lockless.

2. Why Firewalls, sysctl, and Filesystem Jails Do Not Block the Attack

Two operational boundaries make CVE-2026-98276 particularly dangerous on shared hosting servers, CI runners, and multi-tenant Kubernetes nodes:

  1. Purely local syscall vector: An attacker does not send crafted packets across the network perimeter. Any local user—or an attacker who compromises a single web application or container with shell/code execution—opens a UDP socket locally and races bind() and ioctl(SIOCGSTAMPNS_NEW) across two threads. Perimeter firewalls, WAFs, and filesystem isolation layers such as CageFS never intercept these calls, and no sysctl or kernel boot flag disables sock_gettstamp().
  1. Proven production DoS and reproduced root escalation: On November 4, 2026, an attacker triggered 12 full reboots on a production CloudLinux 8 host configured with kernel.panic_on_oops = 1. While the in-the-wild incident only crashed the server, CloudLinux engineers confirmed that they reproduced both the kernel crash and full local privilege escalation to root in-house.

3. Distribution Patch Matrix, Livepatch Verification, and Crash Forensics

As of November 8, 2026, patch availability varies significantly across enterprise Linux streams:

Distribution / Kernel Stream
Affected?
Fixed Kernel / Rebootless Livepatch Status (as of Nov 8, 2026)
Recommended Action
Debian 12 (bookworm) & Debian 13 (trixie)
Yes
Debian 13 fixed in DSA-6568-1 (Oct 16); Debian 12 fixed in DLA-4841-1 (Oct 17); KernelCare livepatches available
Upgrade via apt update && apt upgrade and reboot, or apply KernelCare update
AlmaLinux 8 / 9 / 10 & CloudLinux 9 / 10
Yes
Fixed kernels published in AlmaLinux testing repository:
EL9: kernel-5.14.0-687.66.2.el9_8
EL10: kernel-6.12.0-211.74.2.el10_2
Enable almalinux-release-testing, run dnf update 'kernel*', and reboot if immediate patching is required
CloudLinux 7h & CloudLinux 8 (Kernel 4.18)
Yes
Fixed kernel 4.18.0-553.184.1.lve.1 in staged rollout;
KernelCare livepatch live on the main feed for CloudLinux 8
Run kcarectl --update for zero-downtime livepatching on CL8, or update kernel with --enablerepo=cloudlinux-rollout-10-bypass and reboot
CloudLinux 8 LTS & 9 LTS (TuxCare ELS)
Yes
Fixed in stable channel since Nov 2:
kernel-lts-5.14.0-284.1101.el8.tuxcare.11.els17 (and .el9) or newer
Run yum update 'kernel*' and reboot; verify els17 or newer in uname -r
Red Hat Enterprise Linux (RHEL 7–10)
Yes
No official fixed RHEL kernel released as of Nov 7, 2026 (rated Moderate 7.0)
Restrict untrusted local code execution and monitor Red Hat errata or livepatch feeds

Use the commands below to apply and verify a KernelCare livepatch (avoiding the --info trap) and to inspect previous boot logs for the exact crash signature:

4. Modeling the Non-Atomic sk_flags Lost Update and Lock Fix in Python

The dependency-free Python script below models why a non-atomic read-modify-write on sk->sk_flags loses SOCK_RCU_FREE when racing against sock_gettstamp(), how locking the first timestamp call preserves both bits, and why livepatch verification scripts must check --patch-info.

Scope Verified Locally

Running the script in a local Python environment verified three boundary cases:

  1. Unsynchronized race (locked_first_call=False): Sets SOCK_TIMESTAMP while clobbering SOCK_RCU_FREE (rcu_free_preserved: False), resulting in uaf_on_close_during_udp_rx: True.
  1. Lock-serialized first call (locked_first_call=True): Preserves both SOCK_RCU_FREE and SOCK_TIMESTAMP, preventing the immediate free on close.
  1. Livepatch command check: Rejects kcarectl --info as insufficient (kcarectl_info_omits_cve_list) and confirms patching only when CVE-2026-98276 appears in kcarectl --patch-info.

5. Infrastructure Hardening Checklist

  • Prioritize multi-tenant hosts and CI/CD build nodes: Any host where untrusted users, customers, or automated jobs can execute local binaries or scripts can reach sock_gettstamp() and crash the kernel.
  • Watch for follow-up patches on sk_set_memalloc() and sk_clear_memalloc(): As noted in commit 9ed55f3dbef4, sk_set_memalloc() and sk_clear_memalloc() also mutate sk_flags without holding the socket lock across callers such as nbd, iSCSI, NVMe over TCP, sunrpc, and WireGuard, and are slated for a separate upstream audit and fix.
  • Enable persistent systemd journals (Storage=persistent): On hosts with kernel.panic_on_oops = 1, persistent journaling ensures that crash traces in ipv4_pktinfo_prepare or udp_destruct_common survive an unexpected reboot for post-incident triage.

References

Last verified: November 9, 2026

Korean version: Linux 커널 UDP 소켓 UAF 취약점(CVE-2026-98276) 해부: sock_gettstamp()와 bind() 경합이 SOCK_RCU_FREE를 지우는 원리와 패치 점검하기Linux 커널 UDP 소켓 UAF 취약점(CVE-2026-98276) 해부: sock_gettstamp()와 bind() 경합이 SOCK_RCU_FREE를 지우는 원리와 패치 점검하기

추천 글