文章目錄
-
- 前言
- 編譯linux核心
-
- 下載下傳核心源碼
- 編譯核心
- 制作initramfs檔案系統
-
- initrd介紹
- initramfs檔案系統制作
- qemu啟動
- 使用Debootstrap制作檔案系統
-
- 使用Debootstrap制作檔案系統
- 修改檔案系統
- 添加共享檔案夾
- builtroot
- 參考文章
前言
本部落格要求:可以根據需要,自行搭建基礎的linux實驗環境。
編譯核心要求:可以通過checkout,編譯任何指定版本的核心。
制作disk image要求:可以自行填充busybox等資訊制作一個簡易的initrd;可以借助debootstrap制作并修改成一個可以正常使用的disk image。
qemu要求:啟動的時候可以指定bzImage和disk image;可以設定通路外網;可以設定主機和虛拟機之間共享檔案件。
builtroot:了解即可。
ps:在閱讀這篇blog之前,建議先閱讀:syzkaller安裝
編譯linux核心
我fork一份linux源碼到自己的倉庫。主分支定期拉取上遊倉庫,使得可以看到最新的linux核心源碼。
當需要特定版本的核心操作實驗的時候,checkout過去就好。實驗後作為分支上傳到自己的倉庫。
編譯的時候全部,全部編譯的外面的目錄。
這樣便一直有一份最新的源碼,随時可以切換到特定的版本。非常友善。
下載下傳核心源碼
git檔案名大小寫問題:我電腦的磁盤空間不夠,外接一個U盤。U盤開始采用fat格式,clone linux之後,出現檔案大小寫問題。是以我将U盤部分格式化為ext4,重新clone。
Github進行fork後如何與原倉庫同步:重新fork很省事,但不如反複練習版本合并:為了更好的檢視和修改代碼,我frok了linux到我的倉庫。
# 我fork了linux到我的倉庫
git clone [email protected]:da1234cao/linux.git
# [該commit](https://github.com/torvalds/linux/commit/581738a681b6faae5725c2555439189ca81c0f1f)
# 在5.5版本中引入,也影響到5.6版本
git show 581738a681b6faae57 # 檢視commit資訊
git branch --contains 581738a681b6faae57 # 檢視該commit對應的分支
git tag --contains 581738a681b6faae57 # 從目前的commit往後查找tag
# 切換到v5.6
git checkout v5.6
##### 為了和上遊保持同步
# 添加上遊倉庫
git remote add upstream [email protected]:torvalds/linux.git
git remote -v # 檢視你的遠端倉庫的路徑
##### 漏洞自建一個分支,以後所有關于該漏洞的内容都送出到該分支
# 我checkout 5.6之後,沒有先建立分支,直接修改了5.6的版本
git stash # 在目前分支上的修改暫存起來
git branch CVE-2020-8835
git checkout CVE-2020-8835
git stash pop # 将暫存的修改放到建立分支中
git add .
git commit
git push origin CVE-2020-8835
# 下次記得修改之前,建立自己的分支
git branch test
git checkout test
##### 為了和上遊保持同步
git checkout master
# 因為我主分支一直沒動,是以fetch之後,下面merger不會沖突。這步很慢,可以在晚上的時候運作
git fetch upstream # 抓取上遊原倉庫的更新;
git merge upstream/master # 合并upstream/master到目前分支
git push origin master
#### 這裡再補充一下标簽同步
git fetch upstream --tags #擷取源項目的tag
git push origin --tags #将新的tag推送到fork項目
編譯核心
基本編譯如下。Kernel Build System還是不要看了,待萬不得已的時候再看。
# 編譯核心:O=...,指定kbuild的output;
make mrproper # 保持幹淨源碼
make defconfig O=../linux_image/5.6 # 生成預設配置到./config中
make kvmconfig O=../linux_image/5.6 # Enable additional options for kvm guest kernel support
make O=../linux_image/5.6
很多核心參數,我不知道。需要的時候,去搜特定的參數功能吧。這裡開始積攢我用到過的參數。
# 修改幾個核心配置選項,編輯./config
# Enable kernel config options required for syzkaller
# Coverage collection.
CONFIG_KCOV=y
# Debug info for symbolization.
CONFIG_DEBUG_INFO=y
# Memory bug detector
CONFIG_KASAN=y
CONFIG_KASAN_INLINE=y
# Required for Debian Stretch
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y
制作initramfs檔案系統
我是看到0x04-pwn2own-ebpf-jmp32-cve-2020-8835。這樣隻要有一個人搭建漏洞環境,其他人直接運作就好。感覺很友善。
對于上面倉庫中initramfs制作過程的疑惑,我送出了一個issue:initramfs.cpio中的init可以為空嗎
initrd介紹
參考: boot loader 與 kernel 加載
當啟動時無法挂載根目錄的情況下,一定需要 initrd。
如果你的 Linux 是安裝在 IDE 介面的磁碟上,并且使用預設的 ext2/ext3 檔案系統, 那麼不需要 initrd 也能夠順利的啟動進入 Linux 的!
萬一遇到根檔案系統在一個硬碟上。而核心沒有讀取這個硬碟的驅動。而硬碟的驅動存儲在硬碟中的根檔案系統中。這樣便産生死鎖。
boot loader 可以加載kernel 與initrd ,然後在記憶體中讓initrd 解壓縮成為根目錄, kernel 就能夠借此加載适當的驅動程式,并挂載實際的根目錄檔案系統, 就能夠開始後續的正常啟動流程。
我們也可以使用cpio檢視目前系統中/boot/initrd.img。
initramfs檔案系統制作
我們借助busybox制作。但是busybox是一些程式的集合,沒法填充成完整的檔案系統。是以我們還需要手動複制其他檔案。
我不知道咋整,從網上東看看,西瞅瞅,如下設定。
整體内容填充。
# 下載下傳busybox
curl https://busybox.net/downloads/busybox-1.33.1.tar.bz2 | tar xjf -
cd busybox-1.33.1
# 編譯安裝busybox
mkdir -pv obj/busybox-x86
make O=obj/busybox-x86 defconfig
cd obj/busybox-x86
ls -alh .config
vim .config # 修改添加靜态連結: CONFIG_STATIC=y #
make -j4
make install # install在_install目錄
# 檢視_install裡面内容:有三個目錄,一個檔案
# 裡面的内容全部是busybox的軟連接配接。
# 跳出到外面,制作initramfs
mkdir initramfs
mkdir -pv {bin,sbin,dev,etc,proc,sys,usr}
mkdir -pv {etc/init.d,usr/{bin,sbin}}
cp -a ../busybox-1.33.1/obj/busybox-x86/_install/* initramfs
sudo cp -a /dev/{null,console,tty1,tty2,tty3,tty4} dev
鳥哥中 boot loader 與 kernel 加載 介紹的内容太陳舊了。陳皓也寫過一篇系統啟動的文章:LINUX PID 1 和 SYSTEMD
我當初學習作業系統的時候,學習的是:計算機的啟動過程
現在作業系統的啟動流程,我不清楚。busybox還來這裡攪和一趟。關鍵的是busybox文檔,我也沒看到詳細的描述。
busybox是一個包含很多程式的套件,它也包含
init
程式。
下面我們設定下啟動選項。
方式一:自己寫
touch etc/init.d/rcS
vim etc/init.d/rcS
# 添加下面内容
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
################
# rcS需要可執行權限
chmod 774 etc/init.d/rcS
方式二:使用busybox自帶的内容。
cp -a ../../busybox-1.33.1/examples/bootfloppy/etc/* etc
或許,我們還應該給檔案系統中添加使用者等等。但是這并不容易。
後面,我們使用工具建立檔案系統,将會容易很好。
制作成initrawfs。
find . -print0 | cpio --null -ov --format=newc | gzip -9 > initramfs-busybox-x86.cpio.gz
qemu啟動
關于參數,沒啥辦法,遇到的時候,一個一個到QEMU documentation中搜尋,或直接google。
#!/bin/bash
bzImage_dir=$1
cpio_dir=$2
#run vm
#timeout --foreground 600
qemu-system-x86_64 \
-m 256M \
-enable-kvm \
-nographic -kernel $bzImage_dir \
-append 'root=/dev/ram rw console=ttyS0' \
-initrd $cpio_dir \
-smp cores=2,threads=2 \
-cpu kvm64,+smep,+smap \
-pidfile vm.pid
2>/dev/null
# 檔案結構
➜ linux_image tree -L 1
.
├── 5.6 # 編譯生成的核心
├── 5.6_qemu_cmd.sh # qemu的啟動腳本
└── initramfs # initramfs
# 啟動
./5.6_qemu_cmd.sh ./5.6/arch/x86/boot/bzImage ./initramfs/initramfs-busybox-x86.cpio.gz
# 關閉
kill `cat vm.pid | grep -v '^$'`
# 或者 ctrl + A ,松手,按x
使用Debootstrap制作檔案系統
主要是修改檔案系統+配置共享檔案夾
使用Debootstrap制作檔案系統
自行參考:建構檔案系統
qemu-img create debian.img 1G
Formatting 'debian.img', fmt=raw size=1073741824
# dd if=/dev/zero of=$RELEASE.img bs=1M seek=$SEEK count=1
mkfs.ext4 debian.img
mkdir mnt
sudo mount -o loop debian.img mnt/
sudo debootstrap buster mnt/ # 我們下載下傳debian 10的根檔案系統
sudo umount mnt
rm -rf mnt
修改檔案系統
這個檔案系統非常clear,我們得修改修改。
# 比較尴尬的是,待會qemu啟動的時候,我不知道登入密碼
# 是以,我們需要将上面的img挂載起來,chroot進入,修改登入密碼
mkdir mnt
sudo mount debian.img mnt/
sudo chroot mnt
passwd # 密碼随手起[避免以後忘記,這裡記錄一下]:111111
exit
sudo umount mnt
rm -rf mnt
# 我們使用qemu登入
#!/bin/bash
bzImage_dir=$1
fs_dir=$2
#run vm
#timeout --foreground 600
qemu-system-x86_64 \
-m 256M \
-enable-kvm \
-nographic -kernel $bzImage_dir \
-append 'root=/dev/sda rw console=ttyS0' \
-drive file=$2,format=raw \
-smp cores=2,threads=2 \
-cpu kvm64,+smep,+smap \
-net nic \
-net user \
-pidfile vm.pid \
2>/dev/null
給檔案系統添加網絡配置,以可以連接配接外網。
# 修改網絡配置
ip a
printf '\nauto enp0s3\niface enp0s3 inet dhcp\n' | tee -a /etc/network/interfaces
# 添加普通使用者
useradd -d /home/dacao -m dacao
passwd dacao
chsh -s /bin/bash dacao
usermod -G sudo dacao
apt install sudo
添加共享檔案夾
還需要Qemu虛拟機與主控端之間檔案傳輸
dd if=/dev/zero of=$PWD/share.img bs=1M count=2000
mkfs.ext4 $PWD/share.img
mkdir $PWD/share
但是下面的方法不大靈光。。我不知道為啥。。
#!/bin/bash
bzImage_path="../5.6/arch/x86/boot/bzImage"
rfs_image_path="../debian.img"
share_fs_path="../share.img"
share_mnt_path="../share"
read -e -i "$bzImage_path" -p "enter bzImage path : " bzImage_path
read -e -i "$rfs_image_path" -p "enter root file system image path : " rfs_image_path
read -e -i "$share_fs_path" -p "enter share file system image path : " share_fs_path
read -e -i "$share_mnt_path" -p "enter the share image mnt path : " share_mnt_path
sudo mount -o loop $share_fs_path $share_mnt_path
read -s -n1 -p "請将主機的檔案放到共享檔案夾中\n之後\n按任意鍵繼續 ... "
qemu-system-x86_64 \
-m 256M \
-enable-kvm \
-nographic -kernel $bzImage_path \
-append 'root=/dev/sda rw console=ttyS0' \
-drive file=$rfs_image_path,format=raw \
-drive file=$share_fs_path,if=virtio \
-smp cores=2,threads=2 \
-cpu kvm64,+smep,+smap \
-net nic \
-net user \
-pidfile vm.pid \
2>/dev/null
sudo umount $share_mnt_path
是以,我換用Documentation/9psetup | qemu中使用 9p virtio
# 現在的啟動腳本
#!/bin/bash
bzImage_path="../5.6/arch/x86/boot/bzImage"
rfs_image_path="../debian.img"
share_mnt_path="../share"
read -e -i "$bzImage_path" -p "enter bzImage path : " bzImage_path
read -e -i "$rfs_image_path" -p "enter root file system image path : " rfs_image_path
read -e -i "$share_mnt_path" -p "enter the share image mnt path : " share_mnt_path
qemu-system-x86_64 \
-m 256M \
-enable-kvm \
-nographic -kernel $bzImage_path \
-append 'root=/dev/sda rw console=ttyS0' \
-drive file=$rfs_image_path,format=raw \
-smp cores=2,threads=2 \
-cpu kvm64,+smep,+smap \
-net nic \
-net user \
-fsdev local,security_model=passthrough,id=fsdev0,path=$share_mnt_path \
-device virtio-9p-pci,fsdev=fsdev0,mount_tag=hostshare \
-pidfile vm.pid \
2>/dev/null
其中,起到共享目錄的配置是這兩行。
-fsdev local,security_model=passthrough,id=fsdev0,path=$share_mnt_path \
-device virtio-9p-pci,fsdev=fsdev0,mount_tag=hostshare \
之後,我們進入虛拟機之後,根據mount_tag,将其挂載到适當位置。
mount -t 9p -o trans=virtio hostshare /home/dacao/host_file/
這裡還有另一種共享檔案的方式:virtio-fs – 沒看明白。。
builtroot
builtroot可以根據選擇,同時生成bzImage和根檔案系統。
這裡有個視訊的tutorial:Buildroot Tutorial- Linux Kernel on QEMU Virtual board - Booting Linux and Running Linux Application
- Target Architecture (x86_64)
- (111111) Root password | Run a getty (login prompt) after boot
- Kernel version (Custom version) | (4.6) Kernel version ??
- Kernel configuration (Using an in-tree defconfig file) | (kvm_guest.config) Additional configuration fragment files ??
- -*- BusyBox
- ext2/3/4 variant (ext4)
- host qemu
我選了這些,不知道對不對。大體是這麼操作的。
參考文章
快速搭建一個Linux核心調試環境 – 這篇文章強調“快”
用QEMU來調試核心 – 親身體驗篇 – 這篇文章的“參考”很好