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:
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¶
- ARM Architecture Reference Manual (ARMv7-A/R), VMSA — Memory access control: Domains. — https://developer.arm.com/documentation/ddi0406/b/System-Level-Architecture/Virtual-Memory-System-Architecture--VMSA-/Memory-access-control/Domains
- DACR — Domain Access Control Register (Jon's Arm Reference). — https://arm.jonpalmisc.com/latest_sysreg/AArch32-dacr