# Linux Kernel Debug Enviroment with buildroot 任意のバージョンのLinux KernelをQemu上で動かしてkgdbでデバッグするまでのメモ ## ビルド環境 buildrootのバージョンごとに扱えるgccのバージョンの範囲が限られている しかし経験上、**Linux Kernelは特定の範囲のバージョンのgccを使用しないとビルドに成功しない**事が多い 参考: https://qiita.com/masami256/items/a97917761d6df137f817 そのため、カーネルのリリース日とguessを元に適したバージョンのbuildrootを持ってくる なお今回は**Linux Kernel 3.13.5**をビルドする事を前提とする (このメモはCVE-2014-3153の解析環境の構築が最終目標なので) 対応しているbuildrootは**buildroot-2014.08**だった https://buildroot.org/downloads/buildroot-2014.08.tar.gz また、念の為Dockerを使用してビルドするホスト環境も調整してみた 使用したのは`Ubuntu 16.04`のコンテナ `$ docker run -it ubuntu:16.04` でコンテナを動かしたらホスト側の環境を整備する ``` # apt update # apt install wget build-essential bc libncurses5-dev rsync cpio unzip python vim ``` また、このバージョンのbuildrootの場合、pkgconfのリンクが切れているようなので修正する ```diff package/pkgconf/pkgconf.mk 8c8 < PKGCONF_SITE = http://distfiles.ariadne.space/pkgconf --- > PKGCONF_SITE = http://rabbit.dereferenced.org/~nenolod/distfiles ``` ## buildroot buildrootを展開し、中に入ってQemu用のconfigを持ってくる ``` # wget https://buildroot.org/downloads/buildroot-2014.08.tar.gz # tar xvf ./buildroot-2014.08.tar.gz # cd buildroot-2014.08 # make qemu_x86_64_defconfig ``` menuconfigを使用して追加で設定していく 以降、buildrootのバージョンの違いによって設定名や設定までのパスが異なるかもしれないので注意 ``` # make menuconfig ``` ビルドしたいLinux Kernelのバージョンを指定し、それに適したリソースを持ってくるようにする ``` Toolchain -> Custom kernel headers series -> 3.13.x Kernel -> Kernel version -> 3.13.5 ``` 今回作成する環境に適する形式でかカーネルを出力する (要 出典 / 検証) ``` Kernel -> Install kernel image to /boot in target ``` rootユーザーのパスワードを設定する ``` System Configuration -> Root password ``` rootfsの設定を行う ``` Filesystem images -> cpio the root filesystem ext2/3/4 filesystem -> ext2/3/4 variant -> ext4 ``` ## busybox 今回は権限昇格の脆弱性を検証する予定であるため、ユーザー権限でシェルを動かすためのアプレットを追加する ``` # make busybox-menuconfig ``` ``` Shells -> cttyhack Runit Utilities -> setuidgid ``` ## Linux Kernel そのままでも動くが、デバッグしやすいようにkgdbや各シンボルの保持を設定する ``` # make linux-menuconfig ``` ``` Kernel hacking -> Kernel debugging Kernel hacking -> Compile-time checks and compiler options -> Enable unused/obsolete exported symbols Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with debug info Kernel hacking -> Compile-time checks and compiler options -> Compile the kernel with frame pointers Kernel hacking -> Compile-time checks and compiler options -> Generate readable assembler code Kernel hacking -> KGDB: kernel debugger -> KGDB: use kgdb over the serial console Kernel hacking -> KGDB: kernel debugger -> KGDB: internal test suite Kernel hacking -> KGDB: kernel debugger -> KGDB: Allow debugging with traps in notifiers Kernel hacking -> KGDB: kernel debugger -> KGDB_KDB: include kdb frontend for kgdb ``` デバッグに便利なgdb向けスクリプトを作ってくれる`Provide GDB scripts for kernel debugging`なるオプションがあるらしいが、このメモで使用しているカーネルはかなり古く実装されていないようなので今回は使用しない 参考: https://troushoo.blog.fc2.com/blog-entry-499.html ## Build やや強めに祈ると失敗しないが、強すぎると変なところでコケる 職人の祈祷力が試される ``` # make BR2_JLEVEL=4 ``` 祈りが届いたら熱いうちに以下を持ってくる ``` # Kernel output/build/linux-X.X.X/vmlinux # Kernel (Compressed) output/images/bzImage # rootfs output/images/rootfs.cpio ``` ソースコードを見ながらデバッグしたい場合は ``` # cd output/build/linux-X.X.X # make clean ``` の後に ``` output/build/linux-X.X.X ``` をデバッグ環境の手元(後でgdbを走らせる)に置いておく kernel.orgから直接持ってきてもいいかもしれない 参考: https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.13.5.tar.xz ## rootfs rootfsを展開して変更を加える 適当に展開用のディレクトリを作り、中で展開 ``` $ mkdir rootfs && cd rootfs $ sudo cpio -idv < ../rootfs.cpio ``` initd.dにスクリプトを記述してユーザー権限でのシェルを動かすようにする ``` $ sudo vim ./etc/init.d/S99shell ``` ```shell! #!/bin/sh mdev -s mount -t proc none /proc mkdir -p /dev/pts mount -vt devpts -o gid=4,mode=620 none /dev/pts chmod 666 /dev/ptmx stty -opost uname -a setsid cttyhack setuidgid 1000 sh umount /proc poweroff -d 0 -f ``` 書き込んだら権限を調整してcpioに戻す ``` $ sudo chmod 775 ./etc/init.d/S99shell $ sudo find . -print0 | sudo cpio -o --format=newc --null > ../rootfs.cpio ``` ## Debug Qemuの起動スクリプトを書く ```shell! #!/bin/sh qemu-system-x86_64 \ -m 64M \ -nographic \ -kernel bzImage \ -append "console=ttyS0 loglevel=3 oops=panic panic=-1 pti=on nokaslr" \ -no-reboot \ -cpu qemu64,+smap,+smep \ -smp 1 \ -monitor /dev/null \ -initrd rootfs_debug.cpio \ -gdb tcp::1234 ``` KASLR(カーネル空間のランダマイズ機構)はオフにしないとkgdbを使用する際にdebugger側の想定しているアドレスとdebuggee側での実態のアドレスが異なり、エラーが発生するためデバッグの際は切っておく (`-append nokaslr`の記述) スクリプトを動かすとdebuggee側のQemuが動くため、それに接続するdebugger側も起動させる ``` $ gdb -q -ex 'target remote localhost:1234' ./vmlinux ``` あとは任意の関数にブレークポイントを設置するなりしてデバッグを楽しむ 余談だが、gdb extensionはLinux Kernel向けの機能が盛り込まれたbataさん作のgefのforkが個人的には一番のオススメ 参考: https://github.com/bata24/gef 
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up