
Linux perf/core अनुमति-जाँच बायपास के लिए सत्यापित PoC और विश्लेषण, जो अनधिकृत Android कार्यों को कर्नेल कॉलचेन पते लीक करता है, जिससे KASLR स्लाइड व्युत्पन्न करना संभव हो जाता है।
Linux perf/core अनुमति-जाँच बायपास: एक अपरिविलेज्ड टास्क exclude_kernel=1 सेट करते हुए kernel callchains का अनुरोध कर सकता है, जिससे perf_allow_kernel() गेट को छोड़ दिया जाता है और perf रिंग बफ़र के माध्यम से kernel स्टैक फ़्रेम का खुलासा हो जाता है। इस रिपॉज़िटरी में विश्लेषण और एक सत्यापित PoC शामिल है; यह बग एक सूचना लीक देता है, प्रत्यक्ष विशेषाधिकार-उन्नयन प्रिमिटिव नहीं।
| आइटम | मान |
|---|---|
| CVE | CVE-2026-98937 |
| वर्ग | अनुमति बायपास / सूचना प्रकटीकरण (CWE-284/CWE-269) |
| लक्ष्य | Android arm64 (HONOR YLP-W00 और Redmi K70 पर सत्यापित) |
| Kernel | YLP-W00: 6.12.38-android16-5-gfde7767f6ef6-abogki481467632-4k; K70: 5.15.178-android13-8-00021-g6f2f96be86b9-ab13729987 |
| SELinux | Enforcing (u:r:shell:s0) |
| पैच किया गया | नहीं; 6.12.113 / 6.18.56 / 7.2.10 / 7.3+ में अपस्ट्रीम में ठीक किया गया |
| स्थिति | PoC सत्यापित; KASLR स्लाइड ऑरेकल 6.12.38 और 5.15.178 पर मान्य |
| पूर्व-जाँच | src/vuln_precheck.h |
नीचे दिए गए फ़िक्स से पहले के Kernels प्रभावित हैं। a4b016d0a29038a5b7c96bf62c054bf7832451d9 ("perf/core: Check kernel access when kernel callchains are requested", Dapeng Mi, 2026-06-30 को मर्ज किया गया) और संबंधित स्टेबल बैकपोर्ट्स द्वारा ठीक किया गया।
perf_event_open() पहले kernel प्रोफाइलिंग को केवल !attr.exclude_kernel पर गेट करता था:
if (!attr.exclude_kernel) {
err = perf_allow_kernel(&attr);
if (err)
return err;
}
perf_allow_kernel() में perf_event_paranoid > 1 जाँच और SELinux perf_event { kernel } हुक दोनों शामिल हैं। कोई टास्क exclude_kernel=1 सेट कर सकता है और फिर भी कर्नेल कॉलचेन का अनुरोध कर सकता है (PERF_SAMPLE_CALLCHAIN के साथ exclude_callchain_kernel=0); इसके बाद perf_callchain() सैंपलिंग फ़िल्टर से स्वतंत्र रूप से कर्नेल भाग एकत्र करता है। केवल यूज़र मोड की गणना करने वाले हार्डवेयर PMU इवेंट्स अपना ओवरफ़्लो इंटरप्ट कर्नेल कॉन्टेक्स्ट (स्किड) में ले सकते हैं, इसलिए perf_callchain_kernel() कर्नेल स्टैक को अनवाइंड करता है और कर्नेल टेक्स्ट पते रिंग बफ़र में लिखता है।
यह फ़िक्स तब perf_allow_kernel() को कॉल करता है जब कर्नेल सैंपलिंग या कर्नेल कॉलचेन में से किसी एक का अनुरोध किया जाता है:
if (!attr.exclude_kernel ||
((attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
!attr.exclude_callchain_kernel)) {
err = perf_allow_kernel();
if (err)
return err;
}
ऊपर दिया गया स्निपेट 6.12.113 stable-tree रूप है, जिसमें
perf_allow_kernel() अब किसी attribute pointer को नहीं लेता; upstream
commit उसी शर्त का उपयोग perf_allow_kernel(&attr) के साथ करता है।
पूर्ण call path, skid mechanics, SELinux audit साक्ष्य और device मापों के लिए
docs/analysis.md देखें।
PoC एक unprivileged shell प्रक्रिया के रूप में तीन केस चलाता है:
| केस | perf_event attributes | कमज़ोर kernel पर अपेक्षित |
|---|---|---|
| A | exclude_kernel=0 | EACCES (kernel-perf gate सक्रिय) |
| B | exclude_kernel=1, exclude_callchain_kernel=1 | event अनुमत, कोई kernel callchain फ़्रेम नहीं |
| C | exclude_kernel=1, exclude_callchain_kernel=0 | event अनुमत, kernel callchain फ़्रेम उजागर |
सत्यापित YLP-W00 (kernel 6.12.38, SELinux Enforcing) पर:
EACCES, audit लॉग में
avc: denied { kernel } ... tclass=perf_event के साथ।0xffffffde...
kernel रेंज में।सत्यापित Redmi K70 (kernel 5.15.178, third-party Android 17 ROM, SELinux Enforcing) पर भी वही पैटर्न देखा गया:
EACCES, वही SELinux { kernel } audit पंक्ति।0xffffffdd...
kernel रेंज में।सत्यापित डिवाइसों पर, एक fixed kernel केस C को
perf_event_open() पर EACCES के साथ अस्वीकार कर देगा क्योंकि kernel-callchain
अनुरोध अब perf_allow_kernel() तक पहुँचता है।
मिलते-जुलते vmlinux के साथ, लीक हुए callchain फ़्रेम प्रति-बूट KASLR
slide oracle बन जाते हैं। arm64 virtual slide 2 MiB aligned होता है, और हर लीक हुए text
पते को _stext <= addr - slide < _etext संतुष्ट करना चाहिए; उन अंतरालों का
प्रतिच्छेदन सामान्यतः ठीक एक slide छोड़ता है।
make slide \
SLIDE_VMLINUX=/path/to/vmlinux-6.12.38.elf \
SLIDE_LINK_BASE=0xffffffc080000000 \
SLIDE_LOG=logs/poc-ylp-w00-20261027-020133-period1000.log
सत्यापित YLP-W00 6.12.38 बूट पर, तीन फ़्रेम अद्वितीय
slide=0x1DCFC00000 (रनटाइम _text=0xffffffde4fc00000) देते हैं:
| लीक हुआ पता | लिंक-टाइम पता | प्रतीक |
|---|---|---|
0xffffffde50748c78 | 0xffffffc080b48c78 | local_daif_restore+0x4 (msr DAIF, x0; ret) |
0xffffffde50d406e0 | 0xffffffc0811406e0 | el0t_64_sync_handler+0x70 (bl el0_svc के बाद) |
0xffffffde4fc11588 | 0xffffffc080011588 | el0t_64_sync+0x1a8 (bl el0t_64_sync_handler के बाद) |
ये कोर कर्नेल टेक्स्ट फ़्रेम हैं, मॉड्यूल नहीं: लंबित PMU इंटरप्ट सिस्टम कॉल एंट्री
पथ में msr DAIF, x0 के बाद ठीक ret पर डिलीवर होता है। KASLR के अंतर्गत कच्चे
पतों को सीधे प्रतीकित नहीं किया जा सकता;
पहले स्लाइड घटाएँ। यदि कोई फ़्रेम मॉड्यूल पता है, तो कोई भी स्लाइड सभी
पतों को [_stext, _etext) में नहीं रखती और स्क्रिप्ट अनुमान लगाने के बजाय यही रिपोर्ट करती है। स्लाइड हर बूट पर बदलती है और इसे
रीबूट्स के बीच कैश नहीं किया जाना चाहिए।
Redmi K70 (5.15.178) को भी सत्यापित किया गया है। इसकी मिलती-जुलती इमेज
/sdcard/boot.img से निकाली गई (boot v4; एम्बेडेड वर्ज़न स्ट्रिंग चल रहे कर्नेल से मेल खाती है) और vmlinux-to-elf ने 158,668 प्रतीक पुनःप्राप्त किए। एक period-1000 रन के सात अद्वितीय
फ़्रेम slide=0x1D93800000 (रनटाइम
_text=0xffffffdd9b800000) देते हैं, जो syscall_trace_enter,
el0_svc_common, do_el0_svc, el0_svc, el0t_64_sync_handler,
el0t_64_sync, और syscall_trace_exit पर मैप होते हैं।
लिंक-टाइम बेस ब्रांच-विशिष्ट है — 6.12 मान को 5.15 पर पुनः उपयोग न करें:
| कर्नेल ब्रांच | KIMAGE_VADDR |
|---|---|
| Android 13-5.15 (K70) | 0xffffffc008000000 |
| Android 16-6.12 (YLP-W00) | 0xffffffc080000000 |
| upstream v5.15 (भिन्न लेआउट) | 0xffffffc010000000 |
vmlinux-to-elf ने K70 इमेज के लिए 0xffffffc008000000 का स्वतः पता लगाया, जो
AOSP android13-5.15 से मेल खाता है। यदि स्वतः-पता लगाया गया ELF बेस ब्रांच के
KIMAGE_VADDR से भिन्न है, तो --link-base (या SLIDE_LINK_BASE=) पास करें: प्रतीकीकरण ELF स्पेस में रहता है, रिपोर्ट की गई स्लाइड को वास्तविक बेस के सापेक्ष बनाया जाता है, और
रनटाइम _text एक स्थिर बेस शिफ्ट के प्रति अपरिवर्तनीय रहता है। K70 लीक को
6.12.38 इमेज में फीड करना एक जानबूझकर किया गया नेगेटिव टेस्ट बना हुआ है और कोई उम्मीदवार नहीं देता।
आवश्यकताएँ:
/opt/android-ndk-r29 पर Android NDK r29 (NDK= से ओवरराइड करें)make # PoC, arm64, API 24
make ARCH=arm API=29 # other ABI / API level
make host # static build for qemu-aarch64
make emu # build and run the static PoC locally
make help
आर्टिफ़ैक्ट्स build/ में लिखे जाते हैं और git-ignored होते हैं।
make check # push + read-only environment pre-check
make run # push + full three-case verification
# directly
adb push build/poc /data/local/tmp/poc
adb shell chmod 755 /data/local/tmp/poc
adb shell /data/local/tmp/poc --check
adb shell /data/local/tmp/poc --duration 2 --period 1000
विकल्प:
--check pre-check only, no perf event is opened
--force run on an unlisted kernel release
--duration N sampling seconds per case (default 2)
--period N sample period in cycles (default 1000)
एग्ज़िट कोड: