Post

Linux Kernel with Qemu

Linux Kernel with Qemu

QEMU

QEMU is a generic and open source machine emulator and virtualizer. When used as a machine emulator, QEMU can run OSes and programs made for one machine (e.g. an ARM board) on a different machine (e.g. your own PC). By using dynamic translation, it achieves very good performance.
When used as a virtualizer, QEMU achieves near native performance by executing the guest code directly on the host CPU. QEMU supports virtualization when executing under the Xen hypervisor or using the KVM kernel module in Linux. When using KVM, QEMU can virtualize x86, server and embedded PowerPC, 64-bit POWER, S390, 32-bit and 64-bit ARM, and MIPS guests.

Install QEMU

1
2
sudo apt-get update
sudo apt-get install git fakeroot build-essential ncurses-dev xz-utils libssl-dev bc flex libelf-dev bison qemu-system-x86

Getting kernel source

The Linux kernel is a free and open-source Unix-like kernel that is used in many computer systems worldwide. The kernel was created by Linus Torvalds in 1991 and was soon adopted as the kernel for the GNU operating system which was created to be a free replacement for Unix.
1
2
3
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.54.tar.xz
tar xvf linux-5.10.54.tar.xz
cd linux-5.10.54

Building the kernel

To prepare the kernel for building, we need to set up the .config file.
1
2
3
4
# from inside Linux-5.10.54 folder
make defconfig # creates a .config file
make kvmconfig # modifies .config to set up everything necessary for it to run on QEMU
# or make kvm_guest.config in more recent kernels
Use KVM for debugging
1
2
3
4
5
CONFIG_KVM_GUEST=y
# CONFIG_KVM_DEBUG_FS is not set
CONFIG_HAVE_KVM=y
# CONFIG_KVM is not set
CONFIG_PTP_1588_CLOCK_KVM=y
Use KASAN
1
2
3
4
5
6
7
8
9
10
11
12
13
# Coverage collection.
CONFIG_KCOV=y

# Debug info for symbolization.
CONFIG_DEBUG_INFO=y

# Memory bug detector
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y

# Required for Debian Stretch
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y
Finally, run make olddefconfig to regenerate the configurations with the necessary modifications that the previous lines introduced.
1
make olddefconfig
Run "make -j `nproc`" to start building the linux kernel. It could take a few dozens of minutes, so be patient. In the end, a bzImage file should have been created:
1
ls arch/x86_64/boot/bzImage

Creating an image for the kernel

The kernel cannot boot without a filesystem. There are multiple ways to set up one, including initramfs and others, but I prefer to follow syzkaller guide again and use their script to set up a Debian-like environment which comes with a bunch of handy tools:
1
2
3
4
5
6
# from the source folder root
sudo apt-get install debootstrap
mkdir image && cd image
wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.sh
chmod +x create-image.sh
./create-image.sh
The result is a chroot folder is created, alongside an RSA key that will be used to ssh into QEMU when booted, and stretch.img, which is the actual file system.

Running the kernel

Finally, to run the kernel, I have a script run.sh that I like to use to make things easier:
1
2
3
4
5
6
7
8
9
10
11
12
qemu-system-x86_64 \
        -m 2G \
        -smp 2 \
        -kernel $1/arch/x86/boot/bzImage \
        -append "console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0 nokaslr" \
        -drive file=$2/bullseye.img,format=raw \
        -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 \
        -net nic,model=e1000 \
        -enable-kvm \
        -nographic \
        -pidfile vm.pid \
        2>&1 | tee vm.log
Put it in the linux-5.10.54 folder, and run it:
1
2
chmod +x run.sh
./run.sh . image/
You can login with username root without password
This post is licensed under CC BY 4.0 by the author.