Adreno A7xx SDS->RB privilege bypass (GPU SMMU takeover to Kernel R/W)

Tip

AWS हैकिंग सीखें और अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP हैकिंग सीखें और अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE) Azure हैकिंग सीखें और अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks का समर्थन करें

यह पृष्ठ एक इन-द-वाईल्ड Adreno A7xx माइक्रोकोड लॉजिक बग (CVE-2025-21479) को पुनरुत्पादनीय exploitation तकनीकों में सारगर्भित करता है: Set Draw State (SDS) में IB-स्तर की masking का दुरुपयोग करके एक अनप्रिविलेज्ड ऐप से privileged GPU packets को निष्पादित करना, GPU SMMU takeover की ओर pivot करना और फिर एक dirty-pagetable ट्रिक के माध्यम से तेज़, स्थिर kernel R/W तक पहुँचना।

  • प्रभावित: Qualcomm Adreno A7xx GPU firmware वह जो उस माइक्रोकोड फिक्स से पहले है जिसने register $12 के मास्क को 0x3 से 0x7 में बदला।
  • Primitive: SDS (यूजर-नियंत्रित) से privileged CP packets (उदा., CP_SMMU_TABLE_UPDATE) चलाना।
  • Outcome: मनमाफिक physical/virtual kernel memory R/W, SELinux अक्षम करना, और root प्राप्त करना।
  • Prereq: KGSL GPU context बनाने और ऐसे command buffers सबमिट करने की क्षमता जो SDS में प्रवेश करते हैं (सामान्य ऐप क्षमता)।

Background: IB levels, SDS and the $12 mask

  • Kernel एक ringbuffer (RB=IB0) बनाए रखता है। Userspace CP_INDIRECT_BUFFER के माध्यम से IB1 सबमिट करता है, जो IB2/IB3 से chain होता है।
  • SDS एक विशेष command stream है जो CP_SET_DRAW_STATE के माध्यम से enter होता है:
  • A6xx: SDS को IB3 माना जाता है
  • A7xx: SDS IB4 में स्थानांतरित किया गया
  • Microcode वर्तमान IB level को register $12 में ट्रैक करता है और privileged packets को gate करता है ताकि वे केवल तब स्वीकार किए जाएँ जब effective level IB0 (kernel RB) के समान हो।
  • बग: A7xx microcode ने register $12 को 0x7 (3 bits) की बजाय 0x3 (2 bits) से mask करना जारी रखा। चूंकि IB4 & 0x3 == 0, SDS को गलत तरीके से IB0 के रूप में पहचाना गया, जिससे user-controlled SDS से privileged packets की अनुमति मिल गयी।

Why it matters:

A6XX                | A7XX
RB  & 3       == 0  |  RB  & 3       == 0
IB1 & 3       == 1  |  IB1 & 3       == 1
IB2 & 3       == 2  |  IB2 & 3       == 2
IB3 (SDS) & 3 == 3  |  IB3 & 3       == 3
|  IB4 (SDS) & 3 == 0   <-- misread as IB0 if mask is 0x3

Microcode diff उदाहरण (patch ने mask को 0x7 में बदल दिया):

@@ CP_SMMU_TABLE_UPDATE
- and $02, $12, 0x3
+ and $02, $12, 0x7
@@ CP_FIXED_STRIDE_DRAW_TABLE
- and $02, $12, 0x3
+ and $02, $12, 0x7

एक्सप्लॉइटेशन अवलोकन

Goal: SDS (misread as IB0) से privileged CP packets जारी करके GPU SMMU को attacker-crafted page tables की ओर री-पॉइंट करना, फिर GPU copy/write packets का उपयोग करके arbitrary physical R/W करना। अंत में, dirty pagetable के जरिए तेज़ CPU-side R/W पर pivot करना।

High-level chain

  • shared memory में एक fake GPU pagetable तैयार करें
  • SDS में प्रवेश करें और निष्पादित करें:
  • CP_SMMU_TABLE_UPDATE -> fake pagetable पर switch करें
  • CP_MEM_WRITE / CP_MEM_TO_MEM -> write/read primitives लागू करें
  • CP_SET_DRAW_STATE with run-now flags (dispatch immediately)

