2 poin oleh GN⁺ 2024-07-28 | 1 komentar | Bagikan ke WhatsApp
  • Linux Kernel Module Programming Guide adalah panduan gratis untuk membuat modul kernel yang dapat dimuat pada Linux v5.10 ke atas, mencakup alur lengkap dari lingkungan pengembangan hingga build, load, debugging, dan antarmuka kernel utama
  • Contoh awal menggunakan hello-*.c untuk mempelajari module_init(), module_exit(), kbuild, insmod, rmmod, dan dmesg, serta memakai devtools berbasis QEMU untuk mengurangi risiko merusak sistem host
  • Karena modul kernel berjalan di ruang alamat kernel, pointer yang salah, urutan unload, concurrency, dan kesalahan penyalinan memori pengguna dapat menyebabkan korupsi memori kernel atau ketidakstabilan sistem
  • Cakupan diperluas ke perangkat karakter, /proc, seq_file, threaded IRQ, input, PCI, USB, block, network, Device Model, Device Tree, hingga static key, sambil berulang kali membahas urutan registrasi dan pelepasan serta pengelolaan lifetime
  • Karena API internal kernel berubah menurut versi, perlu memeriksa kondisi seperti LINUX_VERSION_CODE, KERNEL_VERSION, CONFIG_MODVERSIONS, penandatanganan SecureBoot, dan version magic, dan contoh-contohnya juga mencakup kompilasi kondisional

Struktur panduan dan alur dasar

  • Panduan ini adalah materi pembelajaran modul kernel yang menyediakan repositori GitHub dan dokumen PDF, serta dapat disalin, dimodifikasi, dan didistribusikan di bawah ketentuan Open Software License 3.0
  • Saat ini panduan menetapkan Linux v5.10 sebagai batas minimum yang didukung, dan bertujuan menjaga kompatibilitas contoh serta petunjuk di berbagai kernel dukungan jangka panjang
  • Pembelajar perlu menguasai bahasa C dan memiliki pengalaman menulis program untuk proses umum, sementara modul kernel dimuat dan dilepas secara dinamis untuk memperluas fungsi kernel tanpa reboot
  • Alur pengembangan dasar berlanjut dari pemasangan header kernel, build .ko dengan make, pemeriksaan dengan modinfo, load dengan insmod, pengecekan log dengan dmesg atau journalctl -k, lalu unload dengan rmmod
  • devtools/ membangun source kernel dan root filesystem BusyBox lalu melakukan boot di QEMU, membagikan examples/ melalui 9p virtfs, dan memungkinkan pengujian modul di guest
  • Untuk inisialisasi dan pembersihan modul, penggunaan module_init() dan module_exit() lebih disarankan, sedangkan pendekatan lama init_module() dan cleanup_module() dapat menyebabkan kegagalan build dalam kondisi tertentu pada kernel 6.15 ke atas saat x86 IBT aktif
  • Modul kernel tidak menggunakan printf() atau libc dan hanya dapat memakai simbol yang diekspor kernel, sementara output dikirim bukan ke terminal melainkan ke ring buffer log kernel
  • Pemindahan data antara ruang pengguna dan ruang kernel memerlukan fungsi khusus seperti put_user, get_user, copy_to_user, dan copy_from_user
  • Contoh perangkat karakter menunjukkan register_chrdev, file_operations, dynamic major number, pembuatan node /dev, exclusive open, read berbasis put_user, dan penanganan write yang tidak didukung
  • Contoh /proc membahas proc_create, proc_ops, callback read/write, dan API seq_file, serta mencerminkan perubahan setelah Linux v5.6 ketika proc_ops diperkenalkan untuk handler /proc menggantikan file_operations
  • Threaded IRQ memisahkan top-half dan bottom-half dengan request_threaded_irq(), di mana top-half hanya melakukan pekerjaan minimal dalam interrupt context lalu membangunkan bottom-half berbasis thread dengan IRQ_WAKE_THREAD
  • Bab-bab berikutnya meluas ke area driver nyata seperti input, PCI, USB, block, network, Device Model, dan Device Tree, berfokus pada cara registrasi setiap subsystem dan pemilihan ABI userspace
  • Bagian optimasi dan keamanan membahas likely dan unlikely, static key, stack kernel yang kecil, larangan penggunaan FPU, kebocoran padding yang belum diinisialisasi, dan kehati-hatian saat memakai API internal dengan double underscore

