Exercise: Linux Kernel Module Development
Difficulty - Advanced
Estimated Time - 10-12 hours
Learning Objectives
- Understand Linux kernel architecture and module system
- Write kernel modules that interact with hardware and drivers
- Implement character devices with file operations
- Master kernel-space programming and debugging techniques
- Build a custom system call or netfilter hook
- Use Go to interact with kernel modules via syscalls and ioctl
Problem Statement
Build a custom Linux kernel module that implements a character device driver, and create a Go userspace program that interacts with it. The kernel module will provide a virtual device that can be read from and written to, demonstrating kernel-space programming while using Go for the userspace interface.
Kernel module development is essential for device drivers, system extensions, security tools, and performance optimization. Understanding kernel programming helps you build low-level tools, debug system issues, and understand how operating systems work.
Real-World Scenario:
1// Go userspace program interacting with kernel module
2func main() {
3 // Open custom kernel device
4 dev, err := os.OpenFile("/dev/mydevice", os.O_RDWR, 0)
5 if err != nil {
6 log.Fatal(err)
7 }
8 defer dev.Close()
9
10 // Write to kernel device
11 message := "Hello from userspace!"
12 dev.Write([]byte(message))
13
14 // Read from kernel device
15 buffer := make([]byte, 256)
16 n, _ := dev.Read(buffer)
17 fmt.Printf("Kernel says: %s\n", buffer[:n])
18
19 // Use ioctl to control device
20 const IOCTL_GET_STATUS = 0x8001
21 status, _ := ioctl(dev.Fd(), IOCTL_GET_STATUS)
22 fmt.Printf("Device status: %d\n", status)
23}
24
25// Result: Direct communication with kernel!
Requirements
Functional Requirements
- Kernel Module: Loadable kernel module with init/exit functions
- Character Device: Implement char device with file operations
- Device Registration: Register device with major/minor numbers
- Proc Entry: Create /proc entry for status information
- Kernel Logging: Use printk for kernel log messages
- Go Userspace: Go program using syscalls to interact with module
- Ioctl Interface: Control device behavior via ioctl calls
- Interrupt Handling: Handle hardware interrupts
Non-Functional Requirements
- Module loads/unloads cleanly without system crashes
- Proper error handling in both kernel and userspace
- Thread-safe kernel code
- Memory safety
- Documentation for building and loading module
Background and Theory
Linux Kernel Modules
Kernel modules are pieces of code that can be loaded into the kernel dynamically without rebooting. They extend kernel functionality for:
- Device drivers
- Filesystems
- Security modules
- Network filters
Module Lifecycle:
Load: insmod/modprobe
↓
module_init() function runs
↓
Module active in kernel
↓
module_exit() function runs
↓
Unload: rmmod
Character Devices
Character devices are accessed sequentially as a stream of bytes. Examples: /dev/null, /dev/random, /dev/tty
File Operations Structure:
1struct file_operations {
2 struct module *owner;
3 loff_t;
4 ssize_t;
5 ssize_t;
6 long;
7 int;
8 int;
9};
Kernel Space vs User Space
User Space:
- Applications run here
- Limited privileges
- Can be preempted
- Uses virtual memory
System Call Interface
──────────────────────
Kernel Space:
- Kernel and drivers
- Full privileges
- Direct hardware access
- Non-preemptible critical sections
Kernel Debugging
printk: Kernel's printf equivalent
1printk(KERN_INFO "Hello from kernel\n");
Levels: KERN_EMERG, KERN_ALERT, KERN_CRIT, KERN_ERR, KERN_WARNING, KERN_NOTICE, KERN_INFO, KERN_DEBUG
dmesg: View kernel log
1dmesg | tail
GDB: Debug kernel with kgdb
ftrace: Trace kernel functions
SystemTap: Dynamic tracing
Use Cases
1. Device Drivers
- GPU drivers
- Network cards
- Storage controllers
2. Security Tools
- Rootkit detection
- System call monitoring
- Network packet inspection
3. Performance Tools
- eBPF programs
- Profiling tools
- Custom schedulers
4. System Extensions
- Custom filesystems
- Virtual devices
- Network protocols
Implementation Challenges
Challenge 1: Kernel API Changes
Issue: Kernel APIs change between versions.
Solution: Use compatibility checks:
1#include <linux/version.h>
2
3#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)
4 // New API
5#else
6 // Old API
7#endif
Challenge 2: Memory Management
Issue: Kernel has no malloc/free, different allocators.
Solution: Use kmalloc/kfree:
1void *ptr = kmalloc(size, GFP_KERNEL);
2if {
3 return -ENOMEM;
4}
5
6// Use ptr...
7
8kfree(ptr);
GFP Flags:
GFP_KERNEL: Normal allocation, may sleepGFP_ATOMIC: Cannot sleepGFP_DMA: For DMA-capable memory
Challenge 3: Synchronization
Issue: Kernel is preemptible, need proper locking.
Solution: Use mutexes or spinlocks:
1// Mutex
2DEFINE_MUTEX(my_mutex);
3mutex_lock(&my_mutex);
4// Critical section
5mutex_unlock(&my_mutex);
6
7// Spinlock
8spinlock_t my_lock;
9spin_lock_init(&my_lock);
10spin_lock(&my_lock);
11// Critical section
12spin_unlock(&my_lock);
Challenge 4: User/Kernel Data Transfer
Issue: Cannot directly access user-space pointers from kernel.
Solution: Use copy_to_user/copy_from_user:
1// Kernel to user
2if) {
3 return -EFAULT;
4}
5
6// User to kernel
7if) {
8 return -EFAULT;
9}
Hints
Hint 1: Start with Minimal Module
Create a simple "Hello World" kernel module:
1#include <linux/module.h>
2#include <linux/kernel.h>
3#include <linux/init.h>
4
5MODULE_LICENSE("GPL");
6MODULE_AUTHOR("Your Name");
7MODULE_DESCRIPTION("A simple Hello World module");
8
9static int __init hello_init(void) {
10 printk(KERN_INFO "Hello, Kernel!\n");
11 return 0;
12}
13
14static void __exit hello_exit(void) {
15 printk(KERN_INFO "Goodbye, Kernel!\n");
16}
17
18module_init(hello_init);
19module_exit(hello_exit);
Makefile:
1obj-m += hello.o
2
3all:
4 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
5
6clean:
7 make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Load: sudo insmod hello.ko
Unload: sudo rmmod hello
Hint 2: Register Character Device
Use misc device for easy registration:
1#include <linux/miscdevice.h>
2
3static struct file_operations fops = {
4 .owner = THIS_MODULE,
5 .read = device_read,
6 .write = device_write,
7 .open = device_open,
8 .release = device_release,
9};
10
11static struct miscdevice my_device = {
12 .minor = MISC_DYNAMIC_MINOR,
13 .name = "mydevice",
14 .fops = &fops,
15};
16
17static int __init my_init(void) {
18 return misc_register(&my_device);
19}
20
21static void __exit my_exit(void) {
22 misc_deregister(&my_device);
23}
Hint 3: Implement Read/Write
Handle read and write operations:
1static ssize_t device_read(struct file *file, char __user *buf,
2 size_t count, loff_t *offset) {
3 const char *message = "Hello from kernel";
4 size_t len = strlen(message);
5
6 if
7 return 0;
8
9 if
10 count = len - *offset;
11
12 if)
13 return -EFAULT;
14
15 *offset += count;
16 return count;
17}
18
19static ssize_t device_write(struct file *file, const char __user *buf,
20 size_t count, loff_t *offset) {
21 char kernel_buf[256];
22 size_t to_copy = min(count, sizeof(kernel_buf) - 1);
23
24 if)
25 return -EFAULT;
26
27 kernel_buf[to_copy] = '\0';
28 printk(KERN_INFO "Received from user: %s\n", kernel_buf);
29
30 return to_copy;
31}
Hint 4: Go Ioctl Interface
Call ioctl from Go:
1import (
2 "syscall"
3 "unsafe"
4)
5
6const (
7 IOCTL_GET_STATUS = 0x8001
8 IOCTL_SET_MODE = 0x8002
9)
10
11func ioctl(fd uintptr, request uint, arg uintptr) {
12 r, _, errno := syscall.Syscall(
13 syscall.SYS_IOCTL,
14 fd,
15 uintptr(request),
16 arg,
17 )
18 if errno != 0 {
19 return 0, errno
20 }
21 return r, nil
22}
23
24// Usage
25status, err := ioctl(dev.Fd(), IOCTL_GET_STATUS, 0)
Hint 5: Create Proc Entry
Add /proc entry for status:
1#include <linux/proc_fs.h>
2#include <linux/seq_file.h>
3
4static int my_proc_show(struct seq_file *m, void *v) {
5 seq_printf(m, "Device Status: Active\n");
6 seq_printf(m, "Buffer Size: %d\n", buffer_size);
7 return 0;
8}
9
10static int my_proc_open(struct inode *inode, struct file *file) {
11 return single_open(file, my_proc_show, NULL);
12}
13
14static const struct proc_ops my_proc_ops = {
15 .proc_open = my_proc_open,
16 .proc_read = seq_read,
17 .proc_lseek = seq_lseek,
18 .proc_release = single_release,
19};
20
21static int __init my_init(void) {
22 proc_create("mydevice", 0, NULL, &my_proc_ops);
23 // ...
24}
Solution
Show Complete Solution
Approach
We'll create:
- Kernel Module - Character device driver in C
- Go Userspace - Program to interact with the module
- Proc Interface - Status information in /proc
- Ioctl Commands - Control device behavior
Kernel Module Implementation
1// mydevice.c - Kernel module
2
3#include <linux/module.h>
4#include <linux/kernel.h>
5#include <linux/init.h>
6#include <linux/fs.h>
7#include <linux/uaccess.h>
8#include <linux/slab.h>
9#include <linux/mutex.h>
10#include <linux/miscdevice.h>
11#include <linux/proc_fs.h>
12#include <linux/seq_file.h>
13
14MODULE_LICENSE("GPL");
15MODULE_AUTHOR("Go Tutorial");
16MODULE_DESCRIPTION("Example character device driver");
17MODULE_VERSION("1.0");
18
19#define DEVICE_NAME "mydevice"
20#define BUFFER_SIZE 1024
21
22// IOCTL commands
23#define IOCTL_GET_STATUS _IOR('M', 1, int)
24#define IOCTL_SET_MODE _IOW('M', 2, int)
25#define IOCTL_RESET _IO('M', 3)
26
27// Device state
28static char *device_buffer;
29static size_t buffer_size = 0;
30static size_t read_offset = 0;
31static int device_mode = 0;
32static int open_count = 0;
33static DEFINE_MUTEX(device_mutex);
34
35// Statistics
36static unsigned long read_count = 0;
37static unsigned long write_count = 0;
38
39// Device open
40static int device_open(struct inode *inode, struct file *file) {
41 mutex_lock(&device_mutex);
42
43 if {
44 mutex_unlock(&device_mutex);
45 return -EBUSY; // Device busy
46 }
47
48 open_count++;
49 mutex_unlock(&device_mutex);
50
51 printk(KERN_INFO "mydevice: Device opened\n");
52 return 0;
53}
54
55// Device close
56static int device_release(struct inode *inode, struct file *file) {
57 mutex_lock(&device_mutex);
58 open_count--;
59 read_offset = 0;
60 mutex_unlock(&device_mutex);
61
62 printk(KERN_INFO "mydevice: Device closed\n");
63 return 0;
64}
65
66// Device read
67static ssize_t device_read(struct file *file, char __user *buf,
68 size_t count, loff_t *offset) {
69 size_t to_read;
70
71 mutex_lock(&device_mutex);
72
73 if {
74 mutex_unlock(&device_mutex);
75 return 0; // EOF
76 }
77
78 to_read = min(count, buffer_size -*offset);
79
80 if) {
81 mutex_unlock(&device_mutex);
82 return -EFAULT;
83 }
84
85 *offset += to_read;
86 read_count++;
87
88 mutex_unlock(&device_mutex);
89
90 printk(KERN_INFO "mydevice: Read %zu bytes\n", to_read);
91 return to_read;
92}
93
94// Device write
95static ssize_t device_write(struct file *file, const char __user *buf,
96 size_t count, loff_t *offset) {
97 char *new_buffer;
98
99 mutex_lock(&device_mutex);
100
101 // Allocate new buffer if needed
102 if {
103 count = BUFFER_SIZE;
104 }
105
106 new_buffer = kmalloc(count, GFP_KERNEL);
107 if {
108 mutex_unlock(&device_mutex);
109 return -ENOMEM;
110 }
111
112 if) {
113 kfree(new_buffer);
114 mutex_unlock(&device_mutex);
115 return -EFAULT;
116 }
117
118 // Replace old buffer
119 if {
120 kfree(device_buffer);
121 }
122 device_buffer = new_buffer;
123 buffer_size = count;
124 read_offset = 0;
125 write_count++;
126
127 mutex_unlock(&device_mutex);
128
129 printk(KERN_INFO "mydevice: Wrote %zu bytes\n", count);
130 return count;
131}
132
133// Device ioctl
134static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
135 int status;
136 int mode;
137
138 switch {
139 case IOCTL_GET_STATUS:
140 status = ? 1 : 0;
141 ifarg)) {
142 return -EFAULT;
143 }
144 printk(KERN_INFO "mydevice: IOCTL_GET_STATUS = %d\n", status);
145 return 0;
146
147 case IOCTL_SET_MODE:
148 ifarg)) {
149 return -EFAULT;
150 }
151 mutex_lock(&device_mutex);
152 device_mode = mode;
153 mutex_unlock(&device_mutex);
154 printk(KERN_INFO "mydevice: IOCTL_SET_MODE = %d\n", mode);
155 return 0;
156
157 case IOCTL_RESET:
158 mutex_lock(&device_mutex);
159 if {
160 kfree(device_buffer);
161 device_buffer = NULL;
162 }
163 buffer_size = 0;
164 read_offset = 0;
165 device_mode = 0;
166 mutex_unlock(&device_mutex);
167 printk(KERN_INFO "mydevice: IOCTL_RESET\n");
168 return 0;
169
170 default:
171 return -EINVAL;
172 }
173}
174
175// File operations
176static struct file_operations fops = {
177 .owner = THIS_MODULE,
178 .open = device_open,
179 .release = device_release,
180 .read = device_read,
181 .write = device_write,
182 .unlocked_ioctl = device_ioctl,
183};
184
185// Misc device
186static struct miscdevice my_device = {
187 .minor = MISC_DYNAMIC_MINOR,
188 .name = DEVICE_NAME,
189 .fops = &fops,
190 .mode = 0666, // rw-rw-rw-
191};
192
193// Proc file operations
194static int proc_show(struct seq_file *m, void *v) {
195 seq_printf(m, "Device Status:\n");
196 seq_printf(m, " Buffer Size: %zu bytes\n", buffer_size);
197 seq_printf(m, " Mode: %d\n", device_mode);
198 seq_printf(m, " Open Count: %d\n", open_count);
199 seq_printf(m, " Read Count: %lu\n", read_count);
200 seq_printf(m, " Write Count: %lu\n", write_count);
201
202 if {
203 seq_printf(m, " Buffer Content: ");
204 seq_write(m, device_buffer, min((size_t)64, buffer_size));
205 seq_printf(m, "\n");
206 }
207
208 return 0;
209}
210
211static int proc_open(struct inode *inode, struct file *file) {
212 return single_open(file, proc_show, NULL);
213}
214
215#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0)
216static const struct proc_ops proc_fops = {
217 .proc_open = proc_open,
218 .proc_read = seq_read,
219 .proc_lseek = seq_lseek,
220 .proc_release = single_release,
221};
222#else
223static const struct file_operations proc_fops = {
224 .owner = THIS_MODULE,
225 .open = proc_open,
226 .read = seq_read,
227 .llseek = seq_lseek,
228 .release = single_release,
229};
230#endif
231
232static struct proc_dir_entry *proc_entry;
233
234// Module initialization
235static int __init mydevice_init(void) {
236 int ret;
237
238 printk(KERN_INFO "mydevice: Initializing module\n");
239
240 // Register misc device
241 ret = misc_register(&my_device);
242 if {
243 printk(KERN_ERR "mydevice: Failed to register device\n");
244 return ret;
245 }
246
247 // Create proc entry
248 proc_entry = proc_create("mydevice", 0444, NULL, &proc_fops);
249 if {
250 printk(KERN_ERR "mydevice: Failed to create proc entry\n");
251 misc_deregister(&my_device);
252 return -ENOMEM;
253 }
254
255 printk(KERN_INFO "mydevice: Device registered at /dev/%s\n", DEVICE_NAME);
256 printk(KERN_INFO "mydevice: Proc entry at /proc/mydevice\n");
257
258 return 0;
259}
260
261// Module cleanup
262static void __exit mydevice_exit(void) {
263 printk(KERN_INFO "mydevice: Cleaning up module\n");
264
265 // Remove proc entry
266 if {
267 proc_remove(proc_entry);
268 }
269
270 // Free buffer
271 mutex_lock(&device_mutex);
272 if {
273 kfree(device_buffer);
274 device_buffer = NULL;
275 }
276 mutex_unlock(&device_mutex);
277
278 // Unregister device
279 misc_deregister(&my_device);
280
281 printk(KERN_INFO "mydevice: Module removed\n");
282}
283
284module_init(mydevice_init);
285module_exit(mydevice_exit);
Makefile:
1obj-m += mydevice.o
2
3KDIR := /lib/modules/$(shell uname -r)/build
4PWD := $(shell pwd)
5
6all:
7 make -C $(KDIR) M=$(PWD) modules
8
9clean:
10 make -C $(KDIR) M=$(PWD) clean
11
12install:
13 sudo insmod mydevice.ko
14
15uninstall:
16 sudo rmmod mydevice
17
18reload: uninstall install
19
20test:
21 @echo "Loading module..."
22 @sudo insmod mydevice.ko
23 @echo "Module loaded. Check dmesg for messages."
24 @dmesg | tail -5
Go Userspace Implementation
1// main.go - Userspace program
2
3package main
4
5import (
6 "fmt"
7 "io/ioutil"
8 "log"
9 "os"
10 "syscall"
11 "unsafe"
12)
13
14const (
15 DEVICE_PATH = "/dev/mydevice"
16 PROC_PATH = "/proc/mydevice"
17)
18
19// IOCTL commands
20const (
21 IOCTL_GET_STATUS = 0x80044D01 // _IOR('M', 1, int)
22 IOCTL_SET_MODE = 0x40044D02 // _IOW('M', 2, int)
23 IOCTL_RESET = 0x00004D03 // _IO('M', 3)
24)
25
26// ioctl performs an ioctl system call
27func ioctl(fd uintptr, request uint, arg uintptr) {
28 r, _, errno := syscall.Syscall(
29 syscall.SYS_IOCTL,
30 fd,
31 uintptr(request),
32 arg,
33 )
34 if errno != 0 {
35 return 0, errno
36 }
37 return r, nil
38}
39
40func main() {
41 fmt.Println("=== Kernel Module Interaction Demo ===\n")
42
43 // Open device
44 dev, err := os.OpenFile(DEVICE_PATH, os.O_RDWR, 0)
45 if err != nil {
46 log.Fatalf("Failed to open device: %v\n", err)
47 }
48 defer dev.Close()
49
50 fmt.Println("1. Writing to device...")
51 message := "Hello from Go userspace!"
52 n, err := dev.Write([]byte(message))
53 if err != nil {
54 log.Fatalf("Write failed: %v\n", err)
55 }
56 fmt.Printf(" Wrote %d bytes\n", n)
57
58 // Seek to beginning
59 dev.Seek(0, 0)
60
61 fmt.Println("\n2. Reading from device...")
62 buffer := make([]byte, 256)
63 n, err = dev.Read(buffer)
64 if err != nil {
65 log.Fatalf("Read failed: %v\n", err)
66 }
67 fmt.Printf(" Read %d bytes: %s\n", n, buffer[:n])
68
69 fmt.Println("\n3. Using IOCTL commands...")
70
71 // Get status
72 var status int32
73 _, err = ioctl(dev.Fd(), IOCTL_GET_STATUS, uintptr(unsafe.Pointer(&status)))
74 if err != nil {
75 log.Printf("IOCTL_GET_STATUS failed: %v\n", err)
76 } else {
77 fmt.Printf(" Device status: %d\n", status)
78 }
79
80 // Set mode
81 mode := int32(42)
82 _, err = ioctl(dev.Fd(), IOCTL_SET_MODE, uintptr(unsafe.Pointer(&mode)))
83 if err != nil {
84 log.Printf("IOCTL_SET_MODE failed: %v\n", err)
85 } else {
86 fmt.Printf(" Set mode to: %d\n", mode)
87 }
88
89 fmt.Println("\n4. Reading proc entry...")
90 procData, err := ioutil.ReadFile(PROC_PATH)
91 if err != nil {
92 log.Printf("Failed to read proc: %v\n", err)
93 } else {
94 fmt.Printf("%s\n", procData)
95 }
96
97 fmt.Println("5. Resetting device...")
98 _, err = ioctl(dev.Fd(), IOCTL_RESET, 0)
99 if err != nil {
100 log.Printf("IOCTL_RESET failed: %v\n", err)
101 } else {
102 fmt.Println(" Device reset successfully")
103 }
104
105 fmt.Println("\n=== Demo Complete ===")
106 fmt.Println("\nCheck kernel log with: sudo dmesg | tail")
107}
Build and Run Instructions
Build kernel module:
1make
Load module:
1sudo insmod mydevice.ko
Check module loaded:
1lsmod | grep mydevice
Build Go program:
1go build -o client main.go
Run Go program:
1./client
Check kernel log:
1sudo dmesg | tail -20
Unload module:
1sudo rmmod mydevice
Expected Output
Go program output:
=== Kernel Module Interaction Demo ===
1. Writing to device...
Wrote 23 bytes
2. Reading from device...
Read 23 bytes: Hello from Go userspace!
3. Using IOCTL commands...
Device status: 1
Set mode to: 42
4. Reading proc entry...
Device Status:
Buffer Size: 23 bytes
Mode: 42
Open Count: 1
Read Count: 1
Write Count: 1
Buffer Content: Hello from Go userspace!
5. Resetting device...
Device reset successfully
=== Demo Complete ===
Kernel log:
[12345.678] mydevice: Initializing module
[12345.679] mydevice: Device registered at /dev/mydevice
[12345.679] mydevice: Proc entry at /proc/mydevice
[12346.123] mydevice: Device opened
[12346.124] mydevice: Wrote 23 bytes
[12346.125] mydevice: Read 23 bytes
[12346.126] mydevice: IOCTL_GET_STATUS = 1
[12346.127] mydevice: IOCTL_SET_MODE = 42
[12346.128] mydevice: IOCTL_RESET
[12346.129] mydevice: Device closed
Testing Your Solution
Test these scenarios:
- Module Loading: Load and unload module successfully
- Device Creation: /dev/mydevice appears and is accessible
- Read/Write: Basic file operations work correctly
- Ioctl Commands: Control device behavior
- Proc Entry: Status information is accurate
- Concurrent Access: Multiple processes accessing device
- Error Handling: Invalid operations return proper errors
- Memory Leaks: No kernel memory leaks after unload
Verification Checklist:
- Module loads without errors
- Device file created at /dev/mydevice
- Proc entry created at /proc/mydevice
- Write operation stores data correctly
- Read operation retrieves stored data
- Ioctl commands execute successfully
- Module unloads cleanly
- No memory leaks
Bonus Challenges
- Sysfs Interface: Add sysfs attributes for device configuration
- Interrupt Handling: Handle hardware interrupts
- DMA: Implement direct memory access for bulk transfers
- Netlink Socket: Create netlink interface for kernel-user communication
- Netfilter Hook: Intercept and modify network packets
- System Call: Add a new custom system call
- Kernel Thread: Create kernel thread for background work
- Workqueue: Use workqueues for deferred work
- Block Device: Implement a simple block device driver
- Virtual Filesystem: Create a simple in-memory filesystem
Key Takeaways
- Kernel modules extend kernel functionality without rebooting
- Character devices provide sequential byte stream access via standard file operations
- Kernel space has no safety net - bugs cause kernel panics
- Memory management is explicit - use kmalloc/kfree, never malloc
- Synchronization is critical - use mutexes and spinlocks appropriately
- User/kernel data transfer requires special functions - copy_to_user/copy_from_user
- Ioctl provides custom device control beyond read/write
- Go can interact with kernel modules using syscalls and ioctl
- Debugging is harder in kernel space - use printk and /proc for visibility
- Always test in a VM - kernel bugs can crash the system
Kernel module development is one of the most advanced topics in systems programming, requiring deep understanding of operating system internals, memory management, and hardware interfaces.