Chapter 3. GNU/Linux kernel hacking: making entries in the /proc virtual file system

Table of Contents

The monolithic kernel of Linux
Linux kernel compiling
Kernel modules
Making entries in the /proc virtual file system
Creating the module in VirtualBox.

Abstract

In this chapter we have made a lifelong friend with a beautifully sophisticated monolithic kernel called Linux.

  • First, we are going to configure and compile a custom Linux kernel.

  • Then, we will write a kernel module that will create and maintain a simple „debugging file” under /proc virtual file system.

„LINUX is obsolete”

—Andy Tanenbaum (ast) Linus-Tanenbaum vita

The monolithic kernel of Linux

 

„<odd>.x.x: Linus went crazy, broke absolutely _everything_, and rewrote the kernel to be a microkernel using a special message-passing version of Visual Basic.”

 
 --Linus Torvalds RFD: Kernel release numbering (Linux Kernel Mailing List)

In the previous case study, we had some experience with the operation of the microkernel, where architectural components are organized in different hierarchical levels. This section drives us towards the other end of the spectrum, to the world of monolithic kernels. What do monolithic and micro kernels mean in practice? Think about the previous MINIX case study, where the data structures of the lower levels of the kernel could not be accessed from the higher levels. For example, from the Minix Information Server, we could not access the vector added to PCB, we needed to copy it up to the server level. In a monolithic kernel, the data structures and functions of the kernel can be accessed from anywhere in the kernel code.

In the known history of mankind, there have been several examples where huge masses of people were cooperating to achieve some mutual goals or were involved in achieving some goals. Some examples may be the building of the pyramids, the religious communities and the large mass armies of the 19th century.

If we investigate only pure intellectual purposes, we will find that we are not an embarrassment of riches. A present day example may be the building of the LHC (Large Hadron Collider), that was built by 10.000 technicians, engineers and scientist from all over the world. This may be comparable to writing the Linux kernel that is being maintained by more than 8000 developers [KERNELDEV]. And if we focus not only on the kernel itself but the whole GNU/Linux system (including editors, browsers, games, etc.), then we will get a much greater number than 10000 volunteers.

Linux kernel compiling

We believe that compiling the kernel should be a fundamental experience for all programming students. If the reader has never done it, we will do it now, in this section.

Compiling the kernel is a relatively safe activity, but it is better to do it in a virtualized Linux system. So if the reader has never done it before, we will compile it now, using the virtualized image Batfai_Prog1.ova.

The Linux kernel is a large C program, in order to compile it we need to download its source. The actual kernel sources can be downloaded from kernel.org. Here, at the time of writing, the 3.5 is the actual version. In the beginning, a simple version numbering scheme was used: the unstable versions were numbered by odd numbers and the stable ones by even numbers. But it was too „mathematical”, now a more sophisticated model was used.

Kernel version numbering

But joking apart, the rethinking of the numbering concept was suggested by Linus Torvalds in his email subjected „RFD: Kernel release numbering”.

The 2.6 kernels had already been numbered by the next schema. A stable major.minor.revision is followed by a sequence of major.minor.revision.patchlevel stable versions that contain bugfixes and security fixes. In parallel with these versions, the major.minor.revision+1"-rc-patchlevel" is the development (unstable) version, where new things are introduced. The next stable version major.minor.revision+1 will be evolved from the development versions.

On the Linux's 20th birthday, the version numbering was bumped from 2.6 to 3.0. Now, the revision shows the fixes, the development versions have the rc prefix.

We have chosen the current version, that is 3.5. The whole source tree is roughly 70-80 MB (it is not sufficient to download the patch that is only some kilobytes of large.) The unpacked size will be roughly a half gigabyte, but it should be noted that the size of the compiled kernel tree may be larger than 5 GB.

Using the command wget http://www.kernel.org/pub/linux/kernel/v3.0/linux-3.5.tar.bz2, here we are downloading the kernel sources.

Figure 3.1. Downloading the kernel sources.

Downloading the kernel sources.

The root of the unpacked kernel tree contains a README file, we follow the procedure descripted in this. First, unpack the sources with command tar xvjf linux-3.5.tar.bz2 or cited from the README, with the bzip2 -dc linux-3.5.tar.bz2 | tar xvf - command.

The compiling is controlled by the .config file of the kernel tree that file also can be found in the running system's /boot folder. We will use the command make menuconfig in order to customize the kernel. The make menuconfig works in the terminal screen and its output is the file .config. If you have already compiled the kernel, use the command make mrproper. This program will clean up the config and the object files from the source tree. As a best practice, the reader can copy the existing file from the /boot directory into the root of the source tree, then uses the command make oldconfig, because in this case it is enough to make decisions about the new features only.

Figure 3.2. Making the .config with command make menuconfig.

Making the .config with command make menuconfig.

Reading all kernel options in make menuconfig is a whole day's work, here we can see only one: under the General setup menu, we are going to set the Kernel .config support option that will save the .config file into the running kernel itself.

Figure 3.3. Setting the option Kernel .config support.

Setting the option Kernel .config support.

Linux kernel compiling may be coming now. Use the make command to compile the sources (here we do not follow the README, the argument O=output/dir is simply omitted, because we do not want to use a separate build directory).

Figure 3.4. Starting the compiling.

Starting the compiling.

The compilation has already finished, now we sudo into root and give the command make modeules_install install. With this command, we install the modules and the kernel.

Figure 3.5. Starting the installation.

Starting the installation.

By using the command uname -a, print the version of the running kernel.

Figure 3.6. The version of the running kernel.

The version of the running kernel.

We should now reboot the computer. After this, it can be seen that the grub menu has also been updated properly.

Figure 3.7. The updated GRUB menu.

The updated GRUB menu.

Now, the compiled custom kernel controls our computer.

Figure 3.8. The new kernel.

The new kernel.

Kernel modules

In the previous section, you can see that options marked by a star (*) will be compiled into the kernel. If we mark an option with M, it will be compiled into the kernel as a module.

At creating the configuration, we also have opportunity to compile a pure monolithic kernel without module support.

Figure 3.9. Switching off the option Enable loadable module support.

Switching off the option Enable loadable module support.


Without module support, the size of the kernel image is much larger than the original one. Let's also see it after creating and booting a new pure monolithic kernel:

 [norbert@BatfaiProg1 ~]$ ls -l /boot/vmlinuz-`uname
          -r` -rw-r--r--. 1 root root 25532624 Jul 31 15:50
          /boot/vmlinuz-3.5.0 

Figure 3.10. The size of the kernel image.

The size of the kernel image.