Part 1: Building a custom kernel in Arch Linux

Deliverable: shell script mmk that automates all the steps starting from make

Make sure the script will stop if any of the commands fail

It takes two arguments: the original kernel version and your UNI

Ex) ./mmk 4.4.50 jwl3

Place mmk script in the kernel source directory, linux-4.4.50.

Optional tasks (these are optional because this is an OS course, not a
shell scripting course, but seriously, any self-respecting hacker should
do them):

You are allowed to hard code virtualbox-guest-dkms version (like
“4.3.26”). Instead, try grabbing it from the pacman query.

Make the two command line arguments optional. You can figure out the
local version from the .config file and the original kernel version
from the Makefile.

You are allowed to hard-code N in “make -jN”, but again, you can
figure out the optimal value on the fly in your script.

Part 2: Reducing kernel build time

In this part, you will reduce your kernel build time drastically.

Go back to the part 1 instruction (and Arch KCT). Regenerate .config
so that it contains only those modules that you are currently using.
This will cut down the number of modules from something like 3000 to
under 100. Here is how.

First, backup your .config to something like .config.UNI-from-lts

Run make localmodconfig. This will take your current .config and
turn off all modules that you are not using. It will ask you a few
questions. You can hit ENTER to accept the defaults.

Now you have a much smaller .config. You can follow the rest of
the steps starting from make -jN. (You can run your mmk script
instead of following the steps manually, of course.)

When you are hacking the kernel code, a lot of times you make simple
changes to some .c files. If you didn’t touch any header file, the
modules will not be rebuilt when you run make, thus there is no reason
to reinstall all modules.

Make a stripped-down version of your mmk script called mko (for “make
kernel only”), which does only the following 3 things:

make -jN

copy the kernel (bzImage)

copy the System.map file

Place mko alongside mmk, in your linux-4.4.50 directory.

Now you have mmk to build the kernel, install modules, and rebuild
vboxguest, but much, much faster than before thanks to the smaller
.config. In addition, you have mko for quick build & reboot cycles
when you didn’t recompile any modules. You are ready to add some system
calls to your kernel.

Part 3: Making the Linux source tree a sparse git repo

You will make the linux-4.4.50 directory a git repo, but a sparse one.
What do I mean by that? You will leave most of the files in the directory
untracked. You will track only those files that you modify from the
original version.

Start by running git init in the linux-4.4.50 directory.
Everything you do in this assignment will be inside the directory. We
will call this directory the TOP.

Create your README.txt in the TOP. Note that there is Linux kernel
README in that directory. Do not touch that. Your homework readme is
README.txt. Track the README.txt in the git repo.

Don’t forget to track mmk and mko in the TOP from part 1 & 2.

You must create a 0-length file named .scmversion in the TOP by
typing touch .scmversion. This will prevent the Makefile in the TOP
to mess up your kernel version string by appending a git commit id or a
‘+’ character.

This way, the grader can git checkout 3c265 to revert your repo to
part2 state if necessary.

When you are ready to submit your work, you will go into the directory
one level above the linux-4.4.50, and clone the repo using the
following command:

git clone linux-4.4.50 hw4

Note that the hw4 directory will contain only a handful of files and
directories. You then make a tar ball for submission.

tar czvf UNI-hw4.tgz hw4

The tar file is supposed to be very small, probably under 100KB. If you
have a big file, you did something wrong.

If you are a git ninja and use branches, maybe to collaborate among the
team members, please make sure that the master branch has everything
that matters and is currently checked out when you tar.

If you have set up a shared directory between your VM and the host
machine, you can git-clone into your host directory to make a backup of
your code. It’s an incremental backup too–you go into the shared
directory from your VM and run git pull to bring it up to date.

The graders will copy your repo over the pristine linux–4.4.50
directory and build the kernel. They will also look at your git log and
the diffs (using git log -u). Please make your commit log meaningful.

Please make sure you understand the process. Ask in the mailing list if
you have any questions.

Part 4: The supermom() System Call

Implement supermom() system call that checks if the parent process of the
calling process has a superuser privilege.

You must read LKD chapter 5 in order to understand how adding a system call
works in general. Unfortunately, some of the steps described in the LKD
book have changed since the book was written.

At the time of this writing, Linux kernel has about 380 system calls. New
system calls are constantly being added to the Linux kernel. Let’s leave
some room and use 400 for our supermom() system call.

Please put your system call code in kernel/hw4.c. Create a test
directory and write a user level test program to call the supermom() system
call. Name your test driver hw4-test.c. After you’re done with this
part, git ls-files should look like this:

If the given pid is NOT the pid of the calling process’s parent
process, it will return –1 and set errno to EINVAL. In addition,
you may optionally print “Not Yo Mama” to kernel log.

See man syscalls for syscall return value convention.

If the given pid matches the pid of the calling process’s parent:

if uid is not NULL, the effective user ID of the calling process’s
parent process is written to *uid.

if the effective user of the parent is root, it returns 0

if the effective user of the parent is NOT root, it returns –1 and
sets errno to EACCES.

LKD chapter 5 tells you what you need to do to copy values between
kernel and user spaces.

A few things that you might find helpful:

Code for other system calls that do similar things. Check out
getppid() and geteuid(), for instance.

Kernel documentations in the Documentation subdirectory of the
kernel source. Check out credentials.txt, for example.

man 7 credentials

The purpose of this part is to learn how to add a system call, and get a
little bit of practice navigating through kernel code and documentation.
As such, we are going to ignore a big issue in correctly implementing a
system call – we are going to ignore race conditions. You don’t have
to worry about synchronization in implementing supermom().

Part 5: Moving a system call into a kernel module

By now, you must be tired of rebooting your VM every time you make a small
change in system call code. In this part, we will move the code for
supermom() into a dynamically loadable kernel module. Our goal is to be
able to make modifications to the system call code without having to reboot
the machine.

There are two ways to implement a system call using a module. You can
try to modify the system call table from the module initialization code.
Changes in recent kernels on the mechanics of setting up system calls
make this method more cumbersome than it used to be, so we are not going
to do this.

Another way is to leave the system call definition in the static kernel
code, but have it call another function defined in a module. This is
our approach.

Use the module skeleton code and Makefile from HW2. Make a module
directory inside the test directory and put Makefile and
supermom.c:

test/module/Makefile
test/module/supermom.c

The system call will be activated when you call sudo insmod
supermom.ko and it will be deactivated when you call sudo rmmod
supermom.ko. When the supermom() syscall is not activated, it will
return ENOSYS, indicating that the function is not implemented.