Kendala awal saat build dan load

  • Modul yang dikompilasi untuk satu kernel mungkin tidak dapat dimuat pada kernel lain, dan jika version magic serta CONFIG_MODVERSIONS tidak cocok, dapat muncul Invalid module format atau ketidakcocokan versi simbol
  • Sebagian besar kernel distribusi Linux umum mungkin mengaktifkan modversioning, sehingga jika contoh tidak langsung berjalan, perlu mempertimbangkan kernel dengan modversioning dimatikan atau lingkungan QEMU
  • Pada sistem dengan SecureBoot aktif, pemuatan modul tanpa tanda tangan bisa dibatasi, dan jika muncul Lockdown: insmod: unsigned module loading is restricted, perlu menonaktifkan SecureBoot atau menjalankan prosedur penandatanganan modul

Lingkungan praktik berbasis QEMU

  • devtools/setup.sh mengunduh dan membangun tarball kernel serta BusyBox, lalu memaketkan initramfs
  • devtools/build-modules.sh membangun modul untuk kernel target QEMU, devtools/boot.sh menyediakan shell guest, dan devtools/test-modules.sh menjalankan pengujian otomatis insmod dan rmmod per modul
  • Debugging GDB dilakukan dengan membangun vmlinux melalui LKMPG_NO_PREBUILT=1 devtools/setup.sh, lalu menggunakan devtools/boot.sh --gdb dan koneksi GDB jarak jauh

Aturan penulisan kode kernel

  • Dalam fungsi init, registrasi dan alokasi bisa gagal, sehingga resource yang sudah diperoleh harus dilepas dalam urutan terbalik melalui jalur error berbasis goto
  • Jika struktur callback didaftarkan ke kernel, userspace dapat memanggil callback bahkan sebelum init selesai mengembalikan nilai, sehingga aturan register last, unregister first penting: selesaikan inisialisasi internal lebih dulu, daftarkan paling akhir, dan saat teardown lepaskan lebih dahulu
  • Process context, softirq/tasklet context, dan hardirq context berbeda dalam hal boleh tidaknya sleep, akses memori pengguna, GFP_KERNEL, dan penggunaan mutex, dan salah memahami perbedaan ini dapat menimbulkan bug kernel yang umum

Hal yang perlu diperhatikan per perangkat dan subsystem

  • Perangkat karakter memakai major number untuk mengidentifikasi driver dan minor number untuk membedakan beberapa perangkat di dalam driver, dan pada pendekatan modern, antarmuka cdev lebih disarankan daripada register_chrdev()
  • Driver PCI tidak mengasumsikan alamat tetap, melainkan memetakan BAR resource yang dienumerasi oleh PCI core, dan pada kode Linux 5.10 ke atas, pcim_enable_device() serta device-managed resource API berguna untuk mengurangi bug teardown
  • Driver USB harus memperlakukan hotplug dan disconnect sebagai kejadian normal, dan dirancang dengan asumsi bahwa URB completion dapat berpacu dengan disconnect, timeout, suspend, dan shutdown dari userspace
  • Driver block bekerja dengan blk-mq, request, gendisk, queue limit, dan semantik flush/FUA, dan berpartisipasi dalam model penyelesaian request asinkron, bukan callback read/write sederhana
  • Driver jaringan terikat dengan struct net_device, net_device_ops, sk_buff, NAPI, offload feature flag, dan pelaporan link-state, dan deklarasi offload yang salah dapat menyebabkan kerusakan lalu lintas

Menangani perubahan versi kernel

  • Contoh menangani perubahan signature class_create() di Linux 6.4, proc_ops di Linux v5.6, perubahan tipe nilai balik remove() di Linux 6.11, serta perubahan helper blk-mq antara Linux 5.15 hingga 6.9 melalui kompilasi kondisional
  • Karena antarmuka internal kernel berubah lebih sering daripada system call, modul yang mendukung banyak kernel sulit menghindari perbandingan LINUX_VERSION_CODE dan KERNEL_VERSION

Checkpoint keamanan

  • Stack kernel jauh lebih kecil daripada stack ruang pengguna, dan pada banyak sistem hanya sekitar 8 KiB atau 16 KiB, sehingga array besar sebaiknya menggunakan kmalloc() atau kzalloc()
  • Saat mengirim data ke ruang pengguna dengan copy_to_user(), semua byte termasuk padding harus sudah diinisialisasi; jika tidak, dapat terjadi kebocoran informasi memori kernel
  • API yang diawali double underscore seperti __kmalloc() dan __list_add() dapat mengasumsikan prasyarat internal, sehingga jika dokumentasi tidak memintanya, sebaiknya utamakan wrapper publik

