Kernel Debug Araçları
TEKNİK REHBER KERNEL DEBUG MEMORY SAFETY 2026

KASAN · UBSAN · KMSAN —
kernel sanitizers.

Compile-time instrumentation ile kernel memory hatalarını, undefined behavior'ı ve veri yarışlarını üretim öncesinde bul. Bug'ın iz bıraktığı yerde seni bekliyor.

00 Kernel sanitizer'lar nedir

Kernel sanitizer'lar, derleme zamanında kaynak koduna ek kontrol talimatları ekleyen araçlardır. Çalışma zamanında bellek erişimlerini, tip dönüşümlerini ve veri yarışlarını izleyerek hataları hemen bulurlar.

SanitizerTespit ettiği hatalarOverheadKernel config
KASANOut-of-bounds, use-after-free, use-after-return~2x bellek, ~2x CPUCONFIG_KASAN=y
UBSANSigned overflow, shift exponent, array index OOB, null deref~1.1x CPUCONFIG_UBSAN=y
KMSANBaşlatılmamış bellek kullanımı~3x bellek, ~3x CPUCONFIG_KMSAN=y
KCSANVeri yarışı (data race), lock-free erişim hataları~1.5x CPUCONFIG_KCSAN=y

Ortak özellikler

KULLANIM MODELİ

Sanitizer'lar debug kernel'lar için tasarlanmıştır. Üretim kernel'ına eklenmez. Tipik akış: syzkaller fuzzing ortamı veya özel test platformu → sanitizer kernel → hata raporu → kaynak düzeltme → yeniden test. ARM MTE donanım desteğiyle KASAN üretim kullanımına yaklaşmaktadır.

01 KASAN — Kernel Address Sanitizer

KASAN, heap/stack/global bellek erişimlerini shadow memory ile izler. Her byte için 1-bit gölge bellek tutar ve her erişimde bu gölge bayta bakarak erişimin geçerli olup olmadığını kontrol eder.

Shadow memory modeli

  Normal bellek alanı:       0x00000000 — 0x7fffffff
  KASAN shadow alanı:        0xdffffc00 — 0xffffffff
                             (1/8 oranında, 8 byte → 1 shadow byte)

  Shadow byte anlamı:
  0x00  → 8 byte tamamen erişilebilir
  0x01–0x07 → ilk N byte erişilebilir, geri kalanlar zehirli
  0xFA  → heap left redzone
  0xFB  → heap right redzone
  0xFC  → use-after-free (freed memory)
  0xFD  → stack left redzone
  0xFE  → global redzone
    

Kernel konfigürasyonu

Kconfig
CONFIG_KASAN=y
CONFIG_KASAN_GENERIC=y         # generic mod (x86, ARM64 vb.)
CONFIG_KASAN_OUTLINE=y         # inline yerine fonksiyon çağrısı (daha küçük ikili)
# veya
CONFIG_KASAN_INLINE=y          # her erişim noktasına instrumentation (daha hızlı)

# Stack ve global değişkenleri de izle
CONFIG_KASAN_STACK=1

# Birden fazla hata bulmak için (ilkinde durmak yerine)
CONFIG_KASAN_MULTI_SHOT=y

Out-of-bounds örneği

C — kasıtlı bug
/* Bu kod KASAN tarafından yakalanır */
char *buf = kmalloc(16, GFP_KERNEL);
buf[16] = 'X';   /* out-of-bounds: 16 byte tahsis, 17. byte'a yazma */
kfree(buf);

buf[0] = 'Y';    /* use-after-free: kfree sonrası erişim */

02 KASAN bug raporu okumak

KASAN bir hata tespit ettiğinde dmesg'e ayrıntılı bir rapor yazar. Bu raporu okumayı öğrenmek, hatayı hızlıca bulmak için kritiktir.

dmesg — KASAN bug raporu
==================================================================
BUG: KASAN: slab-out-of-bounds in my_driver_write+0x4c/0xa0 [my_driver]
Write of size 1 at addr ffff888012345670 by task kworker/0:1/42
                  ^          ^              ^          ^
                  erişim tipi boyut         adres       görev

