Skip to content

SLAB freelist hardening

SLUB free-list pointer'larını, pointer'ın kendi storage adresine anahtarlanmış per-cache random bir XOR ile gizler ve klasik freelist-overwrite heap primitive'ini kırar.

Mechanism

Note

CONFIG_SLAB_FREELIST_HARDENED, SLUB allocator'ının dahili free-list metadata'sını sertleştirir. Invariant: freed bir slab object'inde gömülü next-object pointer'ı asla plaintext olarak saklanmaz ve obfuscation key'i pointer'ın yaşadığı yere bağlanır, böylece o word'ü üzerine yazabilen bir attacker oraya seçtiği bir plaintext adresi koyamaz.

SLUB, singly-linked free list'ini freed object'lerin içinde saklar: bir free object'in ilk word'ü bir sonraki free object'in adresini tutar. Klasik bir heap exploit o word'ü (overflow veya use-after-free yoluyla) üzerine yazar, böylece bir sonraki allocation attacker'ın seçtiği bir adresi döner — bir arbitrary-write veya fake-object primitive'i.

Hardening, saklanan değeri iki secret ile dönüştürür:

  • s->random — per-kmem_cache random bir değer (get_random_long()), attacker tarafından bilinmeyen.
  • ptr_addr — pointer'ı tutan slot'un adresi.

Encoding bir triple XOR'dur:

static inline void *freelist_ptr(const struct kmem_cache *s, void *ptr,
                 unsigned long ptr_addr)
{
#ifdef CONFIG_SLAB_FREELIST_HARDENED
    return (void *)((unsigned long)ptr ^ s->random ^ ptr_addr);
#else
    return ptr;
#endif
}

ptr_addr'ı dahil etmek incelikli kısımdır. Yalnızca ptr ^ random ile, aynı key bir cache'teki her pointer'ı gizler, böylece tek bir {plaintext, obfuscated} çiftinin sızması random'ı geri kazandırır ve attacker'ın herhangi bir pointer'ı forge etmesine izin verir. Storage adresini karışıma katmak, etkili key'i konuma bağımlı yapar: slot A'ya yazılan değer slot B'de tekrar oynatılamaz ve forge edilmiş bir target, hem s->random'ı hem de pointer'ın saklanacağı tam adresi bilmeyi gerektirir.

Walkthrough

Savunma mm/slub.c içinde yaşar. Per-cache key, allocator descriptor'ına eklenir:

struct kmem_cache {
    /* ... */
    unsigned long random;   /* only with CONFIG_SLAB_FREELIST_HARDENED */
};

/* at cache creation */
s->random = get_random_long();

Her freelist traversal/store, slot adresini geçirir ki XOR simetrik olsun (encode == decode):

/* get the decoded next pointer */
next = freelist_ptr(s, *(void **)ptr_addr, (unsigned long)ptr_addr);

/* store the encoded next pointer */
*(void **)ptr_addr = freelist_ptr(s, next_obj, (unsigned long)ptr_addr);

Çalışan bir kernel'de enabled olduğunu teyit edin:

zcat /proc/config.gz | grep SLAB_FREELIST_HARDENED
# CONFIG_SLAB_FREELIST_HARDENED=y

Warning

XOR'da ptr_addr olmadan, bir obfuscated pointer'ın artı onun bilinen plaintext target'ının tek bir info leak'i s->random'ı kolayca verir (random = obf ^ ptr) ve tüm şemayı yener. Storage-address terimi, attacker'ı ek olarak forge edilmiş pointer'ın nereye yazılacağını bilmeye zorlayan şeydir.

Patch, ihmal edilebilir overhead raporladı — yazarın benchmark'ında ~%0.07 mertebesinde.

Note

Yukarıdaki snippet, orijinal 2017 patch'ini yansıtır (ptr ^ s->random ^ ptr_addr). Sonraki bir iyileştirme, ptr_addr terimini bir byte-swap ile karıştırdı (ptr ^ s->random ^ swab(ptr_addr)), böylece numerik olarak bitişik slot adreslerinin encoded pointer'lardan sızması daha da zorlaştı. Ayrıntı için bkz. freelist-poisoning.

Detection

Exploitation açısından, hardening aktifken freed bir SLUB object'inin ilk word'ü tanınabilir bir kernel pointer'ı yerine yüksek-entropili bir değer olacaktır. Defansif olarak, struct kmem_cache içinde random'ın varlığı ve /proc/config.gz'de config option için =y olması, mitigation'ın compile edildiğini gösterir.

Mitigation

Bypass'lar ve sınırlamalar:

  • Leak gerektirir. Hem s->random'ı hem de target slot adresini leak edebilen bir attacker, geçerli bir obfuscated değer hesaplayabilir ve freelist-overwrite primitive'ini sürdürebilir; hardening çıtayı runtime info gerektirmeye yükseltir, primitive'i imkânsız yapmaz.
  • Yalnızca freelist pointer'ını korur. Diğer in-object veya bitişik slab metadata'sı ve non-freelist heap-grooming teknikleri dokunulmamış kalır. slab-freelist-randomization (free-list order'ını randomize eder) ve init-on-free, hardened-usercopy gibi komşu önlemlerle birlikte çalışır.
  • Tamamlayıcı, tek başına değil. Defense in depth için slab-freelist-randomization ve init-on-alloc ile birleştirin.

References