近日,我在寫內(nèi)核模塊的時(shí)候犯了一個(gè)低級(jí)錯(cuò)誤:
直接access用戶態(tài)的內(nèi)存而沒(méi)有使用copy_to_user/copy_from_user!
在內(nèi)核看來(lái),用戶態(tài)提供的虛擬地址是不可信的,所以在一旦在內(nèi)核態(tài)訪問(wèn)用戶態(tài)內(nèi)存發(fā)生缺頁(yè)中斷,處理起來(lái)是非常棘手的。
Linux內(nèi)核的做法是提供了一張 異常處理表 ,使用專有的函數(shù)來(lái)訪問(wèn)用戶態(tài)內(nèi)存。類似 try-catch塊一般。具體詳情可參見(jiàn)copy_to_user/copy_from_user的實(shí)現(xiàn)以及內(nèi)核文檔Documentation/x86/exception-tables.txt的描述。
本來(lái)簡(jiǎn)單看下這個(gè)異常處理表能怎么玩。
首先,我們可以寫一片代碼,將內(nèi)核的異常處理表dump下來(lái):
// show_extable.c#include
我們看下輸出:
# ___sys_recvmsg+0x253位置發(fā)生異常,跳轉(zhuǎn)到ffffffff81649396處理異常。[ 7655.267616] [ffffffff8150d7a3]___sys_recvmsg+0x253/0x2b0 [ffffffff81649396]bad_to_user...# create_elf_tables+0x3cf位置處如果發(fā)生異常,跳轉(zhuǎn)到ffffffff81648a07地址執(zhí)行異常處理。[ 7655.267727] [ffffffff8163250e]create_elf_tables+0x3cf/0x509 [ffffffff81648a1b]bad_gs
一般而言,類似bad_to_user,bad_from_user之類的異常處理函數(shù)都是直接返回用戶一個(gè)錯(cuò)誤碼,比如Bad address之類,并不是直接用戶程序直接段錯(cuò)誤,這一點(diǎn)和用戶態(tài)訪問(wèn)非法地址直接發(fā)送SIGSEGV有所不同。比如:
#include
執(zhí)行之:
[root@localhost test]# ./a.outopen: Successread: Bad address # 沒(méi)有段錯(cuò)誤,只是一個(gè)普通錯(cuò)誤。
我們能不能將其行為修改成和用戶態(tài)訪問(wèn)非法地址一致呢?簡(jiǎn)單,替換掉bad_to_user即可,代碼如下:
// fix_ex.c#include
編譯,加載,重新執(zhí)行我們的a.out:
[root@localhost test]# insmod ./fix_ex.ko[root@localhost test]# ./a.outopen: Success段錯(cuò)誤[root@localhost test]# dmesg[ 8686.091738] 經(jīng)理!rush tighten beat electric discourse! SB 皮鞋[root@localhost test]#
發(fā)生了段錯(cuò)誤,并且打印出了讓經(jīng)理趕緊打電話的句子。
其實(shí),我的目的并不是這樣的,我真正的意思是,Linux的異常處理鏈表,又是一個(gè)藏污納垢的好地方,我們可以在上面的hook函數(shù)中藏一些代碼,比如說(shuō)inline hook之類的,然后呢?然后靜悄悄地等待用戶態(tài)進(jìn)程的bug導(dǎo)致異常處理被執(zhí)行。將代碼注入的時(shí)間線拉長(zhǎng),從而更難讓運(yùn)維和經(jīng)理注意到。
讓代碼注入的時(shí)間點(diǎn)和模塊插入的時(shí)間點(diǎn)分開(kāi),讓事情更加混亂。不過(guò),注意好隱藏模塊或者oneshot哦。
-
模塊
+關(guān)注
關(guān)注
7文章
2837瀏覽量
53283 -
Linux
+關(guān)注
關(guān)注
88文章
11758瀏覽量
219009 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4417瀏覽量
67501
原文標(biāo)題:Linux內(nèi)核態(tài)缺頁(yè)會(huì)發(fā)生什么 - 玩轉(zhuǎn)Exception fixup表
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
Linux內(nèi)核的“心跳”:jiffies如何為系統(tǒng)計(jì)時(shí)?
深入RK3588內(nèi)核:rockchip_linux_defconfig的作用與調(diào)試價(jià)值
Linux系統(tǒng)內(nèi)核參數(shù)調(diào)優(yōu)實(shí)戰(zhàn)指南
【「Linux 設(shè)備驅(qū)動(dòng)開(kāi)發(fā)(第 2 版)」閱讀體驗(yàn)】+讀深入理解Linux內(nèi)核內(nèi)存分配
【「Linux 設(shè)備驅(qū)動(dòng)開(kāi)發(fā)(第 2 版)」閱讀體驗(yàn)】Linux內(nèi)核開(kāi)發(fā)基礎(chǔ)
深入Linux內(nèi)核:進(jìn)程調(diào)度的核心邏輯與實(shí)現(xiàn)細(xì)節(jié)
Linux內(nèi)核日志玩明白了嗎?printk調(diào)試神器全解析
基于 DR1M90 的 Linux-RT 內(nèi)核開(kāi)發(fā):從編譯配置到 GPIO / 按鍵應(yīng)用實(shí)現(xiàn)(1)
Linux內(nèi)核模塊的加載機(jī)制
Linux內(nèi)核printk日志級(jí)別全解析:從參數(shù)解讀到實(shí)操配置
探索操作系統(tǒng)底層的關(guān)鍵接口
deepin亮相2025中國(guó)Linux內(nèi)核開(kāi)發(fā)者大會(huì)
Linux內(nèi)核參數(shù)調(diào)優(yōu)方案
如何配置和驗(yàn)證Linux內(nèi)核參數(shù)
樹(shù)莓派4 性能大比拼:標(biāo)準(zhǔn)Linux與實(shí)時(shí)Linux 4.19內(nèi)核的延遲測(cè)試
Linux內(nèi)核態(tài)缺頁(yè)會(huì)發(fā)生什么 - 玩轉(zhuǎn)Exception fixup表
評(píng)論