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.readfunction. -
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
mutexto 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);
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.
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)