eBPF Araclar ve Kavramlar

Verifier Hatalarini Duzelt

BPF Verifier güvenlik mekanizması ve BTF/CO-RE ile program taşınabilirliği.

Verifier

Lab: eBPF Verifier

Bu lab’da öğrenecekleriniz:

  • License kontrolleri (GPL gereksinimi)
  • Zorunlu NULL pointer kontrolleri
  • Bounds checking
  • Complexity limit

Verifier Kuralları

Bu kurallara eBPFHub egzersizlerinde karşılaşacaksınız:

KuralHata Mesajı
Map lookup sonrası NULL checkR0 invalid mem access 'map_value_or_null'
Stack buffer sabit boyutvariable stack access var_off
Loop bounds derleme zamanıback-edge from insn X to Y
Pointer arithmetic kısıtlıR1 pointer arithmetic prohibited

Verifier Güvenlik Garantileri

  • Termination: Sabit loop bounds, maksimum complexity limit
  • Memory Safety: Rastgele pointer yok, helper function kullanımı zorunlu
  • Bounds Check: Her array erişiminde sınır kontrolü
  • NULL Check: Map lookup sonucu her zaman kontrol edilmeli

Yaygın Hatalar ve Çözümleri

1. Map lookup sonrası NULL check eksik:

// HATALI — verifier reddeder
char *val = bpf_map_lookup_elem(&my_map, &key);
bpf_printk("value: %s", val);  // R0 NULL olabilir!

// DOĞRU
char *val = bpf_map_lookup_elem(&my_map, &key);
if (!val) return 0;             // NULL check zorunlu
bpf_printk("value: %s", val);

2. Sınırsız döngü:

// HATALI — verifier reddeder: "back-edge from insn X to Y"
for (int i = 0; i < len; i++) {   // 'len' runtime değer
    buf[i] = 0;
}

// DOĞRU — derleme zamanı sabit sınır
#pragma unroll
for (int i = 0; i < 64; i++) {    // sabit sınır
    if (i >= len) break;
    buf[i] = 0;
}

3. Paket erişiminde sınır kontrolü eksik (XDP):

// HATALI — verifier reddeder: "invalid access to packet"
struct iphdr *ip = data + sizeof(struct ethhdr);
__u32 src = ip->saddr;  // sınır kontrolü yok!

// DOĞRU — her zaman erişmeden önce kontrol et
struct iphdr *ip = data + sizeof(struct ethhdr);
if ((void *)(ip + 1) > data_end)
    return XDP_PASS;
__u32 src = ip->saddr;  // sınır kontrolünden sonra güvenli

Pratik: Kasıtlı olarak bir verifier hatası tetikleyin, mesajı anlayın ve düzeltin.

Araç: ebpf-cover - VS Code extension, verifier log’larından code coverage görselleştirmesi.


BTF ve CO-RE (Taşınabilirlik)

Lab 1: Portable eBPF Programs

Bu lab’da öğrenecekleriniz:

  • Programların neden farklı kernel’larda çalışmayabileceği
  • vmlinux.h nedir
  • BPF_CORE_READ macro
  • BTF (BPF Type Format)

vmlinux.h Oluşturma

bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h

Bu tek header dosyası, kernel header’larını kurmadan tüm kernel type’larına erişim sağlar.

BPF_CORE_READ

Farklı kernel versiyonlarında iç içe struct field’larını okuma:

#include "vmlinux.h"
#include <bpf/bpf_core_read.h>

SEC("kprobe/tcp_connect")
int trace(struct pt_regs *ctx) {
    struct sock *sk = (void *)PT_REGS_PARM1(ctx);

    // CO-RE OLMADAN — struct layout kernel'lar arasında değişirse bozulur
    // __u16 port = sk->__sk_common.skc_dport;

    // CO-RE İLE — kernel versiyonları arasında çalışır
    __u16 port = BPF_CORE_READ(sk, __sk_common.skc_dport);
    return 0;
}

BPF_CORE_READ relocatable okuma üretir — loader, çalışan kernel’ın BTF bilgisine göre field offset’lerini yükleme zamanında ayarlar.

Lab 2: Truly Portable eBPF

Bu lab’da öğrenecekleriniz:

  • BTFHub kullanımı
  • Minimal BTF oluşturma
  • BTF olmayan kernel’larda çalıştırma

Not: Go + bpf2go kullanırken çoğu şey otomatiktir. Ama işlerin neden bu şekilde çalıştığını anlayın.

Run your code to see execution events here