Skip to content

atyfb_ioctl padding-byte stack infoleak

atyfb framebuffer ioctl'i, bir stack struct atyclk'ı compiler'ın eklediği padding'i sıfırlamadan userspace'e kopyalar ve uninitialized kernel stack byte'larını leak eder.

Mechanism

Note

Compiler'lar alignment için struct member'ları arasına padding ekler; C standardına göre o padding byte'ları belirsiz değerlere sahiptir ve pratikte önceki stack içeriğini korur, çünkü yeni bir stack frame yalnızca stack pointer'ı hareket ettirerek yaratılır. Her adlandırılmış field initialize edilmiş olsa bile padding edilmez — dolayısıyla copy_to_user(dst, &s, sizeof(s)) (bir memcpy) padding'i dışarı kopyalar ve kernel stack memory'sini ifşa eder. atyfb_ioctl() (drivers/video/fbdev/aty/atyfb_base.c) içinde bir stack struct atyclk doldurulup userspace'e kopyalanır, ama vclk_post_div'den sonraki padding byte'ları uninitialized bırakılır.

Walkthrough

İç padding'i olan bir struct ile genel bug şekli:

struct test { int a; char b; int c; };   /* 3 padding bytes between b and c */

struct test arg = { .a = 1, .b = 2, .c = 3 };
copy_to_user(usr_buf, &arg, sizeof(arg));  /* leaks the 3 uninitialized padding bytes */

atyfb için bir attacker, cihaz üzerinde framebuffer clock ioctl'ini issue eder, struct atyclk'ı alır ve padding byte'larını okur — stack içeriğini toplamak için tekrar eder (bu içerik saved register'lar ya da kernel pointer'ları içerebilir ve KASLR'ı kırabilir).

Fix, struct doldurulup dışarı kopyalanmadan önce atyfb_ioctl()'in M64_HAS(INTEGRATED) path'ine sıfırlayan bir memset ekler:

memset(&clk, 0, sizeof(struct atyclk));

Warning

Yalnızca adlandırılmış field'ları memset'lemek yeterli değildir — designated-initializer söz dizimi ({ .a = 1 }) belirtilmeyen member'ları sıfır doldurur ama iç padding'i sıfırlama garantisi vermez. Her zaman önce tüm objeyi memset(&s, 0, sizeof(s)) ile sıfırla.

Detection

Bu sınıfı yakalayan araçlar: Valgrind (bir write sınırını geçen uninitialized memory), MemorySanitizer (LLVM/Clang) ve struct padding/member'larını otomatik sıfırlamak için kernel'in CONFIG_GCC_PLUGIN_STRUCTLEAK* üzerinden kullandığı GCC STRUCTLEAK plugin'i.

Mitigation

  • Doldurmadan önce tüm struct'ı sıfırla: memset(&s, 0, sizeof(s)); s.field = ...;.
  • Stack struct'larını otomatik initialize etmek için CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL ile build et.
  • Bu özel atyfb infoleak'i için public bir CVE doğrulanamadı (No official CVE assigned). Yine de aynı disclosure sınıfını SEI CERT kuralı DCL39-C (struct padding'in userspace'e kopyalanması) dokümante eder.

References