setup ubuntu qemu guest with custom kernel and debug it with gdb

ubuntu host and guest, qemu vm, x86-64 kernel

Posted by jiayy on May 13, 2020

需要在多个linux内核版本上调试代码,因此需要快速搭建基于多种内核版本的调试环境

Kernel

用主线代码, git 下载

git clone https://github.com/torvalds/linux.git $KERNEL

用 ubuntu 维护的内核代码, 下载对应版本的源码包并解压, 比如 ubuntu20.04 对应的源码包为 linux-source-5.4.0 focal linux-source-5.4.0

如果是调试内核漏洞利用,则推荐使用主线的源码,因为对应用层依赖不多,如果是调试内核模块或者工具,则推荐使用ubuntu维护的源码包,因为很多依赖的库需要从ubuntu的源下载,内核跟ubuntu保持一致比较省事

编译时要保证 CONFIG_DEBUG_INFO 打开,最好是同时让 CONFIG_RANDOMIZE_BASE 关闭,这个选项会影响调试

cd $KERNEL
make mrproper
export CC=/your/gcc
make defconfig
make kvmconfig
# modify some config
# CONFIG_DEBUG_INFO=y
# CONFIG_RANDOMIZE_BASE=n
make olddefconfig
make

Image

使用 debootstrap 建立根系统镜像

sudo apt-get install debootstrap

拷贝下面的脚本到文件 create-image.sh, 然后运行,可以得到镜像文件 eoan.img (ubuntu19.10) 或者 focal.img (ubuntu20.04)


#!/bin/bash
# create-image.sh creates a minimal ubuntu image suitable for kernel debugging.
# Copyright 2020 [email protected]

set -eux

RELEASE=eoan  # ubuntu19.10
# RELEASE=focal # ubuntu20.04

DIR=chroot-$RELEASE
sudo rm -rf $DIR
sudo mkdir -p $DIR
sudo chmod 0755 $DIR

INSTALL_PKGS=openssh-server,curl,tar,gcc,libc6-dev,time,strace,sudo,less,psmisc,net-tools,build-essential,vim,git,make

sudo debootstrap --include=$INSTALL_PKGS --components=main,contrib,non-free $RELEASE $DIR

# Set some defaults and enable promtless ssh to the machine for root.
sudo sed -i '/^root/ { s/:x:/::/ }' $DIR/etc/passwd
echo 'T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100' | sudo tee -a $DIR/etc/inittab
# 必须关闭 kaslr 才可以正常调试内核
echo 'GRUB_CMDLINE_LINUX_DEFAULT="nokaslr"' | sudo tee -a $DIR/etc/default/grub
# /etc/network/interfaces 已经被 ubuntu 放弃,改为了 netplan 方式
printf 'network:\n    version: 2\n    renderer: networkd\n    ethernets:\n        enp0s3:\n            dhcp4: true\n' | sudo tee -a $DIR/etc/netplan/01-network-manager-all.yaml
echo '/dev/root / ext4 defaults 0 0' | sudo tee -a $DIR/etc/fstab
echo 'debugfs /sys/kernel/debug debugfs defaults 0 0' | sudo tee -a $DIR/etc/fstab
echo 'securityfs /sys/kernel/security securityfs defaults 0 0' | sudo tee -a $DIR/etc/fstab
echo 'configfs /sys/kernel/config/ configfs defaults 0 0' | sudo tee -a $DIR/etc/fstab
echo 'binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0' | sudo tee -a $DIR/etc/fstab
echo "kernel.printk = 7 4 1 3" | sudo tee -a $DIR/etc/sysctl.conf
echo 'debug.exception-trace = 0' | sudo tee -a $DIR/etc/sysctl.conf
echo "net.core.bpf_jit_enable = 1" | sudo tee -a $DIR/etc/sysctl.conf
echo "net.core.bpf_jit_kallsyms = 1" | sudo tee -a $DIR/etc/sysctl.conf
echo "net.core.bpf_jit_harden = 0" | sudo tee -a $DIR/etc/sysctl.conf
echo "kernel.softlockup_all_cpu_backtrace = 1" | sudo tee -a $DIR/etc/sysctl.conf
echo "kernel.kptr_restrict = 0" | sudo tee -a $DIR/etc/sysctl.conf
echo "kernel.watchdog_thresh = 60" | sudo tee -a $DIR/etc/sysctl.conf
echo "net.ipv4.ping_group_range = 0 65535" | sudo tee -a $DIR/etc/sysctl.conf
echo -en "127.0.0.1\tlocalhost\n" | sudo tee $DIR/etc/hosts
echo "nameserver 8.8.8.8" | sudo tee -a $DIR/etc/resolve.conf
echo "jiayy" | sudo tee $DIR/etc/hostname
ssh-keygen -f $RELEASE.id_rsa -t rsa -N ''
sudo mkdir -p $DIR/root/.ssh/
cat $RELEASE.id_rsa.pub | sudo tee $DIR/root/.ssh/authorized_keys

# Build a disk image
dd if=/dev/zero of=$RELEASE.img bs=1G seek=20 count=1
sudo mkfs.ext4 -F $RELEASE.img
sudo mkdir -p /mnt/$DIR
sudo mount -o loop $RELEASE.img /mnt/$DIR
sudo cp -a $DIR/. /mnt/$DIR/.
sudo umount /mnt/$DIR

Qemu

先安装 qemu

sudo apt-get install qemu-system-x86

使用下面的脚本启动虚拟机

qemu-system-x86_64   \
-smp 4 \
-enable-kvm -m 2G -nographic \
-kernel /path-to/linux/arch/x86/boot/bzImage  \
-append "console=ttyS0 root=/dev/sda earlyprintk=serial rw nokaslr"  \
-drive file=/path-to/focal.img,format=raw   \
-device e1000,netdev=t0  \
-pidfile vm.pid \
-netdev user,id=t0,hostfwd=tcp::10022-:22 -s -S  

注意内核启动选项必须增加 nokaslr 关闭地址随机化,否则就需要kernel编译时关闭 CONFIG_RANDOMIZE_BASE, kaslr 会导致断点出问题无法调试

如果需要杀死虚拟机,用下面的命令:

kill $(cat vm.pid)

Ssh

登录时用秘钥文件登录

ssh -i focal.id_rsa -p 10022 -o "StrictHostKeyChecking no" [email protected]
#ssh -i eoan.id_rsa -p 10022 -o "StrictHostKeyChecking no" [email protected]

登录guest后首先替换源 /etc/apt/source.list , 然后 apt update

如果需要在 guest 编译驱动或者内核源码,需要安装依赖

apt-get build-dep linux
apt-get install libncurses-dev flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf

Gdb

(gdb) target remote :1234
(gdb) b xxx_function
(gdb) c

Ref

setup_ubuntu-host_qemu-vm_x86-64-kernel.md booting-a-custom-linux-kernel-in-qemu-and-debugging-it-with-gdb