Skip to content

Week 21 - Loadable Kernel Modules (LKM)

21.1 Conceptual Core

  • A loadable kernel module is C code compiled against the running kernel's headers, loaded via insmod/modprobe, and unloaded via rmmod. It runs at ring 0, with full kernel privileges. There is no safety net: a bug crashes the box.
  • The legitimate uses for LKMs in 2026 are narrow: device drivers for hardware not supported by mainline, niche filesystem additions, specific tracing or security modules that cannot be expressed as eBPF.
  • For most "I want to extend the kernel" needs today, eBPF is the right answer. Pick LKM only when you genuinely cannot express the work in eBPF.

21.2 Mechanical Detail

  • The skeleton:
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    static int __init mymod_init(void) { pr_info("hello\n"); return 0; }
    static void __exit mymod_exit(void) { pr_info("bye\n"); }
    module_init(mymod_init);
    module_exit(mymod_exit);
    MODULE_LICENSE("GPL");
    
  • Build via a Makefile:
    obj-m += mymod.o
    KDIR := /lib/modules/$(shell uname -r)/build
    all: ; make -C $(KDIR) M=$(PWD) modules
    clean: ; make -C $(KDIR) M=$(PWD) clean
    
  • Character device skeleton: register a cdev, define file_operations (open, release, read, write, unlocked_ioctl), allocate a dev_t via alloc_chrdev_region, create a class and device so udev creates /dev/<name>.
  • Locking: spin_lock (interrupt context), mutex_lock (sleepable), rcu_read_lock (read-mostly). Choosing wrong is a deadlock or a soft-lockup.
  • Memory: kmalloc (small, contiguous), vmalloc (large, possibly non-contiguous), kmem_cache_* (slab). Account in /proc/slabinfo.
  • Signing & secure boot: production hosts with secure boot will reject unsigned modules. Sign with scripts/sign-file against a MOK (Machine Owner Key).

21.3 Lab-"A Character Device LKM"

Write pkv, a simple in-kernel key/value character device: - /dev/pkv accepts writes of the form key=value\n and reads return the value for the last-written key. - 100 KV slots, in-kernel hash table. - Concurrency-correct under multiple writers/readers (use a mutex; pursue an rwlock variant as a stretch). - ioctl operations for LIST and DELETE. - KUnit tests in tree. - Loads/unloads cleanly with no lockdep or KASAN warnings (turn both on in your test kernel).

21.4 Hardening Drill

  • Read CVE history for staging drivers; identify three classes of bugs that recur (UAF after kfree on error path, missing copy_from_user length check, integer overflow). Audit your pkv for each.

21.5 Performance Tuning Slice

  • Run bpftrace with kprobes on your module's functions; measure per-op latency. Compare against an equivalent userspace KV (e.g., a Unix-socket server).

Comments