Purpose: hands-on experience with LSM
This homework consists of 3 parts, with 50%, 100%, and 150% points respectively. If you are not familiar with Linux kernel build system (Kbuild), make sure you start with the first part before jumping to 2nd part. Meanwhile, it is definitely doable to get the 2nd part working within two weeks (again, the deadline for this assignment). Once you feel confident about LSM hooks and Kbuild and you still have time, try to tackle the 3rd part, which is built upon the first two parts while asking for a little bit more kernel hacking. Have fun!
VM Environment: KVM/QEMU, VirtualBox, VMware Player (anything works for you)
OS Environment: Ubuntu 16.04 x86-64 Desktop with Linux kernel version 4.15.X
0. Follow the VM and OS environment to set up your own Linux kernel hacking environment. If you have a spare machine and would like to do bare-metal Linux, feel free.
1. (50%) Within the class, we have learned that LSM provides us a way to build a reference monitor within the Linux kernel. Rather than looking at all of those 300-ish hooks at the same time, let’s start with one hook, which is related to setting the time of the system. For example, we could use the “date” command to display or reset the current system time. As you have probably figured out, time is also a security-sensitive resource and resetting the system time might enable attacks such as firmware downgrading attacks (which relying on the system time to check against the version of the firmware). In this part, you need to find the LSM hook which is in charge of setting the system time and implement a global policy that no one can reset the time earlier than the current system – you can set the time in the future but not the past!
To get started, make sure you have followed [1] to get the Linux kernel source and build toolchain (GCC). Take a look at all different LSM modules under the security directory within the Linux kernel source tree. Ubuntu mainly uses AppArmor and Yama as its main LSM modules (Fedora/RH/CentOS are using SELinux+Yama). Instead of building a new LSM module from scratch, this part only requires you to find an existing LSM model, e.g., Yama, add the LSM system time setting hook there and implement the secure-system-time policy mentioned above. Once you update your kernel source file, compile the kernel, and finally install the new kernel.
Note: within your policy implementation, make sure you use “pr_info” to print out when the system time is successfully reset and when the request is rejected due to an attempt to set the time in the past.
Deliverable: Please provide a “diff” between the original Linux kernel source file and the file that you change. (HINT: you only need to change one source file.) Run “dmesg” command to collect the kernel logging when executing the “date” command to reset the system time both in the future and in the past.
2. (100%) In the first part, you add the system time resetting hook and implement the secure-system-time policy within some existing LSM module, e.g., Yama. It is good to see your policy working, isn’t it? However, to fully understand LSM modules, we need to implement our own. In this part, you need to play with Kbuild and Kconfig to add a new LSM module called “oss-lsm“, which contains the system time resetting hook and the secure-system-time policy implementation. For instance, you need to create a new directory named “oss-lsm” under the security directory. You need to change the config and the Makefile under the security directory to include your “oss-lsm” into the whole Kbuild system. You also need to implement your own Makefile within “oss-lsm” to get your “oss-lsm.c” compiled when you build the Linux kernel. You might also need to update the Linux kernel source configuration file (.config) to add and enable your new “oss-lsm” LSM module. When everything is done, recompile the Linux kernel and install the new kernel image.
Deliverable: Pretty much the same as Part 1, and you need to provide the whole “oss-lsm” directory with every file contained. (HINT: you need to add new files and one new directory and change a bunch of other files.)
3. (150%, BONUS) If you have made it so far, congrats! Now you have a new LSM module integrated within the Linux kernel and it is time to do something more fun! Recall that Linux has a syscall to change the affinity of CPU for a process. Why do we wanna change the affinity of CPU? You might ask. Well, from the performance perspective, we could bind one application to a certain core thus reducing the overhead of context switching among different cores. However, setting CPU affinity is also useful in security. For instance, in a multi-core system, we might wanna reserve the computation power of core 0 to make some important security decisions while allowing other cores to suffer from DoS. This scenario is also not uncommon for load balancing where you wanna make sure there is one core available to handle some urgency.
The good news is LSM provides a hook to intercept that CPU affinity setting syscall. As the first, figure out what the hook is. Then you need to add this new hook into your “oss-lsm” LSM module and implement the other global policy that no process can explicitly set its CPU affinity to core 0.
Soon you might find that while the hook is there, it does not give all the information you need to implement the cpu-affinity-no-core-0 policy. What are you gonna do? This is also related to the LSM design discussion we had in the class – how do we know that LSM is correct, complete, and sound? What if we realize that LSM is not generic enough and we need to change LSM hooks to implement certain policies? Yes, your guess is right. You probably need to change that CPU affinity hook itself to provide more information for you to implement the cpu-affinity-no-core-0 policy.
Deliverable: Pretty much the same as Part 2, and you need to write a user-space program to change the CPU affinity both to core 0 and core non-0.
References:
[1] https://davejingtian.org/2019/11/07/ubuntu-kernel-build-again/