最近在復現一篇論文的時候發現linux內核的強大之處了,就簡單的學習了下關於內核的一些知識,其中主要用到了Kasan這個檢測UAF漏洞的工具(嚴格來說只能是內核編譯插樁),本以爲很簡單,結果搞了好長時間,鑑於目前這方面資料很少,設置過程也缺乏,故將這個設置過程記錄下來,以便交流(本文僅限學術交流,嚴謹轉載)
一 內核編譯
內核編譯過程主要參考了《鳥哥的Linux私房菜》,以及https://www.jianshu.com/p/e1f550ba164d
1 查看自己ubuntu的內核版本 uname -a(-r)
2 查看可用的內核版本:
3 安裝與自己內核頭文件相應的的內核源碼 sudo apt-get install linux-source-4.10.0(內核文件並不大,一般的也就在100M左右),下載完後會直接在/usr/src中看到相應的內核源碼,運行 cd /usr/src 轉到目錄後解壓源碼:sudo tar -axvf linux-source-4.10.0.tar.bz2,轉到相應的源碼目錄:cd /usr/src/linux-source-4.10.0
源碼中一些基本的信息:
arch:與硬件平臺有關的選項,大部分指的是CPU的類別,例如 x86,x86_64,Xen虛擬支持等;
block:與區塊設備較相關的設置數據,區塊數據通常指的是大量存儲媒體,還包括ext3等文件系統的支持是否允許等;
crypto:內核所支持的加密技術,如 md5或des等;
Documention:與內核有關的幫助文檔;
drivers:一些硬件的驅動程序,如顯卡、網卡、PCI相關硬件;
firmware:一些舊式硬件的微指令(固件)數據;
fs:內核所支持的filesystems,如vfat、nfs等;
include:一些可讓其他程序調用的頭(header)定義數據;
init:一些內核初始化的定義功能,包括掛載與init程序的調用等;
ipc:定義Linux操作系統內各程序的通信;
kernel:定義內核的程序、內核狀態、線程、程序的調度(schedule)、程序的信號(signal)等;
lib:一些函數庫;
mm:與內存單元有關的各種信息,包括swap與虛擬內存等;
net:與網絡有關的各項協議信息,還有防火牆(net/ipv4/netfilter/*)等;
security:包括SELinux等安全性設置;
sound:與音效有關的各項模塊;
virt:與虛擬化及其有關的信息,目前內核支持的是KVM(Kernel base Virtual Machine)
4 修改設置:sudo make menuconfig(==make oldconfig ==make xconfig == make gconfig == make config ==sudo vim .config)
報錯,其原因是缺少庫,解決方法:
sudo apt-get install libncurses5-dev
之後再次運行 sudo make menuconfig,得到圖形化界面,在kernel hacking/memory debugging中,可以使用空格進行選擇,前面有M的表示模塊
找到kasan,首先查看Help,查看相關的依賴選項:
注意,KASAN[=n]表示的是目前的狀態時未打開,selects 則和symbol保持着一致性(symbol是啥,selects就是啥),而相關的依賴需要打開。要是找不到,可以在選好後保存,然後 sudo gedit .config進行修改,不過相關的依賴前面會加上CONFIG_的前綴。同時還要注意:enable,don‘t work with後面的選項。當然你也可以使用別人已經設置好的.config文件。
在Kasan的子目錄裏,進行模式選擇,inline比outline要快一些,所以設置
另外還有SLUB,設置後,保存,退出,在源碼的目錄下,Ctrl+H,會發現多出了.config文件,這個就是配置文件了。
5 編譯內核、模塊
make -j 2 clean #先清除臨時文件
make -j 2 bzImage #先編譯內核,生成bzImage文件(中量時間)
sudo make -j 2 modules #再編譯模塊,要權限(大量時間)
製作出來的資料是被放置在/usr/src/linux-source-4.10.0/kernel 目錄下,還沒有被放到系統的相關路徑中
##-j [N], --jobs[=N] 同時允許 N 個任務;無參數表明允許無限個任務
6 安裝模塊
上步編譯內核、模塊後,還沒有將其放入相關的系統路徑中,模塊需要安裝,內核也需要移動位置。模塊會被安裝在/lib/modules的目錄下,這兒一定要注意,當兩個版本一模一樣時,模塊放置的目錄也一樣,此時就會產生衝突,解決方法:
方法1:先將舊的模塊目錄更名,然後才安裝內核模塊到目標目錄中去;
方法2:在 make menuconfig 時,將General setup內的Local version修改成新的名稱;
我在我的機子上實驗並沒有遇到這個問題,所以直接運行:sudo make modules_install,安裝之後,會在/lib/modules下生成一個新目錄
7 移動內核
內核文件通常以 vmlinuz 爲開頭,後面跟上內核版本的文件格式。複製新內核文件到 /boot/ 下並改名 vmlinuz-3.10.107,保留舊內核文件。(命名時,我參考了我的模塊生成的目錄)
sudo cp /usr/src/linux-source-4.10.0/arch/x86/boot/bzImage /boot/vmlinuz-4.10.17
sudo cp /usr/src/linux-source-4.10.0/.config /boot/config-4.10.17
#給新內核文件添加 X 權限
sudo chmod a+x /boot/vmlinuz-4.10.17
sudo cp /usr/src/linux-source-4.10.0/System.map /boot/System.map-4.10.17
sudo gzip -c /usr/src/linux-source-4.10.0/Module.symvers > /boot/symvers-4.10.17(這個要最高權限)
##sudo passwd設置密碼(第一次時)
##su
##獲取最高權限
8 建立相對應的 Initial Ram Disk(initrd)
首先安裝dracut:sudo apt install dracut
其次:sudo dracut -v /boot/initramfs-4.10.17.img 4.10.17
9 編輯開機選項(grub)
在/boot/grub下沒有發現grub2,只能用grub
grub-mkconfig -o /boot/grub/grub.cfg
由此,就可以重新開機並選擇新內核來啓動系統啦!(啓動時進入ubuntu界面按住shift,進入ubuntu高級選項,可以自由選擇內核啓動)
注意:在虛擬機上編譯內核後重啓會出現一個錯誤:
VBoxClient (seamless): failed to start. Stage: Setting guest IRQ filter mas Error: VERR_INTERNAL_ERROR
這個錯誤是關於VBOX的增強功能的,通過以下命令來解決:
sudo apt-get install gcc make perl
cd /media/$USER/VBox_GAs_5.2.22
sudo ./VBoxLinuxAdditions.run
sudo reboot
至此,我們完成了內核編譯的整個過程。
二 內核模塊的操作
上節內容講解了內核、模塊的編譯,安裝過程。事實上,有時候我們僅僅只是想安裝一個模塊,而不想重新編譯內核,那麼在內核需要的功能開啓的情況下,單獨編譯模塊是否可行呢?,回答是正確的,可以實現內核模塊的編譯過程。本節內容主要參考:https://blog.csdn.net/yeshennet/article/details/82315604
簡單的hello world模塊
1 hello.c文件
/*
* hello.c - The simplest kernel module.
*/
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
/*
* A non 0 return means init_module failed; module can't be loaded.
*/
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}
2 Makefile文件
obj-m += hello.o
all:
make -C /lib/modules/4.10.17/build M=$(PWD) modules
clean:
make -C /lib/modules/4.10.17/build M=$(PWD) clean
注意三點:1 hello.o要和hello.c對應,2 Makefile中的目錄是你安裝模塊時的模塊安裝目錄,3 Makefile中make前面是一個TAB符。運行:make,結果如下
同時在目錄裏生成一些文件
其中hello.ko文件就是我們說的模塊
我們對這個hello模塊文件進行操作
1插入一個模塊:
sudo insmod hello.ko
要是報錯:
insmod: ERROR: could not insert module hello.ko: Invalid module format
可能原因:make時使用的內核版本和本系統的內核版本不一致
需要重新啓動,選擇內核來實現模塊插入等操作
uname -r
運行插入模塊的命令
2 查看模塊的相關信息
sudo modinfo hello.ko
3 卸載模塊
sudo rmmod hello.ko
4 lsmod 命令是查看當前已載入的模塊
模塊的基本介紹就到此結束,下節介紹對kasan功能的實現
三 對KASAN功能的實現
實際上,linux內核源碼提供了關於測試kasan的模塊,在內核編譯中可以直接選擇,但是作者本人太笨,一直不知道怎麼搞,另外也想簡單的學習下內核模塊是怎麼搞出來的,就沒打開test_kasan模塊,而是採用上一小節的方法嘗試着將test_kasan.ko做出來。
在內核源碼usr/src/linux-source-4.10.0/lib中可以找到test_kasan.c文件,之後,我們選擇其中的一個函數進行測試就行,不過依然需要我們編寫一個Makefile文件。
首先從test_kasan.c中抽出一個函數作爲test.c文件
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/module.h>
int init_module(void)
{
char *ptr;
size_t size = 123;
pr_info("out-of-bounds to right\n");
ptr = kmalloc(size, GFP_KERNEL);
if (!ptr) {
pr_err("Allocation failed\n");
return 0;
}
ptr[size] = 'x';
kfree(ptr);
}
void cleanup_module(void)
{
printk(KERN_INFO "GOODBYE\n");
}
其次,製作Makefile文件
obj-m += test.o
all:
make -C /lib/modules/4.10.17/build M=$(PWD) modules
clean:
make -C /lib/modules/4.10.17/build M=$(PWD) clean
之後,sudo make和 make 產生了不同的結果(先sudo make,後make)
最終還是生成了相關的文件
運行sudo insmod test.ko後,在運行 dmesg 查看相關信息
會在打印的內容中找到以下的字樣:
或者,也可以在/usr/log/kern.log中找到相關的記錄
由此來看,kasan是一個自動化的內核插樁工具,他不會給你任何的提示來說明是否打開了kasan,需要在對內核的相關過程中實現自動化的檢測,要是不懂dmesg命令,還真不知道這個kasan怎麼搞。KASAN藏的真夠深的!!
想了解kasan原理的可以參考:https://www.cnblogs.com/alantu2018/p/8457420.html
四 總結
到此,我們實現了整個過程,從中學習到了內核的編譯,模塊的編譯,kasan的相關操作。內核的編譯很容易出錯,要是在虛擬機中做,最好要學會時刻保存備份。模塊的編譯,我只看了最基礎的那部分內容,其他的並沒有深入,有興趣的可以參考文中的網址。Kasan的操作是一個很有用的工具,能夠自動化檢測UAF漏洞。總之,經過這次學習,總算理解了爲啥搞安全的都喜歡Linux,這個功能真的強大。
再次感謝文中的博客提供的寶貴資料!!