
GhostLock (CVE-2026-43499) OPPO Find X5 Pro (PFEM10) के लिए — OPlus watchdog और heap-spray detector रिवर्स इंजीनियरिंग
English · 中文
ColorOS 16 पर OPPO Find X5 Pro के लिए GhostLock (CVE-2026-43499) पोर्ट। एक uid=0 चाइल्ड प्रोसेस और एक लोडेड kernelsu.ko तक पहुँचता है; रूट प्रोसेस को इंटरसेप्ट किया जाता है।
CVE-2026-43499 — futex PI use-after-free। remove_waiter() current->pi_blocked_on को तब साफ़ करता है जब current requeuer हो, rt_mutex_start_proxy_lock() के -EDEADLK रोलबैक पथ पर।
remove_waiter @ 0xffffffc0081ed254 — pre-fix shape।
| Device | OPPO Find X5 Pro (PFEM10) |
| SoC | SM8450 / Adreno 730 |
| OS | ColorOS 16.0.3.520 (CN01) |
| Kernel | 5.10.236-android12-9-o-gaf2075ad2c06 |
| Bootloader | locked, green |
| VA_BITS | 39 — KIMAGE_TEXT_BASE = 0xffffffc008000000 |
| Stage | |
|---|---|
Compact waiter trigger (CMP_REQUEUE_PI → EDEADLK) | works |
task_struct leak (perf) | works |
PI write (8-byte; value = 0 या एक वैध kernel address) | works |
task+0x778 या task+0x780 अकेले → Uid=root | works — लेकिन एकल-फ़ील्ड लैंडिंग कार्य को विचलित छोड़ देती है, और वह एक latent hard BUG_ON है। देखें the divergence hazard |
| दोनों फ़ील्ड एक ही मान से लिखे गए (एक सुसंगत युग्म) | ❌ sprayed page के साथ कभी उत्पन्न नहीं हुआ। केवल वैश्विक init_cred alias (09-14, CONTROL=1) के साथ देखा गया। runner अब इसे लागू करता है (SAME_VALUE=1); डिवाइस पर नहीं चलाया गया |
Credential laundering (setresgid + setresuid) | V12_LAUNDER=1 के पीछे लागू; डिवाइस पर नहीं चलाया गया |
kernelsu.ko loaded | works |
| Root process survives | ⚠ स्थापित नहीं — नीचे देखें |
| Reboot mechanism | ❌ स्थापित नहीं। एक उम्मीदवार (the divergence) अब बहिष्कृत है; नीचे देखें |
probe_state as a landing criterion | ❌ गलत — उपयोग न करें। तीन प्रति-उदाहरण; नीचे तालिका देखें |
| pstore/ramoops panic channel | ⚠ instrument मौजूद है; channel कभी मान्य नहीं किया गया (अभी तक कोई null test नहीं) |
| "The victim spins in pure userspace" | ⚠ अभी तक कोई रीडिंग नहीं — uid.stream अब utime/stime/nvcsw रिकॉर्ड करता है ताकि इसे जाँचा जा सके |
| pi-side single-pass dual write | ⚠ स्थापित नहीं; pi.pc/pi.left fdset_map.h में hard-coded 0 हैं |
Path A (UMH / modprobe_path) | STATIC_USERMODEHELPER_PATH="" |
"root process survives" पर: evidence/kill.log में रन
uid=0 तक पहुँचते हैं और kernelsu.ko लोड करते हैं, और उस रन में जिसने वास्तव में इसके लिए पोल किया
KernelSU manager प्रोसेस 120 s तक जीवित रहा और kernelsu अभी भी /proc/modules में Live था। बाद के एक रन में वही श्रृंखला
Android framework services को अगम्य छोड़ गई (Can't find service: package/power/input/phone/wifi)
जबकि मॉड्यूल अभी भी Live था। कोई [ROOTCHECK-*] kernel लाइन और कोई $$sys_call_number@@ payload कभी कैप्चर नहीं किया गया, इसलिए बाद के रन की स्थिति का कारण श्रेय नहीं दिया गया। देखें evidence/notes.md
§2.3, §2.4 और §7।
task_struct
| Field | Offset |
|---|---|
real_cred / cred | 0x778 / 0x780 |
cached syscallno | 0xdf8 |
cached uid / euid / gid / egid | 0xe00 / 0xe08 / 0xe10 / 0xe18 |
thread_info
| Field | Offset |
|---|---|
flags | 0x0 |
addr_limit | 0x8 |
ttbr0 | 0x10 |
preempt_count | 0x18 |
cred
| Field | Offset | Field | Offset |
|---|---|---|---|
uid | 0x4 | cap_inheritable | 0x28 |
gid | 0x8 | cap_permitted | 0x30 |
suid | 0xc | cap_effective | 0x38 |
sgid | 0x10 | cap_bset | 0x40 |
euid | 0x14 | cap_ambient | 0x48 |
egid | 0x18 | ||
fsuid / fsgid | 0x1c / 0x20 |
LT perf leak target task_struct → file W7 stage 1 task+0x778 = V (real_cred → private sprayed page; V observed) W7 stage 2 task+0x780 = V (cred) ★ V12_W7_VALUE=V — THE SAME VALUE, not a new page W7 stage 3 V+8 = 0 (LOCAL repair of the page that was installed, ZERO shape) LT child fexecve(memfd of loader) — no execve of a /data path loader ksud late-load → kernelsu ... Live
**चरण 2 को चरण 1 का मान स्पष्ट रूप से दिया जाना चाहिए।** चरण 1 और 2 दो
स्वतंत्र प्रक्रियाएँ हैं, प्रत्येक का अपना स्प्रे है, इसलिए "क्रेड पेज को दोनों
स्लॉट में लिखें" एक जाल है: इसे भोलेपन से पढ़ने पर `(pageA, pageB)` उत्पन्न होता है, और चूँकि
`commit_creds` **पॉइंटर्स** की तुलना करता है, वह युग्म विचलित होता है भले ही दोनों लेखन
सफल हों। यह काल्पनिक नहीं है — यह ठीक वही है जो रन 3 और 9 ने किया:```
run 9 0x778 shot write value = 0xffffff88679bade0
0x780 shot write value = 0xffffff8785d6ade0 <- a different page
run 3 0x778 shot write value = 0xffffff8787b5ade0
0x780 shot write value = 0xffffff881bad2de0 <- a different page
run_bootA.sh इसलिए stage 2 को V12_W7_VALUE=<stage 1's observed value> के साथ चलाता है और यदि वह मान पुनर्प्राप्त नहीं किया जा सकता है तो उसे बिल्कुल भी चलाने से इनकार कर देता है। HOLD को stage 2 से अधिक समय तक जीवित रहना चाहिए, अन्यथा stage 1 का पृष्ठ मुक्त और पुनःआवंटित हो जाता है और "वही मान" एक डैंगलिंग पॉइंटर बन जाता है। देखें
the same-value rule।
प्रति बूट एक पृष्ठ की मरम्मत होती है। Stage 3 V+8 को शून्य करता है। दो भिन्न पृष्ठों के साथ, दोनों को शून्य करने से gid/suid स्टैम्प (नीचे) मिट जाएगा और एक विचलन को सहमति जैसा दिखाएगा, इसलिए रनर केवल उसी पृष्ठ की मरम्मत करता है जो वास्तव में इंस्टॉल किया गया था और यदि दोनों मान असहमत हों तो रुक जाता है।
cred पृष्ठ payload.c द्वारा बनाया जाता है: सभी आठ id फ़ील्ड शून्य, सभी पाँच capability सेट पूर्ण, और user / user_ns / group_info जो root_user / init_user_ns / init_groups की ओर इंगित हैं। Stage 3 इसलिए मौजूद है क्योंकि लेखन का साइड इफ़ेक्ट हमेशा जिस भी cred को इंस्टॉल करता है उसके cred+8 (gid/suid) को क्लॉबर कर देता है।
init_cred पर — एक स्पष्ट द्विभाजनयहाँ दो अनुभाग पहले एक-दूसरे का खंडन करते थे ("कभी भी ग्लोबल init_cred नहीं" बनाम "CONTROL=1 सेल 2 को पुनरुत्पादित करता है", और सेल 2 है init_cred)। दोनों कथन विभिन्न भूमिकाओं के लिए सत्य हैं:
init_cred पॉइंटर लिखने से साइड इफ़ेक्ट init_cred+8 को वैश्विक रूप से भ्रष्ट कर देता है — init_cred हर कर्नेल थ्रेड द्वारा साझा किया जाता है, और Uid: 0 0 4294967176 0 ठीक वही भ्रष्टता है। कोड इस पथ से इनकार करता है जब तक कि V12_ALLOW_INIT_CRED=1 जानबूझकर सेट न किया गया हो।0xffffff802a7e0be0) लिखा, इसलिए real_cred == cred निर्माण से ही — यही कारण है कि यह execve तक जीवित रहा। CONTROL=1 इसे पुनरुत्पादित करता है। यह एक नियंत्रण है, न कि निर्माण करने योग्य कोई कॉन्फ़िगरेशन।perf leak: PERF_TYPE_SOFTWARE / PERF_COUNT_SW_CPU_CLOCK, PERF_SAMPLE_REGS_INTR, exclude_user=1.
[0xffffff8400000000, 0xffffff90000000) स्वीकार करें, वोट ≥ 15%।