
CVE-2026-52910 के लिए रेस रिप्रोड्यूसर और स्ट्रेस टूलकिट, जो reuseport cBPF सेलेक्टर प्रोग्राम्स में Linux kernel use-after-free है, dmesg और leak जाँच के साथ।
CVE-2026-52910 के लिए एक रेस रिप्रोड्यूसर और स्ट्रेस टूलकिट, जो Linux kernel के classic BPF (cBPF) reuseport selector प्रोग्राम के हैंडलिंग में एक use-after-free (UAF) है, जिसे upstream में commit "bpf: Free reuseport cBPF prog after RCU grace period" द्वारा ठीक किया गया है।
| CVE | CVE-2026-52910 |
| प्रकार | Use-after-free / out-of-bounds read (CWE-125), CVSS 3.1 7.8 HIGH AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| शुरू हुआ | v4.5 (reuseport cBPF समर्थन के साथ) |
| में ठीक किया गया | 5.10.259, 5.15.210, 6.1.176, 6.6.143, 6.12.94, 6.18.36, 7.0.13 (stable); mainline v7.1 |
| Upstream splat | BUG: KASAN: vmalloc-out-of-bounds in reuseport_select_sock (net/core/sock_reuseport.c:596) |
| रिपोर्ट करने वाले | Eulgyu Kim |
[!WARNING] यह एक kernel स्ट्रेस टूल है। कमजोर kernel पर यह जानबूझकर एक use-after-free रेस विंडो को चौड़ा करता है; एक हिट मशीन को क्रैश या करप्ट कर सकती है। इसे केवल उन मशीनों पर चलाएँ जिनके आप मालिक हैं या जिन्हें परीक्षण के लिए स्पष्ट रूप से अधिकृत किया गया है (टेस्ट VM, अस्थायी CI मशीनें), कभी भी प्रोडक्शन सिस्टम पर नहीं।
SO_REUSEPORT कई sockets को एक ही UDP पोर्ट बाइंड करने देता है; प्रत्येक
आने वाले पैकेट के लिए kernel reuseport_select_sock()
(net/core/sock_reuseport.c) में समूह के एक socket को चुनता है। एक समूह एक
selector प्रोग्राम इंस्टॉल कर सकता है — एक classic BPF प्रोग्राम जो
setsockopt(SO_ATTACH_REUSEPORT_CBPF) के साथ अटैच किया जाता है — जो प्रति
पैकेट तय करता है कि समूह का कौन सा socket इसे प्राप्त करेगा। प्रोग्राम RX
softirq (नेटवर्क रिसीव प्रोसेसिंग) में एक RCU read-side critical section के
अंदर निष्पादित होता है।
बग: जब प्रोग्राम को setsockopt() (reuseport_attach_prog() /
reuseport_detach_prog()) के माध्यम से बदला या डिटैच किया जाता है, तो पुराना
cBPF प्रोग्राम sk_reuseport_prog_free() द्वारा तुरंत फ्री कर दिया जाता
है, बिना इन-फ्लाइट RCU रीडर्स की प्रतीक्षा किए। एक CPU जो अभी भी फ्री किए गए
प्रोग्राम के निर्देशों को चला रहा है, फ्री की गई vmalloc'd मेमोरी पढ़ता है:
sequenceDiagram
autonumber
participant C as CPU0 — churner thread
participant K as setsockopt() path
participant R as CPU1 — RX softirq
R->>R: rcu_read_lock()
R->>R: prog = rcu_dereference(reuse->prog)
C->>K: setsockopt(SO_ATTACH_REUSEPORT_CBPF, progB)
K->>K: swap progA → progB
K->>K: sk_reuseport_prog_free(progA)
Note right of K: unfixed kernels: bpf_prog_free()<br/>runs NOW — no RCU grace period
R->>R: execute progA->insns (run_bpf_filter)
Note right of R: progA was already freed<br/>KASAN: vmalloc-out-of-bounds
Note over K: fix: call_rcu(sk_reuseport_prog_free_rcu) —<br/>free deferred by one RCU grace periodeBPF selector पथ (SO_ATTACH_REUSEPORT_EBPF) प्रभावित नहीं है: यह पहले से
ही प्रोग्राम को deferred bpf_prog_put() चरणों के माध्यम से रिलीज़ करता है।
फिक्स cBPF पथ को भी वही व्यवहार देता है — पुराने प्रोग्राम के फ्री होने से
पहले एक RCU grace period।
Upstream KASAN रिपोर्ट (7.0 डीबग kernel पर):
BUG: KASAN: vmalloc-out-of-bounds in reuseport_select_sock+0xedc/0x1220
Read of size 4 at addr ffffc9000051e004 by task slowme/10208
net/core/sock_reuseport.c:596
एक Linux टेस्ट बॉक्स पर:
$ make
$ sudo ./run_hammer.sh 600 # 10-minute run
...
== result: RC=0 (0 clean / 1 setup / 2 splat / 3 leak / 4 integrity) ==
आवश्यकताएँ:
gcc और bash।dmesg, /proc/vmallocinfo, sysctl);
हैमर स्वयं अनप्रिविलेज्ड चलता है (upstream रिप्रो UID 1000 के रूप में चला)।अपेक्षित परिणाम:
RC=2; कभी-कभी हैमर की
इंटीग्रिटी चेक पहले फायर होती है → RC=4।RC=0, स्थिर bpf_prog vmalloc गिनती।रेस विंडो बहुत छोटी है (फ्री बनाम इन-फ्लाइट RX निष्पादन), इसलिए एकल साफ़ रन को अनिर्णायक मानें। वास्तविक परीक्षण के लिए घंटों चलाएँ, उदाहरण:
$ sudo ./run_hammer.sh 86400 512 8 16 4 127.0.0.1 0
reuseport_race_hammer$ ./reuseport_race_hammer [dur_sec] [insns] [nports] [nsocks] [nsenders] [ip] [ebpf]
प्रत्येक समूह एक churner थ्रेड चलाता है जो एक टाइट लूप में setsockopt()
के माध्यम से cBPF selector को स्वैप और डिटैच करता है, और sender थ्रेड्स
समूह पर 64-बाइट UDP डेटाग्राम फ्लड करते हैं जबकि रिसीवर्स प्रति-socket
डिलीवरी गिनते हैं।
रन चरण (T = dur_sec):
time ──────────────────────────────────────────────────────────────►
[0 ──────────── T-15s) [T-15s ── T-10s) [T-10s ─────────── T]
CHURN + FLOOD SETTLE MEASURE
churner swaps/detaches churn frozen, deterministic program
the selector prog at final program (selects the LAST
max rate under full attached socket): EVERY packet
UDP flood — THE (selects LAST must land on the LAST
race window open socket) socket; snapshot A →
run → snapshot B
इंटीग्रिटी चेक: माप चरण के दौरान अंतिम प्रोग्राम समूह के अंतिम socket को नियतात्मक रूप से चुनता है। यदि उस विंडो के दौरान समूह द्वारा प्राप्त पैकेट सभी उस socket पर नहीं पहुँचे, तो चयन गलत हुआ (KASAN के बिना भी एक संभावित UAF प्रभाव) → exit code 2।
हैमर exit codes: 0 PASS · 1 setup/runtime error · 2 integrity WARN।
run_hammer.sh — वन-रन रैपरहैमर चलाता है और वे जाँचें जोड़ता है जो एकल रन को सार्थक बनाती हैं:
/proc/vmallocinfo में bpf_prog allocation गिनती का स्नैपशॉट लेता है;net.core.optmem_max बढ़ाता है ताकि मल्टी-KB cBPF प्रोग्राम साफ़ तौर पर
अटैच हों;DRAIN (डिफ़ॉल्ट 30s)
प्रतीक्षा करता है;BUG:, Oops:, WARNING:, RIP:,
leaked, stuck);bpf_prog vmalloc गिनती की तुलना करता है (लीक चेक), और
यदि /sys/kernel/debug/kmemleak मौजूद है तो वैकल्पिक रूप से kmemleak
स्कैन करता है।Exit codes: 0 साफ़ · 1 setup त्रुटि (हैमर setup विफलता सहित) ·
2 kernel splat देखा गया · 3 संभावित bpf_prog लीक · 4 हैमर
इंटीग्रिटी WARN।
livepatch_cycle.sh — livepatch लाइफसाइकल परीक्षणफिक्स पुराने cBPF प्रोग्राम को एक call_rcu() कॉलबैक से फ्री करता है। यदि
आप फिक्स को livepatch (kernel live patching — चल रहे kernel में पैच
किया गया कोड) के रूप में शिप करते हैं, तो कॉलबैक फ़ंक्शन स्वयं पैच मॉड्यूल
में रहता है: कॉलबैक के अभी भी लंबित रहते हुए एक revert/unload कॉलबैक के
पैरों के नीचे से मॉड्यूल टेक्स्ट को फ्री कर देता है। यह स्क्रिप्ट apply/revert
चक्रों का अभ्यास करती है जबकि हैमर रेस विंडो को गर्म रखता है, और
/sys/kernel/livepatch/*/transition और dmesg पर नज़र रखती है।
$ MODE=rcu ./livepatch_cycle.sh 20 120 # 20 cycles × 120s hammer each
| मोड | व्यवहार |
|---|---|
cycle (डिफ़ॉल्ट) | apply → revert, दोनों निरंतर हैमर लोड के तहत |
rcu | अधिकतम churn पर revert — ऊपर वाला खतरनाक मामला |
Exit codes: 0 साफ़ · 1 कमांड विफलता · 2 splat या अटका हुआ transition ·
4 हैमर से इंटीग्रिटी WARN।
CI हैमर को दो फ्लैग सेट्स के साथ बिल्ड करता है और स्क्रिप्ट्स पर shellcheck चलाता है। Kernel रनटाइम टेस्ट जानबूझकर साझा CI रनर्स पर नहीं चलाए जाते: रिप्रोड्यूसर को रनर के kernel संस्करण पर नियंत्रण चाहिए (और कमजोर kernel पर रनर को oops कर सकता है)। उन्हें वास्तविक टेस्ट मशीनों पर चलाएँ।
GPL-2.0-only — देखें LICENSE।
| फ़ाइल | उद्देश्य |
|---|
reuseport_race_hammer.c | रिप्रोड्यूसर: मल्टीथ्रेडेड हैमर जो पूर्ण UDP लोड के तहत cBPF selector को churn करता है, फिर डिलीवरी इंटीग्रिटी सत्यापित करता है। |
run_hammer.sh | वन-रन रैपर: net.core.optmem_max बढ़ाता है, हैमर चलाता है, फिर dmesg में splats, /proc/vmallocinfo में लीक हुए bpf_prog allocations, और वैकल्पिक रूप से kmemleak की जाँच करता है। |
livepatch_cycle.sh | हैमर चलते समय फिक्स ले जाने वाला livepatch लागू/रिवर्ट करता है — call_rcu()-आधारित फिक्स के livepatch लाइफसाइकल खतरों की खोज करता है। |
Makefile | हैमर बिल्ड करता है। |
.github/workflows/ci.yml | CI: build + shellcheck (कोई रनटाइम kernel टेस्ट नहीं; देखें CI)। |
| तर्क | डिफ़ॉल्ट | अर्थ |
|---|
dur_sec | 300 (न्यूनतम 45) | कुल रन सेकंड |
insns | 256 | churned cBPF प्रोग्राम में filler निर्देश; बड़ा प्रोग्राम हिट करने के लिए बड़ा फ्री किया गया क्षेत्र है। यदि attach ENOMEM के साथ विफल होता है, तो net.core.optmem_max बढ़ाएँ (रैपर यह आपके लिए करता है)। |
nports | 4 (अधिकतम 64) | reuseport समूह (प्रत्येक एक UDP पोर्ट, 21000 से) |
nsocks | 8 (अधिकतम 512) | प्रति समूह sockets |
nsenders | 4 (अधिकतम 32) | प्रति समूह UDP sender थ्रेड्स |
ip | 127.0.0.1 | लक्ष्य पता; RX softirqs को CPUs (RSS) में फैलाने के लिए एक फिजिकल NIC IP का उपयोग करें |
ebpf | 0 | 1 = SO_ATTACH_REUSEPORT_EBPF attach/detach को भी churn करें (CAP_BPF/CAP_NET_ADMIN चाहिए); वह पथ कमजोर नहीं है, यह तुलना/कवरेज के लिए है |
| Env | डिफ़ॉल्ट | अर्थ |
|---|
HAMMER | ./reuseport_race_hammer | हैमर बाइनरी |
DRAIN | 30 | जाँच से पहले रन के बाद प्रतीक्षा करने के सेकंड |
OPTMEM_MAX | 131072 | net.core.optmem_max के लिए मान; 0 = छूना नहीं |
safe | हैमर रोकें → GRACE स्लीप (डिफ़ॉल्ट 30s, एक grace period) → revert |
| Env | डिफ़ॉल्ट | अर्थ |
|---|
APPLY_CMD / REVERT_CMD | kpatch load $PATCH / kpatch unload $PATCH | livepatch कमांड |
PATCH | ./livepatch-reuseport.ko | पैच मॉड्यूल |
HAMMER | ./reuseport_race_hammer | हैमर बाइनरी |
HAMMER_ARGS | 256 4 8 4 127.0.0.1 0 | हैमर तर्क |
TRANSITION_TIMEOUT | 60 | livepatch transition की प्रतीक्षा के लिए अधिकतम सेकंड |
GRACE | 30 | MODE=safe के लिए grace-period स्लीप |
FORCE | 0 | 1 = भले ही कोई livepatch transition न पाई जाए, चलाएँ |