This exercise instructs you how to build a Linux kernel and run it in a QEMU environment.
Assume you already have a Ubuntu 24.04 server running either in a VirtualBox or a native machine.
First, let's install a few pre-requisite Debian packages that will allow us to compile the Linux kernel.
sudo apt update
sudo apt install -y build-essential git libssl-dev flex bison wget pkg-config libelf-dev
sudo apt install -y qemu-system-x86 debootstrap
sudo apt install -y cloud-utils genisoimageWe will compile a minimal version of the Linux kernel that can run in a QEMU virtual machine. To get started, navigate to the Linux source code directory (assuming the Git repository is located in your home directory) and switch to the v6.8 branch:
cd ~/linux
git checkout v6.8Next, we'll use the default configuration for a basic x86-64 machine. That configuration can be generated as follows:
make defconfigThe make defconfig will use x86_64_defconfig on an x86_64 machine. Once done launch the compilation of the kernel with the following command:
make -j4This will take a while (10~30 minutes, depending on your machine settings). Once finished, the compiled kernel's binary is arch/x86/boot/bzImage.
T1: 4 points for building the kernel. You can take a screenshot and attach it to the assignment report.
Try to boot the kernel we just built with QEMU as follows:
qemu-system-x86_64 -m 1G -kernel arch/x86_64/boot/bzImage -nographic -append "console=ttyS0"Here we tell QEMU to create a machine with 1G of RAM and to use the kernel we compiled. The option -append indicates that the option "console=ttyS0" should be passed to the kernel, telling it to output its boot log on the VM's serial console.
You will see Linux starting to boot, but the boot process ends with the following error:
... ...
/dev/root: Can't open blockdev
VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
... ...
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)Don't panic! This is because the kernel we built cannot find a root filesystem. The root filesystem contains all user-space utilities, such as shell.
To exit QEMU, press Ctrl+a followed by x.
T2: 2 points for seeing this kernel panic and exit QEMU. You can take a screenshot and attach it to the assignment report.
We will use the Ubuntu 24.04 LTS (Noble Numbat) cloud image for this assignment.
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.imgSave the following config into a file named user-data. Make sure to replace <your-ssh-public-key> with your SSH public key.
#cloud-config
users:
- name: ubuntu
ssh-authorized-keys:
- <your-ssh-public-key>
sudo: ALL=(ALL) NOPASSWD:ALL
groups: sudo
shell: /bin/bash
chpasswd:
list: |
ubuntu:ubuntu
expire: FalseAnd save the following into meta-data:
local-hostname: ubuntu-lkpGenerate the cloud-init.iso
genisoimage -output cloud-init.iso -volid cidata -joliet -rock user-data meta-dataResize the virtual machine disk image:
qemu-img resize noble-server-cloudimg-amd64.img +4GYou can check the VM image using qemu-img info noble-server-cloudimg-amd64.img.
The Ubuntu cloud image contains a Linux kernel. We can first boot it up and let cloud-init to finish the configuration. Copy, paste and execute the following command in the shell:
qemu-system-x86_64 \
-smp 2 -m 2G -nographic \
-hda ./noble-server-cloudimg-amd64.img \
-device e1000,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2200-:22 \
-cdrom ./cloud-init.iso-hda ./noble-server-cloudimg-amd64.img specifies the virtual hard disk file to use as the main disk for the VM.-device e1000,netdev=net0 adds a virtual network device (e1000) connected to the virtual network defined by -netdev.-netdev user,id=net0,hostfwd=tcp::2200-:22 configures user-mode networking for the VM (net0) and sets up port forwarding from the host’s port 2200 to the guest’s SSH port (22).-cdrom ./cloud-init.iso attaches the cloud-init.iso file as a virtual CD-ROM for initial configuration (e.g., set up hostname, SSH key, etc.).It will take about 1 minute to see the virtual machine booted. When the login prompt appears:
... ...
[ 109.098393] cloud-init[852]: Cloud-init v. 24.3.1-0ubuntu0~24.04.2 running 'modules:c.
[ 116.319845] cloud-init[862]: Cloud-init v. 24.3.1-0ubuntu0~24.04.2 running 'modules:final' at Tue, 31 D.
[ 116.710797] cloud-init[862]: Cloud-init v. 24.3.1-0ubuntu0~24.04.2 finished at Tue, 31 Dec 2024 23:43:0s
Ubuntu 24.04.1 LTS ubuntu-lkp ttyS0
ubuntu-lkp login:Login as ubuntu, and use ubuntu as the password.
You can check the kernel version using uname -a, and shut down the VM:
sudo poweroffYou only need to use the cloud-init.iso the first time you boot the VM to configure the initial settings (e.g., creating users, setting up SSH keys, hostname, etc.). Once the VM is booted and configured, the configuration is saved to the VM’s filesystem, and cloud-init will not require the ISO for subsequent boots.
Save the following script as a file named run-ubuntu.sh:
#!/bin/bash
QEMU_BIN=qemu-system-x86_64
NCPU=2
MEMSIZE=2G
KNL_SRC=./linux # TODO: Change with your kernel base location
BZIMAGE=${KNL_SRC}/arch/x86/boot/bzImage
CMDLINE="nokaslr console=ttyS0 root=/dev/sda1 rw debug"
UBUNTU_IMG=noble-server-cloudimg-amd64.img
sudo ${QEMU_BIN} \
-s \
-nographic \
-smp ${NCPU} -m ${MEMSIZE} \
-nic user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:2200-:22 \
-net nic,model=e1000 \
-drive file=${UBUNTU_IMG},format=qcow2 \
-kernel ${BZIMAGE} \
-append "${CMDLINE}"Note: If you are not running QEMU within a VirtualBox VM or other virtualized environment, you can add -enable-kvm to accelerate the VM execution.
chmod +x run-ubuntu.sh
./run-ubuntu.shOnce the VM is booted with your compiled kernel, you should be able to ssh into this VM from another terminal using:
ssh ubuntu@localhost -p 2200Check the Linux kernel version:
ubuntu@ubuntu-lkp:~$ uname -a
Linux ubuntu-lkp 6.8.0 #3 SMP PREEMPT_DYNAMIC Tue Dec 31 05:15:29 UTC 2024 x86_64 x86_64 x86_64 GNU/LinuxT3: 4 points for seeing the new kernel version. You can take a screenshot and attach it to the assignment report.