2 puan yazan GN⁺ 2024-07-28 | 1 yorum | WhatsApp'ta paylaş
  • Linux Kernel Module Programming Guide, Linux v5.10 ve üzeri için yüklenebilir çekirdek modülleri oluşturmaya yönelik ücretsiz bir rehberdir; geliştirme ortamından derleme, yükleme, hata ayıklama ve başlıca çekirdek arayüzlerine kadar süreci uçtan uca ele alır
  • İlk örnekler hello-*.c üzerinden module_init(), module_exit(), kbuild, insmod, rmmod, dmesg kullanımını öğretir; QEMU tabanlı devtools ile ana sistemin zarar görme riskini azaltır
  • Çekirdek modülleri çekirdek adres alanında çalıştığından hatalı işaretçiler, unload sırası, eşzamanlılık ve kullanıcı belleği kopyalama hataları çekirdek belleği bozulmasına veya sistem kararsızlığına yol açabilir
  • Karakter aygıtları, /proc, seq_file, threaded IRQ, input, PCI, USB, blok, ağ, Device Model, Device Tree ve static key’e kadar genişler; kayıt–kaldırma sırası ve lifetime yönetimini tekrar tekrar işler
  • Çekirdek içi API’ler sürüme göre değiştiği için LINUX_VERSION_CODE, KERNEL_VERSION, CONFIG_MODVERSIONS, SecureBoot imzası ve version magic gibi koşulları kontrol eder; örnekler de koşullu derleme içerir

Rehberin yapısı ve temel akış

  • Bu rehber, GitHub deposu ve PDF belgesi sunan bir çekirdek modülü öğrenme kaynağıdır; Open Software License 3.0 koşullarıyla kopyalanabilir, değiştirilebilir ve dağıtılabilir
  • Mevcut rehber Linux v5.10’u asgari destek ölçütü olarak alır ve uzun süreli destek çekirdekleri genelinde örneklerin ve yönergelerin uyumluluğunu korumayı hedefler
  • Öğrenenlerin C dili ve genel proseslere yönelik program yazma deneyimine sahip olması gerekir; çekirdek modülleri dinamik olarak yüklenip kaldırılarak yeniden başlatma gerektirmeden çekirdek işlevlerini genişletir
  • Temel geliştirme akışı; çekirdek header’larının kurulması, make ile .ko derlenmesi, modinfo kontrolü, insmod ile yükleme, dmesg veya journalctl -k ile günlüklerin incelenmesi ve rmmod ile unload adımlarından oluşur
  • devtools/, çekirdek kaynaklarını ve BusyBox kök dosya sistemini derleyip QEMU’da boot eder; examples/ dizinini 9p virtfs ile paylaşarak modüllerin konuk sistemde test edilmesini sağlar
  • Modül başlatma ve temizleme için module_init()·module_exit() kullanımı tercih edilir; eski init_module()·cleanup_module() yöntemi, x86 IBT’nin etkin olduğu 6.15 sonrası çekirdeklerde bazı koşullarda derleme hatasına neden olabilir
  • Çekirdek modülleri printf() veya libc kullanmaz, yalnızca çekirdeğin export ettiği sembolleri kullanabilir; çıktı terminale değil çekirdek log ring buffer’ına gider
  • Kullanıcı alanı ile çekirdek alanı arasında veri taşımak için put_user, get_user, copy_to_user, copy_from_user gibi özel fonksiyonlar gerekir
  • Karakter aygıtı örneği register_chrdev, file_operations, dinamik major number, /dev node’u oluşturma, exclusive open, put_user tabanlı read ve desteklenmeyen write işlemesini gösterir
  • /proc örneği proc_create, proc_ops, read/write callback’leri ve seq_file API’sini ele alır; Linux v5.6’dan sonra /proc handler’larında file_operations yerine proc_ops getirilen değişikliği yansıtır
  • threaded IRQ, request_threaded_irq() ile top-half ve bottom-half’i ayırır; top-half interrupt context’te yalnızca asgari işi yapar ve IRQ_WAKE_THREAD ile thread tabanlı bottom-half’i uyandırır
  • Sonraki bölümler input, PCI, USB, blok, ağ, Device Model ve Device Tree gibi gerçek sürücü alanlarına genişler; her subsystem’in kayıt yöntemi ve userspace ABI seçimi odağında ilerler
  • Optimizasyon ve güvenlik bölümü likely·unlikely, static key, küçük çekirdek stack’i, FPU kullanım yasağı, başlatılmamış padding sızıntıları ve double-underscore iç API kullanımına dikkat edilmesini işler

