OneShell

I fight for a brighter tomorrow

0%

Linux内核调试环境的搭建

编译系统内核

首先需要下载Linux的内核源码,几个常用的内核源码下载途径如下:

  1. GitHub - torvalds/linux: Linux kernel source tree:适合git commit找补丁和漏洞
  2. Index of /pub/linux/kernel/:下载源码的压缩包
  3. sudo apt-get source linux-image-$(uname -r):下载当前发行版的内核,但是版本往往不全
  4. Ubuntu KernelGitGuide:对于Ubuntu可以获取到发行版的源码,自行进行编译

此次就以编译Linux 5.15.1为例,首先下载并解压源码:

1
2
3
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.1.tar.gz
tar -xvf linux-5.15.1.tar.gz
cd linux-5.15.1/

然后是对内核的编译选项进行设置,常用的基本流程如下:

1
2
3
make **_deconfig
make munuconfig
make
  1. make **_deconfig
    **_deconfig是用来指定此次编译使用的默认配置文件,该配置文件会从指定的**_dedonfig文件中加载配置,并保存到源码目录的.config文件中。

在嵌入式领域,例如需要为ARM架构指定适配特定芯片的Linux内核,配置命令如下:

1
make ARCH=ARM imx_v6_v7_defconfig

在此处,我们的目的是需要编译一个x86_64架构的内核,因此执行命令如下:

1
make x86_64_defconfig
  1. make menuconfig
    undifined
    一般来说,调试内核需要关闭系统的地址随机化、开启调试信息等,除此之外,还需要根据调试的目的来选择需要编译的模块,例如在调试netfilter的时候,就需要开启一些NF_TABLES等相关的配置。
    如下是关闭地址随机化和开启调试信息的步骤:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Processor type and features  --->
    -*- Build a relocatable kernel
    [ ] Randomize the address of the kernel image (KASLR)

    Kernel hacking --->
    Compile-time checks and compiler options --->
    [*] Compile the kernel with debug info
    [*] Generate BTF typeinfo
    [*] Provide GDB scripts for kernel debugging

在menu界面,可以通过输入/来搜索需要开启的内核特性,这比一个个去手动找方便。
undifined

设置完毕后,可以主动保存或者退出提示保存

  1. make
    开始进行编译,可以根据CPU的核数开启多线程编译,提高速度,例如make -j8
    编译完成后,和调试相关的两个重要文件的路径和作用如下:
  • vmlinux:当前目录,原始的内核文件,未压缩,可以用于gdb调试时加载
  • bzImage:./arch/x86_64/boot/bzImage,压缩后的内核,真正运行的内核

制作文件系统

要启动一个能正常运行的Linux,除了内核之外,还需要一个根文件系统。文件系统的制作可以采用手动的方式,也可以采用自动化的脚本部署。

手动制作一个文件系统,基本的步骤就是:

  1. 下载某些发行版的基本根文件系统,例如Ubuntu的根文件系统
  2. 制作磁盘镜像,可以先使用dd创建一个磁盘镜像,然后使用mkfs来为磁盘镜像进行分区和格式化
  3. 挂载磁盘镜像,并将根文件系统装载到磁盘镜像中。
    手动创建根文件系统磁盘镜像就不再更多展开说,后续会单独出一篇文章来进行介绍。

自动化的脚本部署则是推荐一个内核模糊测试工具syzkaller中的脚本create-image.sh,其工作的基本原理是通过工具debootstrap根据参数创建一个Debian的根文件系统磁盘镜像,大概的工作流程如下:

  1. 设置参数,例如Debian的发行版本、系统架构、需要安装的组件
  2. 下载Debian的基本根文件系统,并使用qemu-user-static和chroot到根文件系统目录
  3. apt-get安装相关的组件,然后打包到磁盘镜像中
1
2
3
4
sudo apt-get install debootstrap
wget https://raw.githubusercontent.com/google/syzkaller/master/tools/create-image.sh -O create-image.sh
chmod +x create-image.sh
./create-image.sh

undifined

例如,./create-image.sh -d bullseye制作一个Debian的bullseye发行版根文件系统镜像。
undifined
undifined

qemu+gdb连调

运行所需要的内核和文件系统镜像都制作好了,基本如下:
undifined
就可以使用如下的QEMU命令来运行并调试内核:

1
2
3
4
5
6
7
8
9
sudo qemu-system-x86_64 \
-m 1G \
-kernel ./bzImage \
-append "console=ttyS0 root=/dev/sda earlyprintk=seria net.ifnames=0" \
-drive file=./bullseye.img,format=raw \
-nographic \
-net nic,model=e1000 \
-S \
-s
  • m:指定运行内存
  • kernel:指定内核
  • append:指定console口、磁盘、串口等
  • drive:磁盘
  • nographic:非图形界面,也就是命令行界面
  • net:e1000网卡
  • S:等待gdb的命令后再运行
  • s:开启本地调试端口1234

随后,使用gdb去连接和调试:

1
2
3
4
file ./vmlinux
target remote :1234
b start_kernel
c

可以看到,gdb成功断在了函数start_kernel
undifined

参考链接