RANDSTRUCT structure layout randomization¶
Build-time randomization of selected kernel struct field order (originally grsecurity/PaX
GRKERNSEC_RANDSTRUCT, nowCONFIG_RANDSTRUCT) so attackers cannot hardcode the offset of a function pointer or credential field within a structure.
Mechanism¶
Neden çalışır
Çoğu kernel sömürü primitive'i bir field'ın bir structure içinde nerede
yaşadığını bilmek zorundadır: hijack edilecek bir function pointer'ın offset'i
(function pointer overwrite),
modprobe_path'in offset'i (modprobe path overwrite)
ya da struct cred'in field'ları (cred overwrite).
Bu offset'ler normalde compile time'da sabittir, bu yüzden bir exploit +0x28'i
hardcode'layıp her yerde yeniden kullanabilir.
RANDSTRUCT bu varsayımı, hassas structure'ların member layout'unu build time'da
permute ederek kırar; per-build bir random değerle seed'lenir. Layout bir saldırgana
bilinmediğinde "belirli field'ları overwrite etmeleri çok daha zor hale gelir." Önemli
olarak, plugin tamamen function pointer olan structure'ları (klasik ops/vtable
tabloları) ve açıkça __randomize_layout işaretlenmiş her şeyi otomatik hedefler.
Invariant: bir field'ın offset'i per-build bir sırdır, böylece bir exploit binary'ye
pişirilmiş bir offset artık çalışan kernel ile eşleşmez.
Walkthrough¶
1. Etkinleştir. İki güç seviyesi sunulur:
# Full randomization (strongest)
CONFIG_RANDSTRUCT_FULL=y
# "Fully randomize the member layout of sensitive structures as much as
# possible, which may have both a memory size and performance impact."
# Cacheline-aware (weaker, faster)
CONFIG_RANDSTRUCT_PERFORMANCE=y
# "make a best effort at restricting randomization to cacheline-sized
# groups of members" — and does NOT randomize bitfields.
RANDSTRUCT, ya GCC plugin'i (CONFIG_GCC_PLUGINS, grsecurity/PaX'ten port edilmiş)
ile ya da compiler CC_HAS_RANDSTRUCT'a sahip olduğunda nativce uygulanır. ABI
değiştiği için MODVERSIONS'ı seçer.
2. Seed. Permutasyon bir seed dosyası aracılığıyla build başına yeniden üretilebilirdir:
make clean'i atlatır (böylece out-of-tree modüller aynı layout'a karşı build edilir) ve
make mrproper / make distclean tarafından silinir. Seed'siz temiz bir tree, bir
saldırganın (ya da Volatility gibi bir forensic tool'un) offset'leri geri kazanamayacağı
anlamına gelir.
3. Struct'ları annotate etme. Bir driver yazarı bir struct'ı dahil eder ya da hariç tutar:
struct my_ops {
int (*open)(struct inode *, struct file *);
int (*release)(struct inode *, struct file *);
/* ... */
} __randomize_layout; /* force randomization */
struct must_stay_fixed {
/* ABI-sensitive, hardware-defined order */
} __no_randomize_layout; /* opt OUT */
Tamamen function pointer olan struct'lar, __no_randomize_layout ile tag'lenmediği
sürece otomatik olarak randomize edilir.
4. Hardcode edilmiş bir offset neden bozulur. ops->write'ın +0x10'da olduğunu
varsayan bir exploit, bir RANDSTRUCT kernel'ine karşı farklı bir member'a düşer — control
flow'u yönlendirmek yerine ilgisiz bir field'ı corrupt eder ya da crash eder. Offset hedef
başına yeniden türetilmelidir; bu da source tree ve seed olmadan genellikle olanaksızdır.
Build-time, load-time değil
RANDSTRUCT build başına bir kez randomize eder, boot başına değil. Aynı derlenmiş
vmlinux'u çalıştıran her makine aynı layout'u paylaşır. Sızdırılmış bir
randomize_layout_seed.h, dağıtılmış bir binary kernel ya da bir member'ın adresini
açığa çıkaran bir info leak — hepsi korumayı zayıflatır.
Detection¶
Saldırganlar tarafından mitigation'ın başlı başına bir runtime "tespiti" yoktur, ama bir uyumsuzluk gözlemlenebilir: farklı bir seed'e karşı build edilmiş modüller yüklenemez ve vanilla bir layout için yapılmış forensic tooling (Volatility profilleri) kernel structure'larını sessizce yanlış parse eder.
Mitigation¶
(Not: bu bölüm bir deployment rehberi değil — RANDSTRUCT'ın artık riskini ve nasıl bypass edildiğini listeler.) RANDSTRUCT yalnızca çıtayı yükseltir; gereken offset'i runtime'da sızdırabilen (bir pointer/değer açığa çıkması), aynı seed'e karşı build eden (dağıtım kernel'leri sabit bir binary gönderir) ya da randomization için seçilmemiş bir struct'ı hedefleyen bir saldırganı durdurmaz. Onu yenen leak'leri reddetmek için kptr-restrict gibi pointer-leak hardening'iyle birleştirin.
References¶
- LWN. Randomizing structure layout. — https://lwn.net/Articles/722293/
- kernelconfig.io. CONFIG_RANDSTRUCT_FULL. — https://www.kernelconfig.io/config_randstruct_full
- Linux Kernel Driver DataBase. CONFIG_GCC_PLUGIN_RANDSTRUCT. — https://cateee.net/lkddb/web-lkddb/GCC_PLUGIN_RANDSTRUCT.html