日B视频 亚洲,啪啪啪网站一区二区,91色情精品久久,日日噜狠狠色综合久,超碰人妻少妇97在线,999青青视频,亚洲一区二卡,让本一区二区视频,日韩网站推荐

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

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

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

Linux內(nèi)核態(tài)缺頁會發(fā)生什么 - 玩轉(zhuǎn)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ā)生異常,跳轉(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ù)都是直接返回用戶一個錯誤碼,比如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)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 模塊
    +關(guān)注

    關(guān)注

    7

    文章

    2849

    瀏覽量

    53458
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11822

    瀏覽量

    219600
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4422

    瀏覽量

    67869

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

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

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

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    如何理解Linux內(nèi)核中的PCIe驅(qū)動

    我們習慣了用 Verilog 去死磕 PCIe 的底層協(xié)議狀態(tài)機。但一旦越過硬件邊界來到操作系統(tǒng)層面,Linux 內(nèi)核是如何接管并驅(qū)動這些 PCI/PCIe 設(shè)備的呢?由于不同的 CPU 架構(gòu)實現(xiàn)了
    的頭像 發(fā)表于 04-11 17:22 ?1289次閱讀

    Linux內(nèi)核驅(qū)動開發(fā)的技術(shù)核心精要

    嵌入式Linux驅(qū)動開發(fā)是連接硬件與操作系統(tǒng)的關(guān)鍵環(huán)節(jié)。隨著內(nèi)核演進(如Linux 6.13)和硬件復雜度提升,開發(fā)者需掌握并發(fā)控制、中斷分層、內(nèi)存管理、設(shè)備樹、調(diào)試工具等核心知識。本文提煉出驅(qū)動
    發(fā)表于 03-10 13:56

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    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)的“核心配置開關(guān)
    的頭像 發(fā)表于 11-20 15:54 ?2002次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)核</b>printk日志級別全解析:從參數(shù)解讀到實操配置

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

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

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

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

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

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

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

    Linux系統(tǒng)運維和性能優(yōu)化中,內(nèi)核參數(shù)(sysctl)的配置至關(guān)重要。合理的參數(shù)調(diào)整可以顯著提升網(wǎng)絡(luò)性能、系統(tǒng)穩(wěn)定性及資源利用率。然而,僅僅修改參數(shù)是不夠的,如何驗證這些參數(shù)是否生效同樣關(guān)鍵。
    的頭像 發(fā)表于 05-29 17:40 ?1401次閱讀
    丹东市| 札达县| 崇信县| 汝阳县| 儋州市| 宁明县| 濉溪县| 南陵县| 逊克县| 湖州市| 丹寨县| 本溪| 怀柔区| 高要市| 宽城| 紫云| 台北市| 北碚区| 麦盖提县| 林芝县| 双城市| 台东县| 洪泽县| 望江县| 桐柏县| 崇左市| 永平县| 进贤县| 九江市| 莫力| 襄城县| 湘潭市| 务川| 泽州县| 阜城县| 精河县| 潞西市| 邢台县| 闽侯县| 九龙城区| 无锡市|