CPU: 0 PID: 42 Comm: kworker/0:1 Not tainted 6.6.0-rc4 #1

Hardware name: QEMU Standard PC

Call Trace:
 dump_stack_lvl+0x64/0x83
 print_report+0x165/0x4b0
 kasan_report+0xbb/0x1f0
 kasan_check_range+0x100/0x1a0
 my_driver_write+0x4c/0xa0 [my_driver]   ← HATANIN OLDUĞU FONKSİYON
 spi_sync+0x2a/0x60
 spi_write+0x1e/0x30
 ...

Allocated by task 42:
 __kmalloc+0x2a/0x60
 my_driver_probe+0x88/0x120 [my_driver]   ← TAHSIS NOKTASI

The buggy address belongs to the object at ffff888012345660
 which belongs to the cache kmalloc-16 of size 16
The buggy address is located 16 bytes to the right of
 16-byte region [ffff888012345660, ffff888012345670)
                                        ^
                                        Tahsis edilen alanın tam sonu

Memory state around the buggy address:
 ffff888012345640: fa fb fb fb fc fc fc fc
 ffff888012345660: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff888012345670: fc fc fc fc fc fc fc fc   ← fc = right redzone
                  ^
                  Erişim bu adrese yapıldı
==================================================================

Rapor bileşenleri

BUG tipi
slab-out-of-bounds: heap tampon taşması. use-after-free: serbest bırakılmış belleğe erişim. stack-out-of-bounds: stack buffer taşması.
Access type/size
Read mi Write mi, kaç byte etkilendi.
Call Trace
Hatanın nerede oluştuğunu gösteren yığın izi. Genellikle üçüncü veya dördüncü çerçeve asıl hatayı işaret eder.
Allocated by
Belleğin nerede tahsis edildiği — genellikle probe veya init fonksiyonunda.
Memory state
Shadow byte haritası. 00=temiz, fa=left redzone, fc=right redzone/freed.

03 KASAN modları

KASAN, üç farklı modda çalışabilir. Her birinin farklı overhead'i ve platform gereksinimleri vardır.

ModMekanizmaPlatformOverheadKullanım
Generic KASANShadow memory + compiler instrumentationx86, ARM64, MIPS, RISC-V~2x RAMDebug kernel
SW Tag-basedARM64 TBI (Top Byte Ignore) + 8-bit tagARM64~1.5x RAMDebug kernel
HW Tag-based (MTE)ARM Memory Tagging ExtensionARM64 v8.5+~0% CPU ek yükÜretim adayı

Hardware Tag-based KASAN (MTE)

Kconfig — ARM MTE
CONFIG_KASAN=y
CONFIG_KASAN_HW_TAGS=y    # ARM MTE gerektirir
# CONFIG_KASAN_GENERIC is not set

# u-boot veya kernel cmdline parametresi
# kasan.mode=async  — asenkron mod, daha düşük overhead
# kasan.mode=sync   — senkron mod, daha kesin konum bilgisi
# kasan.mode=asymm  — karma mod
MTE GÖMÜLEBİLİR SISTEMLER

Cortex-A55 ve üzeri çekirdekler (Raspberry Pi 5'in Cortex-A76'sı dahil) MTE destekler. Gömülü sistemlerde üretim kalitesinde memory safety için MTE tabanlı KASAN gelecek vaat ediyor — yaklaşık sıfır runtime overhead ile.

04 UBSAN — Undefined Behavior Sanitizer

UBSAN, C standardının "undefined behavior" olarak tanımladığı durumları çalışma zamanında tespit eder. Derleyici varsayımlarına dayanan sessiz hatalar (taşan imzalı tamsayılar, geçersiz kaydırmalar vb.) burada yakalanır.

Konfigürasyon

