Recompiling the Linux Kernel

Topic Progress:

9.2. Recompiling the Linux Kernel

The kernels provided by Kali include the largest possible number of features, as well as the maximum number of drivers, in order to cover the broadest spectrum of existing hardware configurations. This is why some users prefer to recompile the kernel in order to include only what they specifically need. There are two reasons for this choice. First, it is a way to optimize memory consumption since all kernel code, even if it is never used, occupies physical memory. Because the statically compiled portions of the kernel are never moved to swap space, an overall decrease in system performance will result from having drivers and features built in that are never used. Second, reducing the number of drivers and kernel features reduces the risk of security problems since only a fraction of the available kernel code is being run.


If you choose to compile your own kernel, you must accept the consequences: Kali cannot ensure security updates for your custom kernel. By keeping the kernel provided by Kali, you benefit from updates prepared by the Debian Project.

Recompilation of the kernel is also necessary if you want to use certain features that are only available as patches (and not included in the standard kernel version).

The Debian Kernel Handbook

The Debian kernel team maintains the Debian Kernel Handbook (also available in the debian-kernel-handbook package) with comprehensive documentation about most kernel-related tasks and about how official Debian kernel packages are handled. This is the first place you should look into if you need more information than what is provided in this section.

9.2.1. Introduction and Prerequisites

Unsurprisingly, Debian and Kali manage the kernel in the form of a package, which is not how kernels have traditionally been compiled and installed. Since the kernel remains under the control of the packaging system, it can then be removed cleanly, or deployed on several machines. Furthermore, the scripts associated with these packages automate the interaction with the bootloader and the initrd generator.

The upstream Linux sources contain everything needed to build a Debian package of the kernel but you still need to install the build-essential package to ensure that you have the tools required to build a Debian package. Furthermore, the configuration step for the kernel requires the libncurses5-dev package. Finally, the fakeroot package will enable creation of the Debian package without needing administrative privileges.

apt install build-essential libncurses5-dev fakeroot

9.2.2. Getting the Sources

Since the Linux kernel sources are available as a package, you can retrieve them by installing the linux-source-version package. The apt-cache search ^linux-source command should list the latest kernel version packaged by Kali. Note that the source code contained in these packages does not correspond precisely with that published by Linus Torvalds and the kernel developers; like all distributions, Debian and Kali apply a number of patches, which might (or might not) find their way into the upstream version of Linux. These modifications include backports of fixes/features/drivers from newer kernel versions, new features not yet (entirely) merged in the upstream Linux tree, and sometimes even Debian or Kali-specific changes.

The remainder of this section focuses on the 4.9 version of the Linux kernel, but the examples can, of course, be adapted to the particular version of the kernel that you want.

In this example, we assume that the linux-source-4.9 binary package has been installed. Note that we install a binary package containing the upstream sources but do not retrieve the Kali source package named linux.

# apt install linux-source-4.9
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  bc libreadline7
Suggested packages:
  libncurses-dev | ncurses-dev libqt4-dev
The following NEW packages will be installed:
  bc libreadline7 linux-source-4.9
0 upgraded, 3 newly installed, 0 to remove and 0 not upgraded.
Need to get 95.4 MB of archives.
After this operation, 95.8 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
# ls /usr/src
linux-config-4.9  linux-patch-4.9-rt.patch.xz  linux-source-4.9.tar.xz

Notice that the package contains /usr/src/linux-source-4.9.tar.xz, a compressed archive of the kernel sources. You must extract these files in a new directory (not directly under /usr/src/, since there is no need for special permissions to compile a Linux kernel). Instead, ~/kernel/ is more appropriate.

$ mkdir ~/kernel; cd ~/kernel
$ tar -xaf /usr/src/linux-source-4.9.tar.xz

9.2.3. Configuring the Kernel

The next step consists of configuring the kernel according to your needs. The exact procedure depends on the goals.

