Discovering Kernel Fuzzing
This year, during an industrial project that is part of my master’s program, I had the opportunity to make my first steps into the world of kernel fuzzing. This was a great learning experience, during which I had the opportunity to work with wonderful people. In this blog post, I will describe my journey into the world of kernel fuzzing.
I have to admit that I didn’t know anything about fuzzing when I was finishing my first semester of the Master of Software Engineering at Innopolis University. Before the end of the first semester, we have to choose an industrial project for the next semester. To do so, we attended multiple project presentation sessions with representatives of different companies. During the project presentations, we were presented with many interesting projects covering various areas of software engineering. One project from KasperskyLab was the most appealing to me; I don’t know exactly why, since I didn’t know anything about the project before the presentation. But I think it was because I wanted to learn something outside of my comfort zone. The project was presented by Anna Melekhova, a senior engineer at KasperskyLab. The project was about researching kernel fuzzing approaches and their implementation for Kaspersky OS, a new operating system in development at KasperskyLab. I chose this project and got it accepted along with four other classmates.
According to Wikipedia “fuzzing or fuzz testing is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a computer program.” So, the way I see it, fuzzing is like tricking a software system. You feed it lots of silly, crazy, and random things to see if it can handle them. The goal of this testing approach is to proactively reveal flaws in the software that might be difficult to find with traditional testing approaches.
The kernel, on the other hand, is the core component of a computer’s operating system. Depending on design choices and architecture, the kernel has more or less complete control over everything in the system.
The first week was dedicated to initial research in order to learn as much as possible about fuzzing in general. I went to many websites, read several articles about fuzzing, and finally, I found a good book on the topic, “Fuzzing for Software Security Testing and Quality Assurance, Second Edition” written by: Ari Takanen, Jared D. Demott, and Charles Miller. Although I didn’t read the book cover to cover, I got very good information from It and was confident enough to move on. I recommend reading this book if you want to learn about fuzzing.
After I got familiar with the topic of fuzz testing, I started learning about the target system, KasperskyOS. KasperskyOS is a microkernel operating system developed by the company KasperskyLab. KasperskyOS is designed with cyber immunity features in mind. While the source code of this operating system is proprietary and closed source, a publicly available version of our OS is freely available here. The community edition is the best way for developers to learn about the OS and develop applications for it.
At this point, we have to start researching fuzzing solutions for KasperskyOS. We performed our research by reading several research papers on the topic of kernel fuzzing. At the end of the research, the team agreed that we should work on extending a state-of-the-art kernel fuzzer called Syzkaller. Syzkaller is a popular kernel fuzzing tool developed and maintained by Google. Syzkaller is an unsupervised coverage-guided kernel fuzzer, meaning that it uses coverage data to guide a fully automated fuzzing process.
By following the documentation on the GitHub repository of syzkaller, I set up my local fuzzing environment to fuzz the Linux kernel to see how syzkaller works. Syzkaller has a modular design, its main component is called syz-manager and it is a program written in Golang and running on the host system. syz-manager spins off multiple virtual machines. The actual fuzzing happens inside each virtual machine. Inside a virtual machine is the target operating system, alongside other components such as syzkaller, syz-fuzzer , and syz-executor. syz-fuzzer guides the fuzzing process (input generation, mutation, minimization, etc.) and sends inputs that trigger new coverage back to the syz-manager process. The picture below, taken from syzkaller documentation gives a visual presentation of how the syzkaller fuzzing process works.
After our experimentations with syzkaller, we find out that, in order to be able to use syzkaller to fuzz KasperskyOS we have to develop a custom implementation of syz-executor and syz-fuzzer that will run in the user-space inside a virtual machine running KasperskyOS. Then, we faced one issue, syz-fuzzer is written in Golang, and the KasperskyOS platform is not supported by Golang. So we couldn’t compile syz-fuzzer for KasperskyOS. We looked at other operating systems to see if they were similar case and how this issue was addressed. It turned out that FuchsiaOS from Google has many things in common with KasperskyOS. The FuchsiaOS platform is also not supported by Golang, so Syzkaller has a mode called “host fuzzer” making it possible to run syz-fuzzer on the host system. So we tried to do something similar for KasperskyOS, to be stuck again by another limitation. This limitation was related to the fact that KasperskyOS didn’t have an ssh server at that time. The fuzzing process of Syzkaller involves establishing an ssh connection between syz-manager/syz-fuzzer and the target system in order to execute syz-executor remotely.
At this point, it became clear that there was nothing more we could do and that we couldn’t use SyzKaller to fuzz KasperskyOS until KasperskyLab added an SSH server to their OS. To go further in this learning journey, and after discussing with the representative of the company, we decided to fall back on FuchsiaOS to complete the course project. As stated above, FuchsiaOS is in many aspects similar to KasperskyOS, and Syzkaller support for FuchsiaOS was broken, and we wanted to try to fix it. Luckily enough, it wasn’t very hard, and I was able to fix this in a few days with the help of Syzkaller maintainer Dmitry Vyukov. Here is my pull request that fixed the support for FuchsiaOS.
Overall, this was a great experience for me personally to learn about kernel fuzzing with Syzkaller. I cannot conclude this post without saying thank you to everyone involved in the project. to Anna Melekhova for her time and valuable guidance during the project. to Dmitry Vyukov, for the time dedicated to reviewing my pull request and answering our questions. to all my team members and our mentor.