Derleme ve yüklemede ilk karşılaşılan kısıtlar

  • Bir çekirdek için derlenen modül başka bir çekirdekte yüklenmeyebilir; version magic ve CONFIG_MODVERSIONS eşleşmezse Invalid module format veya sembol sürümü uyuşmazlığı oluşur
  • Çoğu genel Linux dağıtımı çekirdeğinde modversioning etkin olabilir; örnekler doğrudan çalışmazsa modversioning kapalı bir çekirdek veya QEMU ortamı düşünülmelidir
  • SecureBoot açık sistemlerde imzasız modül yükleme kısıtlanabilir; Lockdown: insmod: unsigned module loading is restricted görülürse SecureBoot’u devre dışı bırakmak veya modül imzalama süreci gerekir

QEMU tabanlı pratik ortamı

  • devtools/setup.sh, çekirdek tarball’ını ve BusyBox’ı indirip derler ve initramfs’i paketler
  • devtools/build-modules.sh, QEMU çekirdeği hedefli modülleri derler; devtools/boot.sh konuk shell’i sağlar; devtools/test-modules.sh ise modül bazında insmod·rmmod otomatik testleri yürütür
  • GDB ile hata ayıklama, LKMPG_NO_PREBUILT=1 devtools/setup.sh ile vmlinux derlendikten sonra devtools/boot.sh --gdb ve uzak GDB bağlantısıyla yapılır

Çekirdek kodu yazma kuralları

  • init fonksiyonunda kayıt ve ayırma işlemleri başarısız olabileceğinden, edinilen kaynaklar goto tabanlı hata yollarında ters sırayla serbest bırakılmalıdır
  • Çekirdeğe bir callback yapısı kaydedildiğinde kullanıcı alanı init dönüşünden önce bile callback’i çağırabileceği için, iç başlatmayı bitirdikten sonra en sonda kayıt yapmak ve kaldırmayı önce yapmak anlamındaki register last, unregister first kuralı önemlidir
  • process context, softirq/tasklet context ve hardirq context; sleep, kullanıcı belleğine erişim, GFP_KERNEL ve mutex kullanımının mümkün olup olmaması açısından farklıdır; bu ayrımı yanlış anlamak yaygın çekirdek hatalarına yol açar

Aygıtlar ve subsystem’lere göre dikkat noktaları

  • Karakter aygıtları sürücüyü major number ile, sürücü içindeki birden çok aygıtı ise minor number ile ayırt eder; modern yöntemde register_chrdev() yerine cdev arayüzü önerilir
  • PCI sürücüleri sabit adres varsaymaz; PCI core tarafından enumerate edilen BAR resource’larını map eder. Linux 5.10 sonrası kodlarda pcim_enable_device() ve device-managed resource API, teardown hatalarını azaltmada kullanışlıdır
  • USB sürücüleri hotplug ve disconnect’i normal olaylar olarak ele almalıdır; URB completion ile disconnect, timeout, suspend ve userspace shutdown’ın yarışabileceği varsayımıyla tasarlanmalıdır
  • Blok sürücüleri blk-mq, request, gendisk, queue limit ve flush/FUA semantics etrafında çalışır; basit read/write callback’i değil asenkron request completion modeline katılır
  • Ağ sürücüleri struct net_device, net_device_ops, sk_buff, NAPI, offload feature flag’leri ve link-state raporlamasıyla birleşir; hatalı offload beyanı trafik bozulmasına yol açabilir

Çekirdek sürümü değişikliklerine uyum

  • Örnekler; Linux 6.4’teki class_create() imza değişikliğini, Linux v5.6’daki proc_ops’u, Linux 6.11’deki remove() dönüş tipi değişikliğini ve Linux 5.15–6.9 arasındaki blk-mq helper değişikliklerini koşullu derlemeyle ele alır
  • Çekirdek içi arayüzler sistem çağrılarından daha sık değiştiği için, birden çok çekirdeği destekleyen modüllerde LINUX_VERSION_CODE ve KERNEL_VERSION karşılaştırmalarından kaçınmak zordur

Güvenlik kontrol noktaları

  • Çekirdek stack’i kullanıcı alanı stack’inden çok daha küçüktür ve birçok sistemde 8 KiB veya 16 KiB düzeyinde olabilir; büyük diziler için kmalloc()·kzalloc() kullanılmalıdır
  • copy_to_user() ile kullanıcı alanına veri gönderirken padding dahil tüm byte’ların başlatılmış olması gerekir; aksi halde çekirdek belleği bilgi sızıntısı oluşabilir
  • __kmalloc(), __list_add() gibi double underscore ile başlayan API’ler iç önkoşullar varsayabilir; dokümantasyon gerektirmedikçe önce public wrapper kullanılmalıdır

