91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

Linux內(nèi)核態(tài)缺頁會發(fā)生什么 - 玩轉Exception fixup表

Linux閱碼場 ? 來源:Linuxer ? 2020-06-03 15:08 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

近日,我在寫內(nèi)核模塊的時候犯了一個低級錯誤:

直接access用戶態(tài)的內(nèi)存而沒有使用copy_to_user/copy_from_user!

在內(nèi)核看來,用戶態(tài)提供的虛擬地址是不可信的,所以在一旦在內(nèi)核態(tài)訪問用戶態(tài)內(nèi)存發(fā)生缺頁中斷,處理起來是非常棘手的。

Linux內(nèi)核的做法是提供了一張 異常處理表 ,使用專有的函數(shù)來訪問用戶態(tài)內(nèi)存。類似 try-catch塊一般。具體詳情可參見copy_to_user/copy_from_user的實現(xiàn)以及內(nèi)核文檔Documentation/x86/exception-tables.txt的描述。

本來簡單看下這個異常處理表能怎么玩。

首先,我們可以寫一片代碼,將內(nèi)核的異常處理表dump下來:

// show_extable.c#include #include int (*_lookup_symbol_name)(unsigned long, char *);unsigned long (*_get_symbol_pos)(unsigned long, void *, void *);unsigned long start_ex, end_ex; int init_module(void){ unsigned long i; unsigned long orig, fixup, originsn, fixinsn, offset, size; char name[128], fixname[128]; _lookup_symbol_name = (void *)kallsyms_lookup_name("lookup_symbol_name"); _get_symbol_pos = (void *)kallsyms_lookup_name("get_symbol_pos"); start_ex = (unsigned long)kallsyms_lookup_name("__start___ex_table"); end_ex = (unsigned long)kallsyms_lookup_name("__stop___ex_table"); // 按照exception_table_entry的sizeof從start遍歷到end。 for(i = start_ex; i < end_ex; i += 2*sizeof(unsigned long)) { orig = i; // 取出exception_table_entry的insn字段地址。 fixup = i + sizeof(unsigned int); // 取出fixup字段地址。 originsn = orig + *(unsigned int *)orig; // 根據(jù)相對偏移字段求出絕對地址 originsn |= 0xffffffff00000000; fixinsn = fixup + *(unsigned int *)fixup; fixinsn |= 0xffffffff00000000; _get_symbol_pos(originsn, &size, &offset); _lookup_symbol_name(originsn, name); _lookup_symbol_name(fixinsn, fixname); printk("[%lx]%s+0x%lx/0x%lx [%lx]%s ", originsn, name, offset, size, fixinsn, fixname); } return -1;}MODULE_LICENSE("GPL");

我們看下輸出:

# ___sys_recvmsg+0x253位置發(fā)生異常,跳轉到ffffffff81649396處理異常。[ 7655.267616] [ffffffff8150d7a3]___sys_recvmsg+0x253/0x2b0 [ffffffff81649396]bad_to_user...# create_elf_tables+0x3cf位置處如果發(fā)生異常,跳轉到ffffffff81648a07地址執(zhí)行異常處理。[ 7655.267727] [ffffffff8163250e]create_elf_tables+0x3cf/0x509 [ffffffff81648a1b]bad_gs

一般而言,類似bad_to_user,bad_from_user之類的異常處理函數(shù)都是直接返回用戶一個錯誤碼,比如Bad address之類,并不是直接用戶程序直接段錯誤,這一點和用戶態(tài)訪問非法地址直接發(fā)送SIGSEGV有所不同。比如:

#include int main(int argc, char **argv){ int fd; int ret; char *buf = (char *)0x56; // 顯然是一個非法地址。 fd = open("/proc/sys/net/nf_conntrack_max", O_RDWR | O_CREAT, S_IRWXU); perror("open"); ret = read(fd, buf, 100); perror("read");}

執(zhí)行之:

