CMSC 421: Principles of Operating Systems

Project 2: Scrubber Kernel Driver

This project is due on Monday, December 14, at 11:59:59 PM (Eastern standard time). You must use the submit to turn in your homework like so: submit cs421_jtang proj2 scrubber.c scrubber-test.c

Your driver code must be named scrubber.c. It will be compiled against a 4.1 Linux kernel source tree, via the Kbuild supplied below. It must not have any compilation warnings; warnings will result in grading penalties. This module code must be properly indented and have a file header comment, as described on the coding conventions page. Prior to submission, use the kernel's indentation script to reformat your code, like so:

    ~/linux/scripts/Lindent scrubber.c
  

In addition, you will write a unit test program, scrubber-test.c. This code must also have a file header comment and be properly indented. You will submit this test code along with your module code.

In this project, you will write a Linux driver that operates upon a virtual Internet filter. The user stores an arbitrary list of dirty words in your driver. Your driver then scans incoming network packets for those dirty words. For each found word, censor that word by overwriting it with asterisks.

Part 1: Preparing Your Kernel

All instructions hereforth assume you successfully completed the first homework. If you have not done so, go back and finish the homework before proceeding. You have been warned.

To begin, create a directory for your project and download the following files into that directory via wget:

http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/0001-x86-Update-kernel-defconfig-for-packet-mangling.patch
Updates the cs421_defconfig to build so-called packet mangler.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/Kbuild
Read by Linux kernel's build system, defines what is being built.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/Makefile
Builds the kernel module and unit test program, by simply running make. Also included is a clean target to remove all built objects.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/xt_filter.c
A Netfilter module that intercepts packets. You do not need to modify this file.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/scrubber.c
Skeleton code for your scrubber kernel driver.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/scrubber-test.c
Skeleton code for your unit test code.
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/proj2_start.sh
Shell script necessary to set up the virtual Internet filter. After downloading this file, mark the script executable (chmod u+x proj2_start.sh).
http://www.csee.umbc.edu/~jtang/cs421.f15/homework/proj2/proj2_stop.sh
Shell script to disable the virtual Internet filter. After downloading this file, mark the script executable (chmod u+x proj2_stop.sh).

After downloading all of these files, you need to then recompile your kernel:

  1. Change directory to your kernel source code.
  2. Use git am to apply the patch 0001-x86-Update-kernel-defconfig-for-packet-mangling.patch.
  3. Reconfigure and recompile your kernel:
    make cs421_defconfig
    make -j3
    sudo make modules_install install
  4. Reboot your VM, making sure you select the new kernel from the grub menu.
  5. As necessary, reinstall VirtualBox Guest Additions.

Now return to your proj2 directory. Run make to compile this project's files. Upon success, run proj2_start.sh (it may ask for your password, as that it runs some sudo commands). This will set up your VM for this project. Rerun this script if you ever need to reboot your VM.

Part 2: Writing to Device Node

In scrubber.c, you need a data structure to hold the list of dirty words. The kernel linked list is ideal for this. Declare a global variable to hold your list. Because this list will be accessed by many threads, also declare a global spinlock to guard the list.

Next, modify scubber_write() as per its comments. For each word within the user buffer, allocate a new list entry (via kmalloc()) and store the word. Add that entry to the dirty word list with the list_add_tail() macro. Protect all accesses to the list with your spinlock.

When scanning the user buffer for words, do not add empty words to the dirty word list. Assume that words consist of only alphabetic characters. The list may have duplicate words.

Ensure your scrubber_exit() frees all memory that have been allocated by the list.

Although not required, you may want to add a scrubber_read() that will return the list of dirty words. This will prove useful when debugging your driver.

Part 3: Integrate with Internet Filter

Next, you need to add interrupt handling. Read the code xt_filter.c. When this Internet filter is enabled, it will intercept all incoming network packets and raise an interrupt. It is your driver's responsibility to catch those interrupts and scrub the payloads.

In scrubber_init(), install a threaded interrupt handler for the interrupt number FILTER_IRQ. Remove that handler in scrubber_exit(). Implement your interrupt handler as follows:

/**
 * scrubber_check() - top-half of scrubber ISR
 * @irq: IRQ that was invoked
 * @cookie: Pointer to data that was passed into
 * register_threader_irq() (ignored)
 *
 * If @irq is FILTER_IRQ, then wake up the bottom-half. Otherwise,
 * return IRQ_NONE.
 */
static irqreturn_t scrubber_check(int irq, void *cookie);

/**
 * scrubber_handler() - bottom-half to scrubber ISR
 * @irq: IRQ that was invoked
 * @cookie: Pointer that was passed into register_threaded_irq()
 * (ignored)
 *
 * For each word in the dirty word list, scan the payload for that
 * word. For each instance found, case-sensitive matching, overwrite
 * that part of the payload with asterisks. Afterwords, resume the
 * Internet filter.
 *
 * HINT: use list_for_each_entry() to iterate over the dirty word list
 * HINT: strnstr()/memcmp() and memset() are useful here.
 *
 * WARNING: The payload is not null-terminated.
 *
 * Return: always IRQ_HANDLED
 */
static irqreturn_t scrubber_handler(int irq, void *cookie);

Once you are confident your ISR works, add filter_enable() to scrubber_init() (and likewise disable the filter in scrubber_exit()). Install your module, and check /proc/interrupts to ensure the ISR was registered.

Part 4: Example Run

As stated earlier, ensure you have run proj2_start.sh before proceeding.

In one terminal, run this command: nc -l 4210. In a second terminal, run this command: telnet localhost 4210. Use this second terminal to send strings to the first terminal. Open a third terminal; use this one to write entries to /dev/scrubber.

For example, suppose in the third terminal you ran this:

    $ echo "the" > /dev/scrubber
  
Then in the second terminal, send this input:
    To be, or not to be, that is the question.
  
Your first terminal should display this:
    To be, or not to be, that is *** question.
  
If in the third terminal, you then ran this:
    $ echo -e "in\ner" > /dev/scrubber
  
And you send this in the second terminal:
    Whether 'tis Nobler in the mind to suffer
  
You should get this in the first terminal:
    Whe***r 'tis Nobl** ** *** m**d to suff**
  
Note how for the input Whether, both the words the and er matched. In this case, the word first added to the dirty word list (the) has precedence.

You can close the telnet session by pressing control-] (right bracket) and then typing in close.

Part 5: Testing and Documentation

Now that you have (in theory) a working driver, you must then write your own unit tests. Read through the code given in scrubber-test.c. Modify the code as follow:

The unit tests must have comments that explain what things are being tested. You will be graded based upon the thoroughness of the tests.

Other Hints and Notes

Extra Credit

You may earn an additional 20% credit for this assignment by augmenting your scrubber driver. Have your driver create another character device, /dev/scrubber_del. For each word written to this device node (again, newline separated), scan scrubber's list of dirty words. If the string matches an entry (case-sensitive), remove that entry (without leaking any memory). If there are no matching entries for a word, then your driver should ignore that word.

Afterwards, update scrubber-test.c to test this new functionality.

If you choose to perform this extra credit, put a comment at the top of your file, alerting the grader.