Last Saturday I compiled my own Linux kernel for the first time.
This is one of those rites of passage that everyone in the community talks about, and almost nobody explains usefully. The man pages do not really explain it. The various HOWTO documents are either too brief to act on or too long to actually finish reading.
What I want to do here is describe what happened, in order, and what each step actually did.
Why bother
The stock Slackware kernel works. Compiling your own is not necessary for most people. There are two reasons to do it anyway.
The first is that the stock kernel includes drivers for hardware you do not have. Every one of those drivers is a few kilobytes of code that the kernel either contains or tries to load as a module on demand. None of it is needed if you do not own the hardware. A custom kernel is smaller and slightly faster.
The second is that you genuinely understand what is in your kernel only after you have chosen each option yourself. Before Saturday, my mental model of the kernel was a black box that did kernel things. After, the black box is at least partly transparent.
The procedure
I started with the source for 2.0.34, which is the most recent stable release at the time I am writing this. The source comes as a tarball. You unpack it into /usr/src/linux.
Then make config. This walks you through every configuration option in turn and asks you to say yes, no, or module. There are several hundred options. It takes about an hour to read carefully. The first time, you will say yes to things you do not need, and that is fine.
Then make dep. This works out which source files depend on which. It takes a couple of minutes.
Then make clean, which removes anything from a previous build, and make zImage, which actually compiles the kernel. On my box, with a Pentium 75, the latter took about forty minutes. I made a coffee and read.
Then make modules and make modules_install, which builds and installs the optional bits.
Then the bit nobody ever quite tells you. You have to copy the resulting zImage into /boot, edit /etc/lilo.conf to point to it, and run lilo so the bootloader actually finds it on the next boot. If you skip the lilo step the new kernel does not boot. I have made this mistake. Once you have made it, you do not make it again.
What I learned by doing this
I learned how the kernel relates to its modules — that the modules are loaded after boot, into the running kernel, and that the kernel itself only contains what was statically built in. This affects security: a stripped-down kernel cannot be persuaded to load a module that does not exist.
I learned that compiling out networking features I did not need — token ring, AppleTalk, the various radio link layer drivers — measurably reduced the kernel's memory footprint.
I learned that make config is not really a configuration tool, it is a teaching tool. Reading every option, deciding yes or no on every option, taught me the shape of the system more thoroughly than any book had.
The security angle, because there is one
A smaller kernel is a smaller attack surface. Every protocol the kernel speaks is a piece of code that could have a bug in it. Every filesystem the kernel can mount is the same. Every networking feature you switch off is one fewer place where something could go wrong.
More importantly, a kernel you have configured yourself is one you understand. When a vulnerability shows up on Bugtraq you can go to your .config and find out instantly whether the affected feature is in your kernel at all.
Verdict
Worth doing. Once. After that you can use a saved .config to do it again whenever a new kernel comes out. The hard work is the reading, not the compiling.