GPU R/W primitives via fake pagetable

  • Write: CP_MEM_WRITE को attacker-chosen GPU VA पर करें, जिसकी PTEs आप एक चुने हुए PA पर map करते हैं -> arbitrary physical write
  • Read: CP_MEM_TO_MEM target PA से userspace-shared buffer में 4/8 bytes copy करता है (बड़े reads के लिए batch)

Notes

  • प्रत्येक Android process को एक KGSL context मिलता है (IOCTL_KGSL_GPU_CONTEXT_CREATE)। सामान्यतः contexts बदलने पर SMMU tables RB में अपडेट होते हैं; यह बग आपको उन्हें SDS में करने देता है।
  • अत्यधिक GPU ट्रैफ़िक UI blackouts और reboots का कारण बन सकता है; reads छोटे हैं (4/8B) और sync default में धीमा होता है।

Building the SDS command sequence

  • shared memory में एक fake GPU pagetable spray करें ताकि कम से कम एक instance किसी ज्ञात physical address पर आ जाए (उदा., allocator grooming और repetition के जरिए)।
  • एक SDS buffer बनाएं जिसमें, क्रमवार, निम्न हों:
  1. CP_SMMU_TABLE_UPDATE fake pagetable के physical address पर
  2. एक या अधिक CP_MEM_WRITE और/या CP_MEM_TO_MEM packets ताकि आपकी नई translations का उपयोग करके R/W लागू किया जा सके
  3. CP_SET_DRAW_STATE run-now flags के साथ

सटीक packet encodings firmware के अनुसार भिन्न होते हैं; freedreno’s afuc/packet docs का उपयोग करके words assemble करें, और यह सुनिश्चित करें कि ड्राइवर द्वारा SDS submission path लिया जा रहा हो।

Samsung kernel physbase को physical KASLR के तहत खोजना

Samsung Snapdragon डिवाइसेज़ पर kernel physical base को एक ज्ञात क्षेत्र के भीतर randomize करता है। अपेक्षित रेंज को brute-force करें और _stext के पहले 16 bytes की तलाश करें।

Representative loop

while (!ctx->kernel.pbase) {
offset += 0x8000;
uint64_t d1 = kernel_physread_u64(ctx, base + offset);
if (d1 != 0xd10203ffd503233f) continue;   // first 8 bytes of _stext
uint64_t d2 = kernel_physread_u64(ctx, base + offset + 8);
if (d2 == 0x910083fda9027bfd) {           // second 8 bytes of _stext
ctx->kernel.pbase = base + offset - 0x10000;
break;
}
}

एक बार physbase ज्ञात हो जाने के बाद, रैखिक मैप के साथ कर्नेल वर्चुअल की गणना करें:

_stext = 0xffffffc008000000 + (Kernel Code & ~0xa8000000)

तेज़, विश्वसनीय CPU-side kernel R/W (dirty pagetable) के लिए स्थिर करना

GPU R/W धीमा और छोटा-ग्रैन्युलैरिटी वाला है। अपने प्रोसेस PTEs को करप्ट करके (“dirty pagetable”) एक तेज़/स्थिर प्रिमिटिव पर pivot करें:

Steps

  • slow GPU R/W primitives का उपयोग करके वर्तमान task_struct -> mm_struct -> mm_struct->pgd का पता लगाएँ
  • दो सन्निहित userspace पेज mmap करें A और B (e.g., at 0x1000)
  • PGD->PMD->PTE को पार करके A/B’s PTE physical addresses को हल करें (helpers: get_pgd_offset, get_pmd_offset, get_pte_offset)
  • B’s PTE को ओवरराइट करें ताकि वह A/B को मैनेज करने वाले last-level pagetable की ओर RW attributes के साथ पॉइंट करे (phys_to_readwrite_pte)
  • B’s VA के माध्यम से लिखें ताकि A’s PTE बदलकर target PFNs को मैप करे; A’s VA के जरिए kernel memory को read/write करें, और sentinel पलटने तक TLB को फ्लश करते रहें