Kconfig
CONFIG_UBSAN=y
CONFIG_UBSAN_TRAP=y         # UB tespit edilince kernel trap atar (önerilen)
# veya
CONFIG_UBSAN_SANITIZE_ALL=y # tüm kaynak dosyalarını instrumentation'a dahil et

# Belirli UB türleri
CONFIG_UBSAN_BOUNDS=y       # dizi sınırı aşımı
CONFIG_UBSAN_SHIFT=y        # geçersiz bit kaydırma
CONFIG_UBSAN_INTEGER_WRAP=y # işaretli tamsayı taşması

UBSAN'ın yakaladığı hatalar

C — UBSAN örnekleri
/* İşaretli tamsayı taşması (UB) */
int a = INT_MAX;
a = a + 1;   /* UBSAN: signed integer overflow */

/* Geçersiz bit kaydırma */
uint32_t x = 1;
x = x << 32; /* UBSAN: shift exponent >= width */
x = x << -1; /* UBSAN: shift exponent is negative */

/* Dizi sınırı dışı indeks */
int arr[8];
arr[8] = 0;  /* UBSAN: index 8 out of bounds for type 'int[8]' */

/* NULL pointer dereference */
int *p = NULL;
*p = 5;      /* UBSAN: null pointer dereference */

UBSAN raporu

dmesg — UBSAN raporu
================================================================================
UBSAN: signed-integer-overflow in drivers/my_driver/my_driver.c:142:14
s32 overflowed: 2147483647 + 1 cannot be represented in type 's32 (int)'

CPU: 1 PID: 1234 Comm: my_app Not tainted 6.6.0

Call Trace:
 dump_stack_lvl
 ubsan_epilogue
 handle_overflow
 my_driver_calc+0x8e/0xc0 [my_driver]   ← 142. satır
 my_driver_ioctl+0x44/0x90 [my_driver]
================================================================================

05 KMSAN — Kernel Memory Sanitizer

KMSAN, başlatılmamış (uninitialized) bellek kullanımını tespit eder. Kernel stack veya heap belleği başlatmadan kullanan kod, güvenlik açıklarına ve gizli bilgi sızıntısına yol açabilir.

Konfigürasyon

Kconfig
CONFIG_KMSAN=y
# Not: KMSAN, KASAN ile aynı anda etkinleştirilemez
# Not: x86-64 ve ARM64 destekler (6.1+ kernel)

KMSAN'ın yakaladığı hatalar

C — başlatılmamış bellek
/* Başlatılmamış stack değişkeni */
int my_func(void)
{
    int result;           /* başlatılmadı */
    if (some_condition())
        result = 42;
    return result;        /* KMSAN: result başlatılmamış olabilir */
}

/* Başlatılmamış yapı alanı */
struct my_msg {
    int type;
    int value;
    char pad[4];          /* doldurma — başlatılmamış */
};

struct my_msg msg;
msg.type = 1;
msg.value = 2;
/* msg.pad başlatılmamış */
copy_to_user(ubuf, &msg, sizeof(msg));  /* KMSAN: pad başlatılmamış */

KMSAN raporu

dmesg — KMSAN raporu
=====================================================
BUG: KMSAN: uninit-value in copy_to_user+0x7d/0xc0
  Uninit was created at:
   stack_depot_save
   kmsan_save_stack_with_flags
   my_ioctl_handler+0x3c/0x80 [my_driver]   ← başlatılmamış bölge

  Uninit was used at:
   copy_to_user+0x7d/0xc0
   my_ioctl_handler+0x65/0x80 [my_driver]   ← kullanım noktası
=====================================================
GÜVENLİK ÖNEMİ

Başlatılmamış kernel belleğini userspace'e kopyalamak (copy_to_user), kernel stack veya heap içeriğini ifşa edebilir. Bu tür bilgi sızıntısı (information disclosure) KASLR gibi güvenlik mekanizmalarını atlamamıza olanak tanır. KMSAN bu hataları otomatik olarak bulur.

06 KCSAN — Kernel Concurrency Sanitizer