[root@localhost test]# ./a.outopen: Successread: Bad address # 沒有段錯誤,只是一個普通錯誤。

我們能不能將其行為修改成和用戶態(tài)訪問非法地址一致呢?簡單,替換掉bad_to_user即可,代碼如下:

// fix_ex.c#include #include #include int (*_lookup_symbol_name)(unsigned long, char *);unsigned long (*_get_symbol_pos)(unsigned long, void *, void *);unsigned long start_ex, end_ex;void *_bad_from_user, *_bad_to_user; void kill_user_from(void){ printk("經(jīng)理!rush tighten beat electric discourse! "); force_sig(SIGSEGV, current);} void kill_user_to(void){ printk("經(jīng)理!rush tighten beat electric discourse! SB 皮鞋 "); force_sig(SIGSEGV, current);} unsigned int old, new; int (*_lookup_symbol_name)(unsigned long, char *);unsigned long (*_get_symbol_pos)(unsigned long, void *, void *); int hook_fixup(void *origfunc1, void *origfunc2, void *newfunc1, void *newfunc2){ unsigned long i; unsigned long fixup, fixinsn; char fixname[128]; for(i = start_ex; i < end_ex; i += 2*sizeof(unsigned long)) { fixup = i + sizeof(unsigned int); fixinsn = fixup + *(unsigned int *)fixup; fixinsn |= 0xffffffff00000000; _lookup_symbol_name(fixinsn, fixname); if (!strcmp(fixname, origfunc1) || !strcmp(fixname, origfunc2)) { unsigned long new; unsigned int newfix; if (!strcmp(fixname, origfunc1)) { new = (unsigned long)newfunc1; } else { new = (unsigned long)newfunc2; } new -= fixup; newfix = (unsigned int)new; *(unsigned int *)fixup = newfix; } } return 0;} int init_module(void){ _lookup_symbol_name = (void *)kallsyms_lookup_name("lookup_symbol_name"); _get_symbol_pos = (void *)kallsyms_lookup_name("get_symbol_pos"); _bad_from_user = (void *)kallsyms_lookup_name("bad_from_user"); _bad_to_user = (void *)kallsyms_lookup_name("bad_to_user"); start_ex = (unsigned long)kallsyms_lookup_name("__start___ex_table"); end_ex = (unsigned long)kallsyms_lookup_name("__stop___ex_table"); hook_fixup("bad_from_user", "bad_to_user", kill_user_from, kill_user_to); return 0;}void cleanup_module(void){ hook_fixup("kill_user_from", "kill_user_to", _bad_from_user, _bad_to_user);} MODULE_LICENSE("GPL");

編譯,加載,重新執(zhí)行我們的a.out:

[root@localhost test]# insmod ./fix_ex.ko[root@localhost test]# ./a.outopen: Success段錯誤[root@localhost test]# dmesg[ 8686.091738] 經(jīng)理!rush tighten beat electric discourse! SB 皮鞋[root@localhost test]#

發(fā)生了段錯誤,并且打印出了讓經(jīng)理趕緊打電話的句子。

其實,我的目的并不是這樣的,我真正的意思是,Linux的異常處理鏈表,又是一個藏污納垢的好地方,我們可以在上面的hook函數(shù)中藏一些代碼,比如說inline hook之類的,然后呢?然后靜悄悄地等待用戶態(tài)進程的bug導致異常處理被執(zhí)行。將代碼注入的時間線拉長,從而更難讓運維和經(jīng)理注意到。

讓代碼注入的時間點和模塊插入的時間點分開,讓事情更加混亂。不過,注意好隱藏模塊或者oneshot哦。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 模塊
    +關注

    關注

    7

    文章

    2837

    瀏覽量

    53295
  • Linux
    +關注

    關注

    88

    文章

    11761

    瀏覽量

    219054
  • 函數(shù)
    +關注

    關注

    3

    文章

    4417

    瀏覽量

    67524

原文標題:Linux內(nèi)核態(tài)缺頁會發(fā)生什么 - 玩轉Exception fixup表

