Writing a simple FreeBSD kernel module

Writing C can be just as glamorous as HTML and JS apparently are 💁🏻

I’ve been learning more about Operating Systems, specifically what’s going on behind the scenes. In parallel, I’ve been trying to learn some C.

Certainly I know more than most about Operating Systems already, though by most I mean among everyone in the world. That’s not a particularly high bar at all if you think about it for a second.

I’m comfortable writing scripts and small programs in Go and Python, but Operating Systems are build in ASM and C/C++ almost exclusively these days (shout-out to Redux though) and with most of the code examples in the more long-standing OS textbooks appearing in C, I have been pushed far enough to want to learn.

Writing a very basic kernel module seemed like low-hanging fruit, at least with FreeBSD in mind. So here’s how you can do it too.

Get FreeBSD

Head on over to freebsd.org and grab the OS in whichever format suits you. This article was written using 11.1-RELEASE. Personally I am running Veertu on macOS Sierra and it runs fine like that. It doesn’t need to be a particularly beefy VM (assuming you’re using a VM), so you can afford to be stingy.

Get the FreeBSD source

The source is packaged such that you’ll probably want to extract it at the root directory; it’ll all end up in /usr/src that way.

Grab it by running the commands below.

Write the module

Now for the fun bit. I’ll split this up so that I’m not just giving you code to copy paste.

First, include the necessary headers from the FreeBSD source. Of note here are the kernel.h and module.h includes, the latter of which you should read over to learn more about what’s going on in this article.

Watch out for the order of these includes

Now we want to define our event handler. This is a function with a specific prototype akin to all other modules.

The only parameter we care about is event_type, an enum defined in <sys/module.h> which tells us which event was triggered to call the function.

Nice and easy, no? If we’re loading, say so; if we’re unloading, say so; if we’re doing something but neither loading nor unloading, return a ‘not supported’ error.

Next, you want to create your moduledata_t struct.

This struct is used when the module is being declared to the kernel in the next section. It defines the name of the module, the function to be called to handle various module events (e.g. load, unload) and a void pointer which can contain extra information (haven’t learn exactly what yet!).

Finally, we want to use a special macro to register the module with the kernel; DECLARE_MODULE.

All in all, you should have something like this.

I just noticed ‘daying’. Sigh.

To make things easier, steal this Makefile.

Now make it, make load it and make unload it!

As you can see, the module does what we intended by the load and unload events, and you can check it’s status with kldstat

And there you have it!

Conclusion

As with most powerful systems software, FreeBSD kernel modules are written in C. Using the kernel source and a little know-how shared by FreeBSD hackers, it has been easy for me to get to grips with the very basics of writing a loadable kernel module.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.