उदाहरण dirty-pagetable pivot snippet ```c uint64_t *map = mmap((void*)0x1000, PAGE_SIZE*2, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); uint64_t *page_map = (void*)((uint64_t)map + PAGE_SIZE); page_map[0] = 0x4242424242424242;

uint64_t tsk = get_curr_task_struct(ctx); uint64_t mm = kernel_vread_u64(ctx, tsk + OFFSETOF_TASK_STRUCT_MM); uint64_t mm_pgd = kernel_vread_u64(ctx, mm + OFFSETOF_MM_PGD);

uint64_t pgd_off = get_pgd_offset((uint64_t)map); uint64_t phys_pmd = kernel_vread_u64(ctx, mm_pgd + pgd_off) & ~((1<<12)-1); uint64_t pmd_off = get_pmd_offset((uint64_t)map); uint64_t phys_pte = kernel_pread_u64(ctx, phys_pmd + pmd_off) & ~((1<<12)-1); uint64_t pte_off = get_pte_offset((uint64_t)map); uint64_t pte_addr = phys_pte + pte_off; uint64_t new_pte = phys_to_readwrite_pte(pte_addr); kernel_write_u64(ctx, pte_addr + 8, new_pte, false); while (page_map[0] == 0x4242424242424242) flush_tlb();

</details>

## पहचान और हार्डनिंग

- Firmware/microcode: उन सभी स्थानों को ठीक करें जो $12 को मास्क करके 0x7 का उपयोग करते हैं (A7xx) और privileged packet gates का ऑडिट करें
- Driver: privileged packets के लिए effective IB level को मान्य करें और per-context allowlists लागू करें
- Telemetry: चेतावनी जारी करें यदि CP_SMMU_TABLE_UPDATE (या समान privileged opcodes) RB/IB0 के बाहर दिखाई दे, विशेषकर SDS में; 4/8-बाइट CP_MEM_TO_MEM के असामान्य बर्स्ट और अत्यधिक TLB flush पैटर्न की निगरानी करें
- Kernel: pagetable metadata को सख्त करें और user PTE corruption पैटर्न का पता लगाएं

## प्रभाव

GPU तक पहुंच रखने वाला एक स्थानीय ऐप privileged GPU packets चला सकता है, GPU SMMU को hijack कर सकता है, मनमाना kernel physical/virtual R/W हासिल कर सकता है, SELinux को disable कर सकता है और प्रभावित Snapdragon A7xx डिवाइसों (उदा., Samsung S23) पर root प्राप्त कर सकता है। Severity: High (kernel compromise).

## संदर्भ

- [CVE-2025-21479: Adreno A7xx SDS->RB privilege bypass to kernel R/W (Samsung S23)](https://xploitbengineer.github.io/CVE-2025-21479)
- [Mesa freedreno afuc disassembler README (microcode + packets)](https://gitlab.freedesktop.org/mesa/mesa/-/blob/c0f56fc64cad946d5c4fda509ef3056994c183d9/src/freedreno/afuc/README.rst)
- [Google Project Zero: Attacking Qualcomm Adreno GPU (SMMU takeover via CP packets)](https://googleprojectzero.blogspot.com/2020/09/attacking-qualcomm-adreno-gpu.html)
- [Dirty pagetable (archive)](https://web.archive.org/web/20240425043203/https://yanglingxi1993.github.io/dirty_pagetable/dirty_pagetable.html)

> [!TIP]
> AWS हैकिंग सीखें और अभ्यास करें:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP हैकिंग सीखें और अभ्यास करें: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Azure हैकिंग सीखें और अभ्यास करें: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>HackTricks का समर्थन करें</summary>
>
> - [**सदस्यता योजनाओं**](https://github.com/sponsors/carlospolop) की जांच करें!
> - **हमारे** 💬 [**Discord समूह**](https://discord.gg/hRep4RUj7f) या [**टेलीग्राम समूह**](https://t.me/peass) में शामिल हों या **हमें** **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)** पर फॉलो करें।**
> - **हैकिंग ट्रिक्स साझा करें और** [**HackTricks**](https://github.com/carlospolop/hacktricks) और [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) गिटहब रिपोजिटरी में PRs सबमिट करें।
>
> </details>