Skip to content

RANDSTRUCT structure layout randomization

Build-time randomization of selected kernel struct field order (originally grsecurity/PaX GRKERNSEC_RANDSTRUCT, now CONFIG_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:

scripts/gcc-plugins/randomize_layout_seed.h

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