Cakupan yang dihilangkan

  • Disebutkan bahwa beberapa chunk asli dihilangkan selama pemrosesan input karena batas panjang dan biaya, sehingga ringkasan ini tidak membahas setiap bab, contoh, dan jalur kode dalam panduan secara lengkap

1 komentar

 
GN⁺ 2024-07-28
Komentar Hacker News
  • QEMU adalah cara yang bagus untuk mencoba pengalaman meretas kernel
    Akan menyenangkan jika ada yang memperbarui LDD(Linux Device Drivers) dan buku-buku kernel Linux; karena buku teknis seperti ini sulit menghasilkan keuntungan, sepertinya Linux Foundation juga bisa mensponsorinya

    • Ada tulisan yang sedikit membahas proses menulis driver dan membuat lalu memasang perangkat kustom dengan QEMU: [0] https://blog.davidv.dev/posts/learning-pcie/, [1] https://blog.davidv.dev/posts/pcie-driver-dma/
    • Menggunakan virtme-ng https://github.com/arighi/virtme-ng membuat menjalankan kernel yang sedang dikembangkan di QEMU menjadi sangat mudah
    • QEMU banyak dipakai untuk debugging kernel tahap awal yang bahkan belum memiliki konsol
      Minggu ini juga, saya mereproduksi dengan QEMU + GDB masalah di v6.8 ketika parameter command line kernel arm64 sepanjang 146 karakter atau lebih membuat kernel langsung berhenti diam-diam, lalu mengemulasikan build kernel arm64 di host Debian 12 Bookworm amd64 dan menelusuri kode bermasalah baris demi baris untuk menemukan penyebabnya
      Alurnya adalah, di lingkungan yang sudah memiliki dependensi build dan tool cross-compile, build image kernel arm64 dan skrip untuk GDB, lalu pasang gdb, jika perlu gdb-multiarch, serta qemu-system-arm di host, kemudian jalankan qemu-system-aarch64 dalam keadaan berhenti dengan -S -gdb tcp::1234, dan dari terminal lain attach dengan gdb-multiarch ./vmlinux
      Setelah itu, di GDB jalankan target remote :1234, break __parse_cmdline, continue, maka fitur GDB umum seperti memeriksa memori·variabel·stack dan eksekusi satu langkah bisa digunakan
      Untuk debugging kernel dengan GDB dan skrip lx-*, lihat https://www.kernel.org/doc/html/latest/dev-tools/gdb-kernel-...
      Agar GDB dapat memakai skrip Python lx-*, biasanya perlu juga mengizinkan path, misalnya echo "add-auto-load-safe-path ${SRC_DIR}/scripts/gdb/vmlinux-gdb.py" > ~/.gdbinit
    • Kumpulan tes WireGuard yang sekarang masuk ke kernel adalah contoh yang bagus untuk mengembangkan modul kernel dengan QEMU sekaligus mencoba pengujian otomatis
    • Greg KH pernah mengatakan dengan cukup jelas bahwa LDD edisi ke-4 tidak akan terbit
  • Thread HN terkait: https://news.ycombinator.com/item?id=35782630, https://news.ycombinator.com/item?id=28283030

  • The Linux Memory Manager juga layak dijadikan referensi: https://linuxmemory.org/chapters
    Menurut pembaruan terakhir yang dikirim penulis pada awal Juli, draf pertama sudah selesai, dan sekarang sudah masuk tahap penyuntingan bersama penerbit

    • Daftar isinya terlihat bagus, sayang tidak ada pre-order untuk mendukung produksinya
  • Beberapa contoh tampaknya sulit dijalankan langsung
    Misalnya “Detecting button presses” mengasumsikan kita bisa membangun modul untuk RPi, tetapi itu sendiri bisa menuntut pekerjaan seperti cross-compiling sehingga mungkin tidak sederhana

    • Meski agak merepotkan, bukankah cukup menjalankan compiler di Raspberry Pi saja?
  • Sangat bagus karena rinci, berorientasi praktik, dan berupa tutorial yang langsung mencoba membangun modul kernel

  • Materi lain yang layak dibaca bersama: https://0xax.gitbooks.io/linux-insides/content/index.html

  • Saya penasaran di mana tempat yang bagus untuk mempelajari pemrograman kernel Linux secara umum, seperti filesystem atau manajemen memori
    Dulu ada “Linux Kernel Development” karya Robert Love, tetapi sepertinya sekarang tidak lagi diperbarui

  • Pertama kali saya membaca ini sekitar 22 tahun lalu :)