CSE 522S: Studio 5

Loadable Kernel Modules

There was a big book with plain red leather covers; its tall pages were now almost filled. At the beginning there were many leaves covered with Bilbo's thin wandering hand; but most of it was written in Frodo's firm flowing script. It was divided into chapters but Chapter 80 was unfinished, and after that were some blank leaves.

"Why, you have nearly finished it, Mr. Frodo!" Sam exclaimed. "Well, you have kept at it, I must say."

"I have quite finished, Sam," said Frodo. "The last pages are for you."

The Return of the King, Book VI, Chapter 9

Explanation of studio

In this studio, you will:

  1. Build and install a kernel module
  2. Write your own kernel module

Please complete the required exercises below, as well as any optional enrichment exercises that you wish to complete.

As you work through these exercises, please record your answers, and when finished email your results to dferry@email.wustl.edu with the phrase Loadable Kernel Modules in the subject line.

Make sure that the name of each person who worked on these exercises is listed in the first answer, and make sure you number each of your responses so it is easy to match your responses with each exercise.

Required Exercises

  1. As the answer to the first exercise, list the names of the people who worked together on this studio.

  2. Create a new directory (outside of the Linux source tree) to hold your kernel modules. Use pages 338 and 339 of Linux Kernel Development to write a simple "Hello, World!" module. Then create a Makefile that contains the line "obj-m := hello.o". Finally, build the module with the command "make -C /linux/source/directory/ SUBDIRS=$PWD modules", but replace the path with the root location of your Linux source tree.

    What do you expect to happen when you load the kernel module?

  3. Before loading your first module, you might want to clear the contents of the system log. The same command (dmesg) that allows you to view the system log also allows you to manipulate it. You can clear the log with the command "dmesg --clear".

    The basic utility for loading modules into the kernel is called insmod. The make process from before will have generated a .ko file, which is the loadable module. Load your module now with a command such as: "sudo insmod hello.ko"

    NOTE: The insmod utility has been superceeded by another program called modprobe, which in general should be used. modprobe is safer to use because it performs dependency resolution between modules. We use insmod and rmmod here simply to demonstrate the low-level tools that actually perform module loading and unloading.

  4. If you recieve no error messages, then your module has been successfully loaded. However, there are two ways to verify this. First, use the lsmod command to see a listing of all currently loaded kernel modules. Verify that your module appears in the list. Second, verify that the printk statement in your init function has shown up in the system log. For the answer to this exercise, copy the output of lsmod and the last few lines of the system log here.

  5. The basic utility for removing modules from the kernel is called rmmod. When using this tool you can specify the module name (as shown in lsmod) or you can specify a .ko file.

    Remove your module now, and verify its removal as before. As the answer to this exercise, copy the output of lsmod and the last few lines of the system log.

  6. The major reason for kernel modules (as opposed to running a userspace program with root permissions) is that module code has direct access to all of the kernel's resources. Userspace programs, in contrast, must use the OS'es interface (system calls) to access such resources, and even then, most of the kernel is opaque to user processes.

    One kernel variable we've talked about previous is the jiffies counter. Recall that this variable keeps track of how many timer interrupts have (theoretically) occured since system boot. Modify your kernel module to print the value of this variable, it's an unsigned long. This value is not directly accessible by userspace programs, but it is visible in kernelspace.

    Copy and paste a system log message that prints the jiffies variable.

  7. Module init and exit functions are supposed to use the "0/-E" return convention. This means that these functions should return a 0 on success, or in the event of a failure they return the negative value of one of the error codes found in /include/uapi/asm-gerneic/errno-base.h. Modify your init function to return positive and negative values, respectively. What happens when you load the module? Check the system logs, what do you find there?

    Things to turn in

    In addition to the answers above, please submit:

Optional Enrichment Exercises

  1. Kernel symbols that are available to be used in loadable modules are called exported symbols and are identified by the EXPORT_SYMBOL macro. You can see a list of all kernel symbols by looking at the file /proc/kallsyms, e.g. cat /proc/kallsyms. You might notice that this is very similar to the symbol table of a traditional application. (Which you can print with the program nm, if you've never done it before. Try it on any binary!) In fact, their syntax is identical, so you can use man nm to find some more information about how to decode the contents of /proc/kallsyms.

    Symbols that have been exported can be found in this list with the prefixes __kstrtab_, and __ksymtab_. These prefixes denote a special kernel symbol that stores the name of the exported symbol and a struct that stores information about the symbol, respectively. See the definition of EXPORT_SYMBOL to see how these are generated.