DEV Community

Fauzan Febriansyah
Fauzan Febriansyah

Posted on

From npm install to insmod: My Journey into Linux Kernel Module

For a long time, I treated the OS as a black box. I knew how to write APIs in NestJS, but I had no idea how the server actually listened to a port. That changed when I joined the CusDeb Operating System Camp.

The goal was simple: stop relying on high-level abstractions and understand the machine. I wanted to move from just being a user of the OS to an engineer who could build inside it.

Here is what I learned when I finally broke the "Black Box" and accepted a challenge from an AI to build a self-destructing kernel module.

1. The Kernel is just an Express.js App

When I first looked at a Character Device Driver, I was overwhelmed by structs and pointers. But then I realized: The Kernel is just a Server.

Coming from web development, I mapped the concepts, and suddenly, the "magic" disappeared:

  • The Port (alloc_chrdev_region): You reserve a Major/Minor number. This is just like opening port 80. The Kernel needs to know where to route traffic.
  • The Server (cdev_init): This is effectively app.listen(). It tells the Kernel to start accepting traffic for your specific Device ID.
  • The Controller (file_operations): This is where your business logic lives. When a user runs cat /dev/mydevice, the Kernel routes it to your .read function.
  • The Response (copy_to_user): You can't just return json. You have to manually copy bytes across the boundary to the client.

Once I treated the Kernel as an API, I stopped fearing the C code.

2. The Challenger: Gemini 3.0

The CusDeb Camp gave me the foundation, how to build the kernel and run User-Mode Linux (UML). But I didn't want to just copy-paste a "Hello World."

I asked my AI thought partner, Gemini 3.0, for a "Boss Fight." I told it: "Don't give me code. Give me a problem."

It gave me The VoidBox.

The Spec:

  • Read-Once: A secure drop-box. Users write secrets in.
  • Incinerate: When read, the data is returned to User Space and immediately zeroed out in Kernel Memory.
  • Thread-Safe: Use mutex to prevent race conditions.

This wasn't a tutorial. This was a specification sheet.

3. The Holy Trinity of Kernel Hacking

Building the VoidBox forced me to confront three things I usually ignore in TypeScript.

The Boundary (User vs. Kernel)

In JS, variables are just variables. In Kernel space, you never trust a pointer from User Space.

You cannot access the user's buffer directly. You must use copy_from_user and copy_to_user. If you try to dereference a user pointer directly, you might crash the system.

Concurrency is Manual

In Node.js, we are spoiled by the single-threaded Event Loop. We rarely worry about two requests modifying a variable at the exact same nanosecond.

In the Kernel, that protection is gone. If two processes try to write to /dev/voidbox simultaneously, they will corrupt the memory.

I had to implement a mutex lock.

mutex_lock(&void_device.lock);
// ... Critical Section ...
// Copy data, update length
mutex_unlock(&void_device.lock);
Enter fullscreen mode Exit fullscreen mode

If I didn't lock it, the memory will be corrupted.

The "Filesystem" is a Lie

/dev/voidbox looks like a file. You can echo into it. You can cat it. But it's not a file. It's a stream.

I learned the hard way that if you don't manually update the cursor position (*ppos), the cat command will read forever, looping your data infinitely until you kill the process.

4. The Logic: Self-Destructing Memory

The logic I wrote was ruthless.

The Write: I checked if the box was full. If it was, I returned -EBUSY. I threw an I/O Error on purpose because this is a secure box. No overwriting allowed.

The Read: I first checked whether any data existed. If it did, I copied the data to user space, then immediately incinerated it void_device.data[0] = '\0'; and reset the stored length to 0, enforcing strict read-once semantics.

VoidBox Demo

The screenshot above shows the result. I wrote "NUS Msc..." into the void. I read it once. I tried to read it again, and it was gone. Total erasure.

Conclusion

I am still a "wannabe" Systems Engineer. My Makefile is messy, and the pointers still scare me.

But the "Black Box" is open. I know that insmod isn't magic, it's just loading a library. I know that cat isn't just reading a file, it's triggering a driver function.

If you are a web developer, stop fearing the low level. Spin up a User-Mode Linux instance and break things. It's the only way to see how the machine actually works.

If you want to check my messy code, here is the repo: github.com/fauzanfebrian/linux-kernel-hacking

Top comments (0)