kernel 调试环境搭建

准备

查看内核版本

1
2
$ uname -a
Linux guo 4.15.0-22-generic #24-Ubuntu SMP Wed May 16 12:15:17 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

查看内核是否支持调试(在Ubuntu 16.04默认开启)

1
2
3
4
5
6
7
8
9
10
$ cat /boot/config-4.8.0-36-generic | grep GDB 
# CONFIG_CFG80211_INTERNAL_REGDB is not set
CONFIG_SERIAL_KGDB_NMI=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_TESTS is not set
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_KDB=y

如果不支持调试或者需要其他版本的内核

选择kernel版本

1
2
3
4
# 搜索含有dbgsym的内核版本
apt-cache search linux-image | grep dbgsym | grep 4.8
# 搜索特定source code的内核版本
apt-cache search linux-source

安装内核

1
2
3
4
5
6
# 搜索要下载的linux内核版本
apt-cache search linux-image | grep linux-image | grep generic
# 安装内核
sudo apt-get install linux-image-4.8.0-36-generic
# 查看安装的内核版本
sudo dpkg --list | grep linux-image

安装符号文件

1
2
3
4
5
6
7
codename=$(lsb_release -c | awk  '{print $2}')
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-proposed main restricted universe multiverse
EOF

http://ddebs.ubuntu.com 是 Ubuntu 的符号服务器。执行下面的命令添加密钥:

1
wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add -

执行sudo apt update更新
下载符号文件包:

1
sudo apt-get install linux-image-`uname -r`-dbgsym

完成后,符号文件将会放在下面的目录下:

1
/usr/lib/debug/boot/vmlinux-4.8.0-36-generic

安装kernel对应的源代码

打开/etc/apt/sources.list,启用deb-srcsudo apt update更新

1
2
3
4
5
6
vim /etc/apt/sources.list
# 去掉下面这句话的注释
deb-src http://us.archive.ubuntu.com/ubuntu/ xenial main restricted

...
sudo apt-get update

搜索所有版本的source code:apt-cache search linux-source
安装指定版本的source code:sudo apt-get install linux-source-4.8.0
下载好的源代码会放在/usr/src目录下
解压源代码sudo tar -xvf linux-source-4.8.0.tar.bz2

配置VMware

移除打印机,添加串口,保证串口名称相同。

  • 在target机上添加串口,确认该端为服务器端。
  • 在host机上添加串口,确定该端为客户机端。

配置target机的启动项

需要让target在开机时候进入kgdb的调试状态,首先需要修改grub文件,增加grub引导时候的菜单项。

1
sudo vim /etc/grub.d/40_custom

修改的内容从/boot/grub/grub.cfg里复制,复制一个菜单项(menuentry)过来,再把菜单名中增加调试信息,然后在内核命令行中增加KGDB选项,即下面这样:
新增部分:kgdbwait kgdb8250=io,03f8,ttyS0,115200,4 kgdboc=ttyS0,115200 kgdbcon nokaslr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/sh
exec tail -n +3 $0
# This file provides an easy way to add custom menu entries. Simply type the
# menu entries you want to add after this comment. Be careful not to change
# the 'exec tail' line above.
menuentry 'Ubuntu,KGDB with nokaslr' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-4.10.0-19-generic-advanced-32ee8e9c-31e6-494c-a9ea-1a416cbfeca7' {
recordfail
load_video
gfxmode $linux_gfx_mode
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1 32ee8e9c-31e6-494c-a9ea-1a416cbfeca7
else
search --no-floppy --fs-uuid --set=root 32ee8e9c-31e6-494c-a9ea-1a416cbfeca7
fi
echo 'Ubuntu,KGDB with nokaslr ...'
linux /boot/vmlinuz-4.10.0-19-generic root=UUID=32ee8e9c-31e6-494c-a9ea-1a416cbfeca7 ro find_preseed=/preseed.cfg auto noprompt priority=critical locale=en_US quiet kgdbwait kgdb8250=io,03f8,ttyS0,115200,4 kgdboc=ttyS0,115200 kgdbcon nokaslr
echo 'Loading initial ramdisk ...'
initrd /boot/initrd.img-4.10.0-19-generic
}

修改/etc/default/grub文件,使虚拟机开机是出现选择内核界面。

1
2
3
4
5
$ sudo vim /etc/default/grub
# 注释该这一行
GRUB_HIDDEN_TIMEOUT=0
# 开机选择界面等待时间 s
GRUB_TIMEOUT=10

配置host

设置串口通信的波特率

1
sudo stty -F /dev/ttyS0 115200

要查看是否设置成功

1
sudo stty -F /dev/ttyS0

每次host重启都需要重新设置。

调试

编写config,用source加载(直接在gdb里输入也可)

1
2
set architecture i386:x86-64:intel
target remote /dev/ttyS0

使用gdb来调试带符号的vmlinux (此处gdb需要sudo权限,切gdb插件pwndbg不能使用)

1
2
gdb -s /usr/lib/debug/boot/vmlinux-4.10.0-19-generic
gdb > source config

查看源码遇到的问题

1
in /build/linux-hwe-eyfT8D/linux-hwe-4.8.0/net/core/skbuff.c:758

list本来应该显示具体的源码,但是这里只是打印出了它所在的文件,这是因为在这个路径下没有源码。
所以说我们就建立这个路径,然后把源码放进去。
然后dir设置好目录

1
dir /build/linux-hwe-eyfT8D/linux-hwe-4.8.0

现在就可以查看源码了。

单步调试

当target端成功启动,并且host端成功挂载gdb时。如果我们需要调试exp程序,只需要在target端输入:

1
sudo su && echo g > "/proc/sysrq-trigger"

此时,target端处于假死状态,在host端可以使用gdb下断点调试内核。