Hardened usercopy¶
Linux
CONFIG_HARDENED_USERCOPY, hercopy_to_user/copy_from_user'ı slab object'inin whitelist'lenmiş region'ına, stack frame'ine ve kernel text/rodata'sına karşı bounds-check eder; böylece buggy bir copy komşu belleğe over-read veya over-write yapamaz.
Mechanism¶
copy_to_user() / copy_from_user(), user/kernel sınırı boyunca arbitrary-length
buffer'ları taşır. Bir uzunluk veya pointer attacker'ın etkisindeyse, bir copy
amaçlanan object'inin sonunu aşabilir ve komşu kernel belleğini açığa çıkarabilir
(over-read) ya da corrupt edebilir (over-write) — klasik bir information-leak ve
heap-corruption primitive'i.
Hardened usercopy, böyle her copy'ye bir check araya sokar. Whitelisting uzantısı
(grsecurity/PaX PAX_USERCOPY'den David Windsor tarafından port edildi, Kees Cook
tarafından review edildi), bir slab cache'in object'lerinin içinde bir usercopy
region declare etmesine izin verir: kmem_cache_create_usercopy() bir useroffset
(kopyalanabilir pencerenin başladığı yer) ve bir usersize (uzunluğu; 0 bu cache'ten
hiç kopyalamaya izin verilmediği anlamına gelir) alır.
Invariant hardened usercopy enforces
Slab allocator'ından elde edilen bir object bir user-space copy fonksiyonuna
geçirildiğinde, kopyalanacak alan tamamen whitelist'lenmiş pencerenin içinde
[useroffset, useroffset + usersize) yer almalıdır. Object sınırını geçecek,
yanlış region'a yayılacak veya bir usersize == 0 cache'ten kaynaklanacak
herhangi bir copy reddedilir (kernel usercopy: kernel memory ... raporlar
ve BUG verir). Check şunları da kapsar:
- slab object'leri — copy, object'in usercopy region'ı içinde kalmalı;
- stack — copy, mevcut stack frame içinde olmalı, ondan taşmamalı;
- kernel text / rodata —
.text/.rodataile çakışan copy'ler yasaktır, çünkü bunlar asla meşru copy kaynağı/hedefi değildir.
Her object yalnızca tek bir region expose edebilir, bu da driver'ları user-expose edilen field'ları bir arada gruplamaya zorlar. Whitelisting serisinden sonra, taze bir boot'ta slab-cache belleğinin ~%15'inden azı usercopy bug'larına expose kalır.
GFP_USERCOPY / dedike usercopy slab'leri, heap-layout saldırılarını
zorlaştırmak için user-expose edilen object'leri daha da izole eder.
Walkthrough¶
1. Özelliğin build içinde olduğunu doğrula.
2. Gerçek bir whitelist annotation'ı oku. userspace'e veri expose eden
cache'ler pencerelerini açıkça declare eder, ör. mimari başına FPU/task_struct
cache'leri kmem_cache_create_usercopy(name, size, align, flags,
useroffset, usersize, ctor) çağırır. kmem_cache_create() ile oluşturulan
generic bir cache'in usersize == 0'ı vardır, dolayısıyla byte'larından
herhangi birini userspace'e/userspace'ten kopyalamak reddedilir.
3. Bir reddi gözlemle. Whitelist'lenmiş region'ı aşan bir copy, suçlu task'ı bir raporla abort eder:
usercopy violation report
Whitelisting depends on correct annotations
Check yalnızca annotate edilmiş olanı korur. Eksik bir whitelist tarihsel
olarak amaçlanan field aralığı yerine tüm slab allocation boyutunu
check etmeye geri düşerdi (CONFIG_HARDENED_USERCOPY_FALLBACK, açığı işaretlemek
için bir WARN() ile), ki bu sıkı bir usersize'dan daha zayıftır. Ayrıca
aşırı geniş bir whitelist'in içinde kalan bir copy'yi de yakalamaz.
Detection¶
Bir ihlal kendi kendini raporlar: __check_object_size() / __check_heap_object(),
task'ı öldürmeden önce cache adını, offset'i ve boyutu loglayan usercopy_abort()'u
çağırır — hem bir runtime savunması olarak hem de fuzzing sırasında bir driver'ın bir
copy'yi yanlış boyutlandırdığına dair bir sinyal olarak faydalıdır.
Mitigation¶
SMAP (ki kernel'in user page'lere istenmeyen erişimini tümden bloklar), slab hardening (slab freelist hardening) ve init-on-alloc ile eşleştir; böylece leak'lenen bir region'ın neyi açığa çıkarabileceğini azalt.
References¶
- LWN.net. Hardened usercopy whitelisting. — https://lwn.net/Articles/727322/
- Kees Cook / kernel-hardening. [PATCH 00/23] Hardened usercopy whitelisting. — https://www.openwall.com/lists/kernel-hardening/2017/06/19/17