The kernel build depends on a kernel configuration file. In most cases, you will most likely keep as close as possible to that proposed by Kali, which, like all Linux distributions, is installed in the /boot directory. In this case, rather than reconfiguring everything from scratch, it is sufficient to make a copy of the /boot/config-version file. The version should be the same as that version of the kernel currently used, which can be found with the uname -r command. Place the copy into a .config file in the directory containing the kernel sources.

$ cp /boot/config-4.9.0-kali1-amd64 ~/kernel/linux-source-4.9/.config

Alternatively, since the kernel provides default configurations in arch/arch/configs/*_defconfig, you can put your selected configuration in place with a command like make x86_64_defconfig (in the case of a 64-bit PC) or make i386_defconfig (in the case of a 32-bit PC).

Unless you need to change the configuration, you can stop here and skip to Section 9.2.4, "Compiling and Building the Package". If you need to make changes or if you decide to reconfigure everything from scratch, you must take the time to configure your kernel. There are various dedicated interfaces in the kernel source directory that can be used by calling the make target command, where target is one of the values described below.

make menuconfig compiles and launches a text-mode kernel configuration interface (this is where the libncurses5-dev package is required), which allows navigating the many available kernel options in a hierarchical structure. Pressing the Space key changes the value of the selected option, and Enter validates the button selected at the bottom of the screen; Select returns to the selected sub-menu; Exit closes the current screen and moves back up in the hierarchy; Help will display more detailed information on the role of the selected option. The arrow keys allow moving within the list of options and buttons. To exit the configuration program, choose Exit from the main menu. The program then offers to save the changes that you have made; accept if you are satisfied with your choices.

Other interfaces have similar features but they work within more modern graphical interfaces, such as make xconfig, which uses a Qt graphical interface, and make gconfig, which uses GTK+. The former requires libqt4-dev, while the latter depends on libglade2-dev and libgtk2.0-dev.

Dealing with Outdated .config Files

When you provide a .config file that has been generated with another (usually older) kernel version, you will have to update it. You can do so with make oldconfig, which will interactively ask you the questions corresponding to the new configuration options. If you want to use the default answer to all those questions, you can use make olddefconfig. With make oldnoconfig, it will assume a negative answer to all questions.

9.2.4. Compiling and Building the Package

Clean Up Before Rebuilding

If you have already compiled a kernel in the directory and wish to rebuild everything from scratch (for example because you substantially changed the kernel configuration), you will have to run make clean to remove the compiled files. make distclean removes even more generated files, including your .config file, so make sure to back it up first.

Once the kernel configuration is ready, a simple make deb-pkg will generate up to five Debian packages in standard .deb format: linux-image-version, which contains the kernel image and the associated modules; linux-headers-version, which contains the header files required to build external modules; linux-firmware-image-version, which contains the firmware files needed by some drivers (this package might be missing when you build from the kernel sources provided by Debian or Kali); linux-image-version-dbg, which contains the debugging symbols for the kernel image and its modules; and linux-libc-dev, which contains headers relevant to some user-space libraries like GNU's C library (glibc).

The version is defined by the concatenation of the upstream version (as defined by the variables VERSION, PATCHLEVEL, SUBLEVEL, and EXTRAVERSION in the Makefile), of the LOCALVERSION configuration parameter, and of the LOCALVERSION environment variable. The package version reuses the same version string with an appended revision that is regularly incremented (and stored in .version), except if you override it with the KDEB_PKGVERSION environment variable.

$ make deb-pkg LOCALVERSION=-custom KDEB_PKGVERSION=$(make kernelversion)-1
$ ls ../*.deb

To actually use the built kernel, the only step left is to install the required packages with dpkg -i file.deb. The “linux-image” package is required; you only have to install the “linux-headers” package if you have some external kernel modules to build, which is the case if you have some “*-dkms” packages installed (check with dpkg -l "*-dkms" | grep ^ii). The other packages are generally not needed (unless you know why you need them)!