Kapsam dışında bırakılanlar

  • Girdi işleme sırasında bazı özgün metin parçalarının uzunluk ve maliyet sınırları nedeniyle atlandığı belirtilmiştir; bu nedenle bu özet rehberin tamamındaki tüm bölümleri, örnekleri ve kod yollarını eksiksiz kapsamaz

1 yorum

 
GN⁺ 2024-07-28
Hacker News yorumları
  • QEMU, kernel hacklemeyi deneyimlemek için iyi bir yöntem
    Birilerinin LDD(Linux Device Drivers) ve Linux kernel kitaplarını güncellemesi güzel olurdu; bu tür teknik kitaplardan gelir elde etmek zor olduğu için Linux Foundation’ın sponsor olması da iyi olabilir

    • Sürücü yazmayı ve QEMU ile özel bir aygıt oluşturup bağlamayı biraz anlatan bir yazı var: [0] https://blog.davidv.dev/posts/learning-pcie/, [1] https://blog.davidv.dev/posts/pcie-driver-dma/
    • virtme-ng https://github.com/arighi/virtme-ng kullanınca QEMU’da geliştirilmekte olan kerneli başlatmak gerçekten kolaylaşıyor
    • Konsolun bile olmadığı erken aşama kernel hata ayıklama için QEMU sıkça kullanılıyor
      Bu hafta da v6.8’de arm64 kernel komut satırı parametresi 146 karakterden uzunsa kernelin anında ve sessizce durması sorununu QEMU + GDB ile yeniden ürettim; Debian 12 Bookworm amd64 host üzerinde arm64 kernel derlemesini emüle edip sorunlu kodu satır satır izleyerek nedeni buldum
      Akış, derleme bağımlılıkları ve çapraz derleme araçlarının hazır olduğu bir ortamda arm64 kernel imajını ve GDB için scriptleri derlemek; host’a gdb, gerekirse gdb-multiarch ve qemu-system-arm kurmak; ardından qemu-system-aarch64ı -S -gdb tcp::1234 ile durdurulmuş durumda başlatıp başka bir terminalden gdb-multiarch ./vmlinux ile bağlanmak şeklinde
      Sonrasında GDB’de target remote :1234, break __parse_cmdline, continue çalıştırılırsa bellek, değişken ve stack inceleme ile tek adım yürütme gibi normal GDB özellikleri kullanılabiliyor
      Kernel GDB hata ayıklama ve lx-* scriptleri için bkz. https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-...
      GDB’nin lx-* Python scriptlerini kullanabilmesi için genelde echo "add-auto-load-safe-path ${SRC_DIR}/scripts/gdb/vmlinux-gdb.py" > ~/.gdbinit gibi path’e izin vermek de gerekiyor
    • Şu anda kernele dahil olan WireGuard test paketi, QEMU ile kernel modülü geliştirmeyi ve otomatik testleri denemeyi sağlayan iyi bir örnek
    • Greg KH, LDD 4. baskının çıkmayacağını oldukça net söylemişti
  • İlgili HN başlıkları: https://news.ycombinator.com/item?id=35782630, https://news.ycombinator.com/item?id=28283030

  • The Linux Memory Manager da bakmaya değer: https://linuxmemory.org/chapters
    Yazarın temmuz başında gönderdiği son güncellemeye göre ilk taslağı bitirmiş ve şu anda yayıneviyle birlikte editörlük aşamasına geçmiş

    • İçindekiler iyi görünüyor, ancak üretimi destekleyecek bir ön sipariş olmaması üzücü
  • Bazı örnekleri doğrudan çalıştırmak zor görünüyor
    Örneğin “Detecting button presses”, RPi için modül derlenebildiğini varsayıyor; bu da başlı başına çapraz derleme gibi işler gerektirdiğinden basit olmayabilir

    • Biraz zahmetli olsa da, doğrudan Raspberry Pi üzerinde derleyiciyi çalıştırmak yeterli olmaz mı diye düşünüyorum
  • Ayrıntılı, pratik odaklı ve doğrudan kernel modülü derlemeyi deneten bir öğretici olduğu için harika

  • Birlikte bakılabilecek kaynak: https://0xax.gitbooks.io/linux-insides/content/index.html

  • Dosya sistemi veya bellek yönetimi gibi genel Linux kernel programlama konuları için nereye bakmanın iyi olacağını merak ediyorum
    Eskiden Robert Love’ın “Linux Kernel Development” kitabı vardı, ama artık güncellenmiyor gibi

  • Bunu ilk okuduğumda yaklaşık 22 yıl önceydi :)