x86-64 리눅스 커널을 디버깅 하는 방법입니다.
커널을 디버깅하기 위해 host-machine, target-machine이 필요한데 host-machine은 우분투 x86-64라고 가정하고 target-machine은 커널을 qemu에 올려서 vm으로 진행하겠습니다.
먼저 디버깅할 버전의 커널을 컴파일 해야합니다.
커널을 다운로드 받고 (http://kernel.org) 압축을 풀어서 커널 디렉토리로 이동한 후
make defconfig
make kvmconfig
make menuconfig
를 순서대로 실행해줍니다.
make menuconfig를 하면 옵션을 선택할 수 있는 창들이 뜰 텐데 여기서
Kernel Hacking
compile-time checks and compiler options
compile the kernel with debug info 체크
를 해준 후 exit하면 make를 하기 위한 설정이 다 되었습니다.
이제 make를 해서 빌드를 시작하고 기다리면 됩니다.
빌드가 다 되었다면 arch/x86/boot/bzImage에 커널 파일이 생기고 최상위 디렉토리에 vmlinux파일이 정상적으로 생겼을 것입니다. 이 파일을 vm을 구성할 디렉토리로 옮겨줍니다.
다음은 파일시스템을 구성해야합니다.
sudo apt-get install debootstrap를 해서 다운로드 해주고
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/bin/bash # Copyright 2016 syzkaller project authors. All rights reserved. # Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. # create-image.sh creates a minimal Debian-wheezy Linux image suitable for syzkaller. set -eux # Create a minimal Debian-wheezy distributive as a directory. RELEASE=wheezy DIR=wheezy sudo rm -rf $DIR mkdir -p $DIR sudo debootstrap --include=openssh-server,curl,tar,gcc,libc6-dev,time,strace,ltrace,sudo,less,psmisc,selinux-utils,policycoreutils,checkpolicy,selinux-policy-default,gdb $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 printf '\nauto eth0\niface eth0 inet dhcp\n' | sudo tee -a $DIR/etc/network/interfaces echo 'debugfs /sys/kernel/debug debugfs defaults 0 0' | sudo tee -a $DIR/etc/fstab echo 'SELINUX=disabled' | sudo tee $DIR/etc/selinux/config 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_harden = 2" | 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 "debugging-machine" | 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=1M seek=2047 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 | cs |
위 코드를 create-image.sh로 붙여넣고 실행해주면 됩니다.
(google syzkaller에서 가져옴 (https://github.com/google/syzkaller/blob/master/tools/create-image.sh))
wheezy.img까지 정상적으로 생성되었다면 이제 부팅을 할 시간입니다.
qemu가 없다면 sudo apt-get install qemu kvm qemu-kvm을 해서 설치해주고
qemu-system-x86_64 -kernel bzImage -append "console=ttyS0 root=/dev/sda debug" -hda wheezy.img -net user,hostfwd=tcp::10021-:22 -net nic -nographic -m 4G -smp 2 -s
을 이용해서 부팅할 수 있습니다.
kernel은 아까 컴파일한 bzImage파일을 사용하겠다는 의미이고 이미지는 wheezy.img, 22번 포트를 10021포트로 리다이렉팅 했기 때문에 ssh -p 10021 -i wheezy.id_rsa root@localhost를 이용해서 ssh접속을 할 수 있습니다.
그리고 메모리 4G, cpu코어 두개를 할당하고 1234번 포트로 gdb 디버깅이 들어오도록 listen하고 있겠다는 의미입니다.
만약 본인의 cpu가 가상화를 지원한다면 -enable-kvm 옵션을 추가해서 좀 더 빠르게 qemu를 돌릴 수 있습니다.
이제 정상적으로 부팅이 됐다면 디버깅을 해볼 차례입니다. qemu를 종료하고 gdb -q ./vmlinux를 해서 심볼을 로드합니다.
그 후 b*start_kernel을 해서 커널의 첫 시작 함수인 start_kernel에 브레이크 포인트를 걸고 target remote localhost:1234를 해서 1234번 포트로 디버기가 붙기를 기다립니다.
그 후 다시 qemu를 부팅한다면 gdb로 커널이 붙게됩니다. 그 상태에서 c를 입력해주면 start_kernel에 브레이크 포인트가 걸립니다.
심볼까지 로드했기 때문에 현재 어셈의 위치와 소스를 비교하면서 디버깅 할 수 있습니다.
이제 원하는 함수 / 드라이버에 브레이크 포인트를 걸고 디버깅하면 됩니다.
'Linux Kernel' 카테고리의 다른 글
커널 컴파일 시 code model kernel does not support PIC mode 해결법 (2) | 2018.03.27 |
---|---|
커널 옛날 버전 컴파일 하다가 ____ilog2_nan 에러날 때 (0) | 2018.03.20 |