文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    Linux內(nèi)核的“心跳”:jiffies如何為系統(tǒng)計時?

    Linux 內(nèi)核的世界里,有一個默默工作的 "計時器"——jiffies。它不像我們手機上的時鐘那樣顯示年月日,卻掌控著內(nèi)核中絕大多數(shù)時間相關的操作:從進程調度到設備驅動的定時檢查,都離不開它的身影。
    的頭像 發(fā)表于 02-04 16:27 ?826次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>的“心跳”:jiffies如何為系統(tǒng)計時?

    深入RK3588內(nèi)核:rockchip_linux_defconfig的作用與調試價值

    在 RK3588 芯片的 Linux 開發(fā)中,有一個文件始終是開發(fā)者繞不開的核心 ——kernel/arch/arm64/configs/rockchip_linux_defconfig。無論是首次
    的頭像 發(fā)表于 02-03 15:56 ?1168次閱讀
    深入RK3588<b class='flag-5'>內(nèi)核</b>:rockchip_<b class='flag-5'>linux</b>_defconfig的作用與調試價值

    Linux系統(tǒng)內(nèi)核參數(shù)調優(yōu)實戰(zhàn)指南

    Linux 內(nèi)核參數(shù)調優(yōu)是系統(tǒng)性能優(yōu)化的核心環(huán)節(jié)。隨著云原生架構的普及和硬件性能的飛速提升,默認的內(nèi)核參數(shù)配置往往無法充分發(fā)揮系統(tǒng)潛力。在高并發(fā) Web 服務、大數(shù)據(jù)處理、容器化部署等場景下,合理的
    的頭像 發(fā)表于 01-28 14:27 ?452次閱讀

    【「Linux 設備驅動開發(fā)(第 2 版)」閱讀體驗】+讀深入理解Linux內(nèi)核內(nèi)存分配

    時復用”,在fork()系統(tǒng)調用中廣泛使用;中斷上下文中發(fā)生缺頁中斷會導致雙重故障中斷,通常會使內(nèi)核崩潰等。經(jīng)過這段時間的閱讀,收獲頗豐,此書有不少關于內(nèi)核開發(fā)的新內(nèi)容值得本人深入學
    發(fā)表于 01-16 20:05

    【「Linux 設備驅動開發(fā)(第 2 版)」閱讀體驗】Linux內(nèi)核開發(fā)基礎

    感謝電子發(fā)燒友論壇提供的《Linux設備驅動開發(fā)(第2版)》閱讀機會,測評將從Linux內(nèi)核開發(fā)基礎、Linux內(nèi)核平臺抽象和設備驅動程序、
    發(fā)表于 01-12 22:45

    深入Linux內(nèi)核:進程調度的核心邏輯與實現(xiàn)細節(jié)

    ,背后都離不開內(nèi)核調度算法的精準操控。今天,我們就從優(yōu)先級、調度算法、時間片分配到底層實現(xiàn),全方位拆解Linux內(nèi)核進程調度的核心邏輯。 一、進程調度的“身份標識”:優(yōu)先級與分類 要理解調度邏輯,首先得搞懂:進程憑什么“插隊”?
    的頭像 發(fā)表于 12-24 07:05 ?4314次閱讀
    深入<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>:進程調度的核心邏輯與實現(xiàn)細節(jié)

    Linux內(nèi)核日志玩明白了嗎?printk調試神器全解析

    前言:做Linux驅動開發(fā)或內(nèi)核調試的朋友,一定對printk不陌生,但你真的會用它嗎?為什么同樣是調試RK3588內(nèi)核,別人能精準捕捉關鍵錯誤,你卻被海量日志淹沒?今天就帶大家吃透printk
    的頭像 發(fā)表于 12-19 08:32 ?870次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>日志玩明白了嗎?printk調試神器全解析

    基于 DR1M90 的 Linux-RT 內(nèi)核開發(fā):從編譯配置到 GPIO / 按鍵應用實現(xiàn)(1)

    本手冊由創(chuàng)龍科技研發(fā),針對 DR1M90,詳述 Linux-RT 實時內(nèi)核開發(fā):含實時性測試(LinuxLinux-RT 對比、CPU 空載 / 滿負荷 / 隔離狀態(tài)測試)、
    的頭像 發(fā)表于 12-02 10:38 ?1186次閱讀
    基于 DR1M90 的 <b class='flag-5'>Linux</b>-RT <b class='flag-5'>內(nèi)核</b>開發(fā):從編譯配置到 GPIO / 按鍵應用實現(xiàn)(1)

    Linux內(nèi)核模塊的加載機制

    Linux內(nèi)核模塊通常是.ko文件,也就是Kernel Object的縮寫。這些文件是ELF格式的,但和用戶空間的程序不同,它們包含的是特定于內(nèi)核的信息。比如,模塊的元數(shù)據(jù),像作者、許可證、描述等
    發(fā)表于 11-25 06:59

    Linux內(nèi)核printk日志級別全解析:從參數(shù)解讀到實操配置

    一、開篇:一個命令引出的核心問題 在?Linux?終端執(zhí)行?cat /proc/sys/kernel/printk,你可能會看到這樣的輸出: 這串數(shù)字不是隨機的,而是內(nèi)核日志系統(tǒng)的“核心配置開關
    的頭像 發(fā)表于 11-20 15:54 ?1707次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>printk日志級別全解析:從參數(shù)解讀到實操配置

    探索操作系統(tǒng)底層的關鍵接口

      在linux中,將程序的運行空間分為內(nèi)核空間與用戶空間(內(nèi)核態(tài)和用戶態(tài)),在邏輯上它們之間是相互隔離的,因此用戶程序不能訪問
    的頭像 發(fā)表于 11-08 12:42 ?749次閱讀

    deepin亮相2025中國Linux內(nèi)核開發(fā)者大會

    11 月 1 日,第二十屆中國 Linux 內(nèi)核開發(fā)者大會(CLK)在深圳舉辦。CLK 作為國內(nèi) Linux 內(nèi)核領域極具影響力的峰會,由清華大學、Intel、華為、阿里云、富士通南大
    的頭像 發(fā)表于 11-05 17:59 ?829次閱讀

    Linux內(nèi)核參數(shù)調優(yōu)方案

    在高并發(fā)微服務環(huán)境中,網(wǎng)絡性能往往成為K8s集群的瓶頸。本文將深入探討如何通過精細化的Linux內(nèi)核參數(shù)調優(yōu),讓你的K8s節(jié)點網(wǎng)絡性能提升30%以上。
    的頭像 發(fā)表于 08-06 17:50 ?959次閱讀

    如何配置和驗證Linux內(nèi)核參數(shù)

    Linux系統(tǒng)運維和性能優(yōu)化中,內(nèi)核參數(shù)(sysctl)的配置至關重要。合理的參數(shù)調整可以顯著提升網(wǎng)絡性能、系統(tǒng)穩(wěn)定性及資源利用率。然而,僅僅修改參數(shù)是不夠的,如何驗證這些參數(shù)是否生效同樣關鍵。
    的頭像 發(fā)表于 05-29 17:40 ?1162次閱讀

    樹莓派4 性能大比拼:標準Linux與實時Linux 4.19內(nèi)核的延遲測試

    引言本文是對我之前關于RaspberryPi3同一主題的帖子的更新。與之前的帖子一樣,我使用的是隨Raspbian鏡像提供的標準內(nèi)核,以及應用了RT補丁的相似內(nèi)核版本。對于實時版,我
    的頭像 發(fā)表于 03-25 09:39 ?818次閱讀
    樹莓派4 性能大比拼:標準<b class='flag-5'>Linux</b>與實時<b class='flag-5'>Linux</b> 4.19<b class='flag-5'>內(nèi)核</b>的延遲測試