KCSAN, kilit olmadan yapılan bellek erişimlerini (data race) tespit eder. Iki thread'in aynı bellek konumuna eş zamanlı erişmesi ve en az birinin yazmak olması durumunda uyarı verir.

Konfigürasyon

Kconfig
CONFIG_KCSAN=y
CONFIG_KCSAN_REPORT_ONCE_IN_MS=3000  # en fazla 3 saniyede bir rapor
CONFIG_KCSAN_UDELAY_TASK=80          # task bağlamında rastgele gecikme (µs)
CONFIG_KCSAN_UDELAY_INTERRUPT=20     # interrupt bağlamında gecikme (µs)

KCSAN mekanizması

KCSAN, rastgele seçilen bellek erişimlerinde kısa süreli "watchpoint" yerleştirir. Başka bir CPU eş zamanlı olarak aynı adrese erişirse iki erişim arasında veri yarışı olduğu sonucuna varır.

C — data race örneği
/* Kilit olmadan iki thread aynı değişkene yazıyor */
int shared_counter = 0;   /* global, kilitsiz */

/* Thread 1 */
void increment(void) { shared_counter++; }   /* data race */

/* Thread 2 */
void decrement(void) { shared_counter--; }   /* data race */

/* Doğru yaklaşım: atomik işlem veya kilit */
atomic_t shared_counter = ATOMIC_INIT(0);
void increment(void) { atomic_inc(&shared_counter); }  /* güvenli */

KCSAN raporu

dmesg — KCSAN raporu
==================================================================
BUG: KCSAN: data-race in increment+0x14/0x20 / decrement+0x14/0x20

write to 0xffffffff82345678 of 4 bytes by task 123 on cpu 1:
 increment+0x14/0x20

read to 0xffffffff82345678 of 4 bytes by task 456 on cpu 0:
 decrement+0x14/0x20
==================================================================
READ_ONCE / WRITE_ONCE

Kasıtlı olarak kilitsiz erişim yapıyorsanız (lock-free programming) READ_ONCE() ve WRITE_ONCE() makrolarını kullanın. KCSAN bu makroları gördüğünde raporlamayı atlar — erişimin kasıtlı olduğu anlaşılır.

07 Sanitizer performans maliyeti

Sanitizer'ların performans etkisi, hangi sanitizer'ın kullanıldığına ve hedef platforma göre önemli ölçüde değişir. Bu bilgi, hangi sanitizer'ın hangi ortamda kullanılacağını belirlemek için kritiktir.

SanitizerCPU overheadBellek overheadKod boyutuÜretim?
KASAN Generic~1.5–2x~2x (shadow)~1.5xHayır
KASAN SW Tag~1.2–1.5x~1.5x~1.3xHayır
KASAN HW (MTE)~1.02xminimal~1.1xAday
UBSAN~1.05–1.15xminimal~1.2xHayır
KMSAN~2.5–3x~3x~2xHayır
KCSAN~1.3–1.5xminimal~1.15xHayır

Gömülü sistemlerde sanitizer kullanımı

FLASH VE RAM KISITLARI

KASAN Generic için shadow memory, kernel'ın kullandığı RAM'ın ~1/8'i kadar ek alan gerektirir. 128 MB RAM'li bir sistem için 16 MB shadow bellek demektir. Bellek kısıtlı gömülü sistemlerde bu kabul edilemez olabilir. KASAN HW (MTE) bu sorunu çözer ama ARM v8.5+ gerektirir.

Sanitizer kernel yapılandırma stratejisi

Kconfig — debug kernel
# Ayrı bir debug kernel yapılandırması oluştur
# (üretim .config dosyasından türetilmiş, sanitizer'lar ekli)

# Üretim .config al
cp /path/to/production.config .config

# Sanitizer'ları ekle
scripts/config --enable CONFIG_KASAN
scripts/config --enable CONFIG_KASAN_GENERIC
scripts/config --enable CONFIG_UBSAN
scripts/config --enable CONFIG_KASAN_MULTI_SHOT

