Skip to content

STACKLEAK stack erase on syscall return

Her userspace'e return'de kernel stack'inin kullanılmış kısmını poison'layan bir GCC-plugin hardening'i (grsecurity/PaX'ten port edilmiş); uninitialized-stack infoleak'leri öldürür ve hassas stack data'sının ömrünü kısaltır.

Mechanism

STACKLEAK, bugün CONFIG_KSTACK_ERASE ("clear stack on a syscall return") tarafından kapatılan Linux CONFIG_GCC_PLUGIN_STACKLEAK feature'ıdır. Bir GCC plugin'i kernel'i instrument eder; her syscall'un sonunda, user space'e return etmeden önce, kernel, syscall'un gerçekten dokunduğu kernel stack porsiyonunu bir poison değeriyle overwrite eder.

Neden işe yarar

Kernel stack frame'leri entry'de sıfırlanmaz, dolayısıyla uninitialized bir local okuyan bir function — ya da partially-filled bir struct'ın copy_to_user()'ı — önceki, daha derin bir call chain'in stack'te bıraktığı her şeyi leak edebilir: pointer'lar (KASLR'yi yenerek), credential'lar ya da başka secret'lar. STACKLEAK, bu tür leak'lerin dayandığı önkoşulu kırar: attacker-useful stale data'nın çağrılar arasında stack'te kalıcı olması. Her syscall'dan sonra kullanılmış bölge STACKLEAK_POISON (-0xBEEF) sabitine set edilir, böylece sonraki bir uninitialized read residual data yerine bilinen, secret-olmayan, pointer-ımsı-olmayan bir sabit görür. Ayrıca temporal pencereyi de kısaltır: tek bir syscall içinde bile en derin önceki kullanım silinmiştir. Yalnızca stack'in kullanılmış kısmı temizlendiği için — sürekli güncellenen bir lowest_stack water-mark'ı üzerinden izlenir — maliyet call complexity'siyle değil stack depth'iyle ölçeklenir, ki bu yüzden ucuzdur. Aynı instrumentation bir runtime kernel-stack-depth/overflow check'i de ekler.

Walkthrough

Kernel config'inde etkinleştir (iki option birlikte çalışır, ikisi de =y olmalı):

CONFIG_KSTACK_ERASE=y          # (historically CONFIG_GCC_PLUGIN_STACKLEAK=y)
CONFIG_GCC_PLUGIN_STACKLEAK=y  # GCC plugin that does the instrumentation
CONFIG_STACKLEAK_METRICS=y     # optional: expose metrics
CONFIG_STACKLEAK_RUNTIME_DISABLE=y  # optional: allow runtime toggle

CONFIG_KSTACK_ERASE alternatif değil, feature'ın modern umbrella/menu config'idir ve altındaki CONFIG_GCC_PLUGIN_STACKLEAK plugin'ini gate'ler; historically feature yalnızca CONFIG_GCC_PLUGIN_STACKLEAK adıyla vardı. Feature'ın aktif olması için ikisi de =y olmalıdır.

Çekirdek runtime parçaları (kernel/stackleak.c'den, sonradan kernel/kstack_erase.c):

STACKLEAK_POISON          = -0xBEEF   # value written into the used stack region
current->lowest_stack                 # per-task water-mark of deepest stack use
stackleak_track_stack()               # plugin-inserted; updates lowest_stack
stackleak_erase()                     # runs before return-to-user; poisons stack

Runtime'da değiştir (runtime-disable seçeneğiyle build edildiğinde):

# boot parameter
stack_erasing=off

# sysctl
sysctl kernel.stack_erasing        # 1 = erasing on, 0 = off
Syscall başına kavramsal akış
syscall entry
  └─ deep call chain runs; stackleak_track_stack() keeps lowest_stack
     pointing at the deepest byte touched
syscall exit (return to user)
  └─ stackleak_erase():
       from current stack pointer down to lowest_stack,
       write STACKLEAK_POISON over every byte
  └─ lowest_stack reset for next syscall
A subsequent syscall that reads an uninitialized local now reads
0x...BEEF instead of a leftover kernel pointer or secret.

Uyarılar

  • STACKLEAK eşleşen GCC plugin'ini gerektirir; yalnızca GCC'ye özgü bir feature'dır (Clang, -ftrivial-auto-var-init gibi farklı mekanizmalar kullanır).
  • Syscall return'ünde poison'lar, dolayısıyla data onu üreten syscall'un süresi boyunca canlıdır — exposure penceresini ortadan kaldırmaz, azaltır.
  • Variable'ları bir function içinde ilk kullanımdan önce initialize etmez; bunun için stack auto-init ile eşle (bkz. Mitigation).

Detection

Feature'ın derlemeye dahil edildiğini ve aktif olduğunu doğrula:

grep -E 'KSTACK_ERASE|GCC_PLUGIN_STACKLEAK' /boot/config-$(uname -r)
sysctl kernel.stack_erasing          # 1 when erasing is enabled

In-tree self-test (lkdtm STACKLEAK_ERASING / STACKLEAK test driver), stack'in gerçekten silindiğini doğrulamak için poison-and-erase path'ini çalıştırır.

Mitigation

Residual risk ve saldırganların başa çıkma yolu:

References

  • Linux kernel docs, "Kernel Self-Protection" (Memory poisoning — CONFIG_KSTACK_ERASE): https://docs.kernel.org/security/self-protection.html
  • LWN, "Introduce the STACKLEAK feature and a test for it": https://lwn.net/Articles/735584/
  • LWN, "gcc-plugins: Add stackleak feature erasing the kernel stack at the end of syscalls": https://lwn.net/Articles/725287/