Skip to content

Memory Domains (ARM emulated SMAP)

AArch32, belleği 16 domain'e böler; DACR her birine 2-bit'lik bir access type (No access / Client / Manager) verir ve böylece bir kernel'in bir domain'e privileged erişimi toptan fault'lamasına izin verir — coarse, SMAP benzeri bir kontrol.

Mechanism

Neden çalışır

AArch32'de (ARMv7-A / ARMv8 AArch32), her short-descriptor translation table entry'si 4-bit'lik bir domain field'ı taşır ve bölgeyi 16 memory domain'inden birine atar. Domain Access Control Register (DACR), on altı adet 2-bit'lik field D0..D15 tutan 32-bit'lik bir register'dır; D<n> field'ı [2n+1:2n] bitlerini kaplar ve domain n için erişim type'ını belirler:

Encoding Type Davranış
0b00 No access Domain'e yapılan herhangi bir erişim bir Domain fault üretir
0b01 Client Erişimler translation-table permission bit'lerine karşı kontrol edilir
0b10 Reserved Kullanım için tanımlanmamış
0b11 Manager Erişimler permission bit'lerine karşı kontrol edilmez

Bir defender'ın istismar ettiği invariant: bir Manager domain'i page permission kontrollerini tamamen bypass eder, oysa bir No access domain'i page'in kendi permission'larından bağımsız olarak her dokunuşta fault'lar. User page'leri bir domain'e, kernel page'leri başka bir domain'e koyup kernel entry/exit'inde DACR field'ını flip ederek, yazılım user memory'ye privileged erişimi reddedebilir — bir "emulated SMAP" — ve onu yalnızca denetlenen bir pencere içinde yeniden verebilir. Kontrol hızlıdır çünkü page permission'larını yeniden yürümek yerine bir bütün domain'i tek seferde toggle eder.

Walkthrough

Domain'ler yalnızca AArch32'ye özgü bir özelliktir (Long-descriptor / LPAE formatı onları düşürür ve AArch64'te DACR yoktur — bunun yerine PAN kullanılır). Onları CP15 üzerinden yapılandırıp gözlemlersin.

1. Register layout'u. DACR, CP15 c3'tür; her domain iki bit'e sahiptir:

DACR bits:  31  ..             ..   3 2   1 0
            [D15] ... [D2] [D1] [   D0   ]
            each D<n> = 2 bits, value in {00,01,11}

2. Bir domain'i No access yap (içindeki her şeyi reddet). Domain 0'ı No access ve domain 1'i Client olarak işaretleyen kavramsal bir CP15 write:

; r0 = (Client<<2) | (NoAccess<<0)  =  (0b01 << 2) | (0b00 << 0) = 0x4
MCR p15, 0, r0, c3, c0, 0      ; write DACR

Domain 0 ile tag'lenmiş bir page'e yapılan sonraki herhangi bir erişim artık, per-page AP bit'lerine bakılmadan önce, data/prefetch abort handler'da bir Domain fault yükseltir.

3. SMAP-emülasyon pattern'i. Userspace bölgelerini kendi domain'lerine koy; kernel entry'de o domain'i No access'e ayarla ve Client'ı yalnızca açık bir copy_to_user/copy_from_user tarzı pencerenin çevresinde geçici olarak geri yükle — x86 stac/clac ya da AArch64 PAN'ın uaccess toggling'i ile aynı şekil.

Manager bir özellik değil, bir footgun

Manager (0b11)'da bırakılan bir domain, içindeki her page'in kendi permission bit'lerini bypass etmesine neden olur — read-only ve no-execute işaretleri privileged erişim için yok sayılır. Bu yüzden buggy ya da fazla geniş bir DACR değeri, kilitli olduğunu sandığın belleğe erişimi sessizce yeniden etkinleştirebilir. Manager domain'lerini kasıtlı, dar kapsamlı bir istisna olarak gör.

Detection

Bir Domain fault, AArch32 fault status register'ları (DFSR / IFSR) üzerinden, Permission fault'tan ayrı bir Domain-fault status encoding'iyle bildirilir. İkisini ayırt etmek, defender'a abort'un coarse domain kontrolünden mi yoksa per-page AP bit'lerinden mi geldiğini söyler.

Mitigation

(Residual risk.) Domain'ler coarse'tur: koruma yalnızca her bölgenin domain assignment'ı kadar iyidir ve tek bir Manager domain'i ya da yanlış kapsamlandırılmış bir uaccess penceresi erişimi yeniden açar. Domain'ler ayrıca LPAE/AArch64 altında mevcut değildir, bu yüzden modern AArch64 kernel'leri PAN / PXN üzerine ve x86'da donanımsal SMAP üzerine dayanır.

References