# Debug build yap (üretim kernel'ı etkilemez)
make -j$(nproc) LOCALVERSION="-kasan-debug"

08 Pratik: KASAN ile driver bug bul

Gerçek dünya senaryosu: bir DMA buffer yönetimi sürücüsünde zaman zaman kernel oops'u oluşuyor ama tetikleme koşulları tutarsız. KASAN ile sistematik bulma.

Kasıtlı out-of-bounds bug içeren sürücü

buggy_dma_driver.c
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>

#define BUF_SIZE 64

static char *dma_buf;

static int __init buggy_init(void)
{
    int i;

    dma_buf = kmalloc(BUF_SIZE, GFP_KERNEL);
    if (!dma_buf)
        return -ENOMEM;

    pr_info("DMA buffer tahsis edildi: %p, boyut=%d\n", dma_buf, BUF_SIZE);

    /* BUG: döngü sınırı 1 fazla — 65. byte'a yazıyor */
    for (i = 0; i <= BUF_SIZE; i++)   /* <= yerine < olmalıydı */
        dma_buf[i] = (char)(i & 0xFF);

    pr_info("Buffer başlatıldı\n");
    return 0;
}

static void __exit buggy_exit(void)
{
    kfree(dma_buf);
    pr_info("DMA buffer serbest bırakıldı\n");
}

module_init(buggy_init);
module_exit(buggy_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Kasıtlı OOB bug — KASAN demo");

KASAN raporunu tetikle ve oku

bash
insmod buggy_dma_driver.ko
dmesg | grep -A 40 'BUG: KASAN'
dmesg — KASAN çıktısı
==================================================================
BUG: KASAN: slab-out-of-bounds in buggy_init+0x68/0xa4 [buggy_dma_driver]
Write of size 1 at addr ffff000012ab8040 by task insmod/1234

CPU: 0 PID: 1234 Comm: insmod

Call Trace:
 kasan_report
 __asan_report_store1_noabort
 buggy_init+0x68/0xa4 [buggy_dma_driver]  ← 65. byte yazma
 do_init_module

Allocated by task 1234:
 kmalloc_trace
 buggy_init+0x30/0xa4 [buggy_dma_driver]  ← BUF_SIZE=64 tahsis

The buggy address is located 0 bytes to the right of
 64-byte region [ffff000012ab8000, ffff000012ab8040)
                                        ^
                                        ffff...8040 = tam sınır

Memory state:
 ffff000012ab8000: 00 00 00 00 00 00 00 00   ← temiz (initialized)
 ffff000012ab8020: 00 00 00 00 00 00 00 00
 ffff000012ab8040: fc fc fc fc fc fc fc fc   ← right redzone
                  ^
                  KASAN'ın işaret ettiği adres
==================================================================

Hatayı düzelt ve doğrula

C — düzeltilmiş kod
/* BUG: for (i = 0; i <= BUF_SIZE; i++) */
/* FIX: */
for (i = 0; i < BUF_SIZE; i++)   /* < ile BUF_SIZE dahil değil */
    dma_buf[i] = (char)(i & 0xFF);

Hatırlanacaklar

  • KASAN Generic: shadow memory ile out-of-bounds ve use-after-free — debug kernel için standart
  • KASAN raporu: BUG tipi → Call Trace → "Allocated by" → Memory state — bu sıraya göre oku
  • KASAN HW (MTE): ARM v8.5+ için yaklaşık sıfır overhead — üretim adayı
  • UBSAN: signed overflow, shift exponent, dizi indeksi — C UB'yi çalışma zamanında yakala
  • KMSAN: başlatılmamış bellek → bilgi sızıntısı güvenlik açığı — copy_to_user öncesi kontrol et
  • KCSAN: data race — kilitsiz paylaşılan erişimi READ_ONCE/WRITE_ONCE veya atomik işlemlerle belgele
  • Sanitizer kernel = ayrı bir debug build — üretim kernel'ını etkilemez

Bir sonraki adım: kdump & crash rehberi — kernel crash sonrası analiz.