In this post, I will explain how to build and debug the Linux kernel.
How to Build the Linux Kernel with Buildroot
Install Buildroot.
Run the following commands to configure Buildroot:
Terminal window make list-defconfigs # List available configurationsmake qemu_x86_64_defconfig # Select default configurations for QEMU x86_64make menuconfig # Modify configurations if needed- Select
Filesystem images -> ext2/3/4 root file systemand selectext2/3/4 variant -> ext3.
If you want to change the kernel version, follow these steps:
- Select
Kernel -> Kernel version -> Custom Version. - Select
Kernel versionand set the version as you want. - Select
Toolchain -> Custom Kernel Header Seriesand choose the appropriate version.
- Select
Run
make linux-menuconfigand configure the kernel:- Select
Kernel hacking -> Kernel debugging. - Select
Compile-time checks and compiler options -> Debug information -> Rely on the toolchain's implicit default DWARF version. - Optionally, enable any other configurations you want.
- Select
Run
make busybox-menuconfigand configure BusyBox:- Select
Shells -> cttyhack. - Select
Runtime utilities -> setuidgid.
- Select
Run
make -j$(nproc)to build.
You can find bzImage and rootfs.ext3 in <PATH_TO_BUILDROOT>/output/images and vmlinux with debug symbols at <PATH_TO_BUILDROOT>/output/linux-<VERSION>/vmlinux.
How to Build the Linux Kernel without Buildroot
Download and extract the kernel source code (for example, from here).
- Run
make menuconfigand configure as you want. - Run
make build -j$(nproc)to build.
If you want to build the kernel with Clang/LLVM, follow the instructions here.
If you want to enable CONFIG_CFI_CLANG, you may need to compile Clang/LLVM with compiler-rt enabled. follow the instructions here.
- Run
Download and extract the Busybox source code(for example, from here).
- Run
make menuconfigand configure as you want. Make sure to selectSettings -> Build static binary file (no shared lib). - Run
make installto build. Make sure not to usesudo. You can find the compiled binaries in <PATH_TO_BUSYBOX>/_install.
- Run
Create the ext3 root file system image:
Terminal window dd if=/dev/zero of=rootfs.ext3 bs=1M count=16mkfs.ext3 -F rootfs.ext3mkdir -p mntsudo mount -o loop rootfs.ext3 ./mntsudo chown -R 1000:1000 ./mntcp -a <PATH_TO_BUSYBOX>/_install/* ./mntmkdir -p ./mnt/{dev,etc,proc,root,run,sys}
How to Run the Linux Kernel with QEMU
- Install QEMU.
- Run
mkdir -p mntandsudo mount -o loop <PATH_TO_ROOTFS> ./mnt. - Run
sudo chown -R 1000:1000 ./mnt. - Create
/init:#!/bin/shif (exec 0</dev/console) 2>/dev/null; thenexec 0</dev/consoleexec 1>/dev/consoleexec 2>/dev/consolefimkdir /homeecho 'root:x:0:0:root:/root:/bin/sh' > /etc/passwdecho 'root:x:0:' > /etc/groupchmod 644 /etc/passwdchmod 644 /etc/groupadduser ctf --disabled-password 2>/dev/nullchown -R root:root /chmod 700 -R /rootchown ctf:root /home/ctfchmod 777 /home/ctfchmod 755 /devchmod u+s /bin/sumount -t proc -o nodev,noexec,nosuid proc /procmount -t sysfs -o nodev,noexec,nosuid sysfs /sysmount -t tmpfs -o "noexec,nosuid,size=10%,mode=0755" tmpfs /runln -sf /proc/mounts /etc/mtabecho 1 > /proc/sys/kernel/kptr_restrictecho 1 > /proc/sys/kernel/dmesg_restrictecho 1 > /proc/sys/kernel/perf_event_paranoidsetsid cttyhack setuidgid 1000 sh - Create
run.sh:#!/bin/shqemu-system-x86_64 \-m 64M \-cpu qemu64 \-kernel bzImage \-drive file=rootfs.ext3,format=raw \-snapshot \-nographic \-monitor /dev/null \-no-reboot \-smp 1 \-append "root=/dev/sda rw init=/init console=ttyS0 nokaslr nopti loglevel=3 oops=panic panic=-1" - Run
sudo umount ./mnt. - Run
./run.sh.
How to Debug the Linux Kernel with QEMU and GDB
- Run QEMU with the
-gdb tcp::1234option. - Run GDB and execute
target remote localhost:1234.