Running Arch on the new Tornado instance (see this article) has been worth the journey so far. To get up and running quickly, I stuck to using Arch Linux as my server’s distribution; but I ran into some problems with getting the kernel to work with my firewall.
The problem boiled down to installing some missing modules to allow iptables to function correctly, but I figured this was a good time to get my hands dirty and figure out if there were a better, long-term solution.
The Arch distribution that is available with Tornado is a little out of date. This isn’t a massive problem because of Arch’s rolling release schedule (meaning that the distro will use a LiveCD or something simliar as a base and pull the latest packages from the internet to complete an initial install).
However, it appears that Tornado uses Xen for virtualization and might have been running a custom kernel to keep the boxes light on space and memory. When trying to run iptables for the first time, I got filter not available
(I’m paraphrasing, since the actual error is not in front of me now). My guess is that the Tornado Arch kernels didn’t include these modules.
Arch and pretty much every other popular distribution includes a number of packages to enable switching between different kernels. Arch, for example, has packages which will download and install a hardened patch (linux-hardened), longterm (linux-lts). Documentation for that process is readily available here for Arch and only a quick Google search away for other distributions. I won’t be redundant and cover those here.
Our second option is to build a kernel from source via kernel.org. The process isn’t much more complicated, it just uses slightly more space. Let’s start off by grabbing a fresh copy from the kernel.org website. This could take a while depending on your connection speed, so have some coffee (or whiskey) ready:
[you@terminal]$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.19.tar.xz
Once the download is finished we can unpack it, change to the new directory and begin configuring the kernel.
[you@terminal]$ tar xJf linux-5.19.tar.xz && cd linux-5.19/
Once in the kernel source directory, there are a multitude of options we can use to build a kernel from scratch. I’ll list them here, but will only cover the first two.
make config - A question and answer based prompt to build a kernel. make menuconfig - An ncurses based prompt with selectable options similar to a basic Linux distribution. make xconfig - A configuration window using XWindows and QT5 make gconfig - A configuration window using GNOME desktop
The most powerful option (and easiest on mental resources) is the make menuconfig
command. If you have done this once or twice and really need to go through every possible option, make config
might work out for you too.
Before we can move ahead, however, both the config
and menuconfig
recipes require a couple of older GNU tools to run correctly. Make sure at the very least that the bison
and flex
packages are installed on your system. And if you are not familiar with compiling software from scratch, you’ll probably also need make
and either gcc
or clang
. On Arch that process looks something like this:
[you@terminal]$ pacman -Syu flex bison make clang
With those dependencies satisifed, we can go about creating our first configuration:
[you@terminal]$ make menuconfig
Pressing enter, your terminal should dump out a couple of lines of text:
[you@terminal]$ make menuconfig HOSTCC scripts/basic/fixdep UPD scripts/kconfig/mconf-cfg HOSTCC scripts/kconfig/mconf.o HOSTCC scripts/kconfig/lxdialog/checklist.o HOSTCC scripts/kconfig/lxdialog/inputbox.o HOSTCC scripts/kconfig/lxdialog/menubox.o HOSTCC scripts/kconfig/lxdialog/textbox.o HOSTCC scripts/kconfig/lxdialog/util.o HOSTCC scripts/kconfig/lxdialog/yesno.o HOSTCC scripts/kconfig/confdata.o HOSTCC scripts/kconfig/expr.o LEX scripts/kconfig/lexer.lex.c YACC scripts/kconfig/parser.tab.[ch] (bla bla bla...)
and eventually open a screen like the following:
If you’ve been using Linux for a while or have installed something like FreeBSD, this menu will probably look familiar to you. You can move through and play with the options until you find a configuration that you are happy with.
Once this configuration is generated, you can proceed to actually build the kernel. Depending on your processor power, this will take a while. And even with a fast machine, building a kernel tends to be resource-intensive. So I would grab some more coffee (or whiskey) and pull up a 10 minute video on YouTube.
To build the kernel itself, we’ll just need to type make
in the kernel directory and wait.
[you@terminal]$ make ... WRAP arch/x86/include/generated/uapi/asm/socket.h WRAP arch/x86/include/generated/uapi/asm/sockios.h WRAP arch/x86/include/generated/uapi/asm/termbits.h WRAP arch/x86/include/generated/uapi/asm/termios.h WRAP arch/x86/include/generated/uapi/asm/types.h WRAP arch/x86/include/generated/asm/early_ioremap.h WRAP arch/x86/include/generated/asm/export.h WRAP arch/x86/include/generated/asm/mcs_spinlock.h WRAP arch/x86/include/generated/asm/irq_regs.h WRAP arch/x86/include/generated/asm/kmap_size.h WRAP arch/x86/include/generated/asm/local64.h WRAP arch/x86/include/generated/asm/mmiowb.h WRAP arch/x86/include/generated/asm/module.lds.h WRAP arch/x86/include/generated/asm/platform-feature.h WRAP arch/x86/include/generated/asm/rwonce.h WRAP arch/x86/include/generated/asm/unaligned.h UPD include/config/kernel.release UPD include/generated/uapi/linux/version.h UPD include/generated/utsrelease.h CC scripts/mod/empty.o HOSTCC scripts/mod/mk_elfconfig MKELF scripts/mod/elfconfig.h HOSTCC scripts/mod/modpost.o CC scripts/mod/devicetable-offsets.s UPD scripts/mod/devicetable-offsets. (output continued...)
If there are no issues (make
will usually stop with an error), and you don’t need any specific external modules, you can go ahead and continue to the next step.
For systems using Lilo, you can just run make install
and the new kernel will be appended to the bootloader options. For systems running Grub, it will be slightly more involved. I’ll break that down here in the next few paragraphs.
We’ll need to copy the image over to our boot directory.
[you@terminal]$ cp -v arch/x86/boot/bzImage /boot/vmlinuz-linux519-ramar-work
It will need an initramfs. This file is loaded into memory and used to instruct our CPU on how to boot into Linux.
The easiest way to generate a working version would be to make a copy of your system’s current preset file and simply rename it:
[you@terminal]$ cp /etc/mkinitcpio.d/linux.preset /etc/mkinitcpio.d/linux519ramar-work.preset
Once copied, we can instruct mkinitcpio to create an initial ramdisk using the new file as a preset:
[you@terminal]$ mkinitcpio -k linux519-ramar-work -g /boot/initramfs-linux519-ramar-work.img
Your terminal should spew a bunch of text similar to the following:
==> Building image from preset: /etc/mkinitcpio.d/linux519.preset: 'default' -> -k /boot/vmlinuz-5.19.0ramar-work \ -c /etc/mkinitcpio.conf \ -g /boot/initramfs-5.19.0ramar-work.img ==> Starting build: 5.19.0ramar-work -> Running build hook: [base] -> Running build hook: [udev] -> Running build hook: [autodetect] -> Running build hook: [modconf] -> Running build hook: [block] -> Running build hook: [filesystems] -> Running build hook: [keyboard] -> Running build hook: [fsck] ==> Creating zstd-compressed initcpio image: /boot/initramfs-5.19.0ramar-work.img ==> Image generation successful ==> Building image from preset: /etc/mkinitcpio.d/linux519.preset: 'fallback' -> -k /boot/vmlinuz-5.19.0ramar-work \ -c /etc/mkinitcpio.conf \ -g /boot/initramfs-5.19.0ramar-work-fallback.img \ -S autodetect ==> Starting build: 5.19.0ramar-work -> Running build hook: [base] -> Running build hook: [udev] -> Running build hook: [modconf] -> Running build hook: [block] -> Running build hook: [filesystems] -> Running build hook: [keyboard] -> Running build hook: [fsck] ==> Generating module dependencies ==> Creating zstd-compressed initcpio image: \ /boot/initramfs-5.19.0ramar-work-fallback.img ==> Image generation successful
When building a kernel, we’ll also have a file called System.map which lays out the addresses of syscalls in this version of Linux. This is not needed to boot.
[you@terminal]$ cp System.map /boot/System.map-linux519-ramar-work
Now we can go ahead and install our modules via make modules_install
…
[you@terminal]$ make modules_install
in which a successful run should look something like this:
INSTALL /lib/modules/5.19.0ramar-work/kernel/drivers/thermal/intel/x86_pkg_temp_thermal.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/fs/efivarfs/efivarfs.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/ipv4/netfilter/iptable_nat.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/nf_log_syslog.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/xt_LOG.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/xt_MASQUERADE.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/xt_addrtype.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/xt_mark.ko INSTALL /lib/modules/5.19.0ramar-work/kernel/net/netfilter/xt_nat.ko DEPMOD /lib/modules/5.19.0ramar-work
Our final step to installation, is notifying our bootloader that another kernel is available for use. Provided you are already using Linux and your system is already using Grub, there is no reason to reinstall the bootloader. You will, however, need a new configuration–since there are no facilities for Grub to detect new images at runtime.
[you@terminal]$ sudo grub-mkconfig -o /boot/grub/grub.cfg
Now we will need to reboot the system and test the new kernel. But wait, what if we should run into an issue?
In the future, I’ll be covering how to get fancy with your system’s boot process and debug issues with a kernel build.