如何写入Linux内核中的受保护页面?

2023-12-10

我正在尝试在模块中添加系统调用。我的理由是:

  1. 这是一个研究项目,因此具体实施并不重要。
  2. 在内核中添加系统调用需要非常长的时间来重新编译。我可以用扩展的系统调用表进行一次编译,但不是每次都如此。即使使用增量编译,链接和归档最终的二进制文件也需要很长时间。
  3. 由于该项目对时间敏感,因此使用kprobes拦截系统调用处理程序会减慢系统调用处理程序的速度。

我仍然对添加系统调用的其他方法持开放态度,但由于上述原因,我认为写入sys_call_table在模块中是做我想做的事情的最干净的方法。

我已经从系统调用表的地址System.map,禁用了 kaslr,我正在尝试清除页面保护,但某些写保护仍然阻碍我。

// following https://web.iiit.ac.in/~arjun.nath/random_notes/modifying_sys_call.html

// clear cr0 write protection
write_cr0 (read_cr0 () & (~ 0x10000));

// clear page write protection
sys_call_table_page = virt_to_page(&sys_call_table[__NR_execves]);
set_pages_rw(sys_call_table_page, 1);

// do write
sys_call_table[__NR_execves] = sys_execves;

但是,我仍然收到权限错误,但我不知道它的执行机制:

[   11.145647] ------------[ cut here ]------------
[   11.148893] CR0 WP bit went missing!?
[   11.151539] WARNING: CPU: 0 PID: 749 at arch/x86/kernel/cpu/common.c:386 native_write_cr0+0x3e/0x70
...
Here was a call trace pointing to the write of sys_call_table
...
[   11.332825] ---[ end trace c20c95651874c08b ]---
[   11.336056] CPA  protect  Rodata RO: 0xffff888002804000 - 0xffff888002804fff PFN 2804 req 8000000000000063 prevent 0000000000000002
[   11.343934] CPA  protect  Rodata RO: 0xffffffff82804000 - 0xffffffff82804fff PFN 2804 req 8000000000000163 prevent 0000000000000002
[   11.351720] BUG: unable to handle page fault for address: ffffffff828040e0
[   11.356418] #PF: supervisor write access in kernel mode
[   11.359908] #PF: error_code(0x0003) - permissions violation
[   11.363665] PGD 3010067 P4D 3010067 PUD 3011063 PMD 31e29063 PTE 8000000002804161
[   11.368701] Oops: 0003 [#1] SMP KASAN PTI

完整的消息

关于如何禁用它有什么猜测吗?


有一种方法不需要重新编译内核。由于内核会检测wp位是否被修改write_cr0,您可以提供自定义函数来绕过它。

inline void mywrite_cr0(unsigned long cr0) {
  asm volatile("mov %0,%%cr0" : "+r"(cr0), "+m"(__force_order));
}

这是启用/禁用写保护的功能。我们用mywrite_cr0代替write_cr0

void enable_write_protection(void) {
  unsigned long cr0 = read_cr0();
  set_bit(16, &cr0);
  mywrite_cr0(cr0);
}

void disable_write_protection(void) {
  unsigned long cr0 = read_cr0();
  clear_bit(16, &cr0);
  mywrite_cr0(cr0);
}

In your mod_init功能,你可以使用kallsyms_lookup_name("sys_call_table")找出地址sys_call_table在运行时,而不是编译时。幸运的是,我们现在可以直接写入sys_call_table不处理 pageattr。

下面的代码在Linux Kernel 5.1.4上测试

inline void mywrite_cr0(unsigned long cr0) {
  asm volatile("mov %0,%%cr0" : "+r"(cr0), "+m"(__force_order));
}

void enable_write_protection(void) {
  unsigned long cr0 = read_cr0();
  set_bit(16, &cr0);
  mywrite_cr0(cr0);
}

void disable_write_protection(void) {
  unsigned long cr0 = read_cr0();
  clear_bit(16, &cr0);
  mywrite_cr0(cr0);
}

static struct {
  void **sys_call_table;
  void *orig_fn;
} tinfo;

static int __init mod_init(void) {
  printk(KERN_INFO "Init syscall hook\n");
  tinfo.sys_call_table = (void **)kallsyms_lookup_name("sys_call_table");
  tinfo.orig_fn = tinfo.sys_call_table[your_syscall_num];
  disable_write_protection();
  // modify sys_call_table directly
  tinfo.sys_call_table[your_syscall_num] = sys_yourcall;
  enable_write_protection();
  return 0;
}

static void __exit mod_cleanup(void) {
  printk(KERN_INFO "Cleaning up syscall hook.\n");
  // backup syscall
  disable_write_protection();
  tinfo.sys_call_table[your_syscall_num] = tinfo.orig_fn;
  enable_write_protection();
  printk(KERN_INFO "Cleaned up syscall hook.\n");
}

module_init(mod_init);
module_exit(mod_cleanup);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何写入Linux内核中的受保护页面? 的相关文章

  • 内存地址是否指向一个字节的信息?

    以下是 DTS 文件的摘录 linux arch powerpc boot dts 板名 dts memory device type memory reg lt 0x00000000 0x40000000 gt 1GB at 0 嵌入式设
  • UIScrollView 滚动时捕捉到位置

    我正在尝试实现一个捕捉到点的滚动视图滚动时 我在这里看到的所有帖子都是关于在用户结束拖动滚动条 之后 捕捉到某个点的 我想让它在拖动过程中折断 到目前为止 我已经用它来停止拖动后的惯性 并且效果很好 func scrollViewWillE
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • 从内核空间中的块设备读取

    我正在编写一个内核模块 需要从现有的块设备执行读取 dev 东西 有谁知道有任何其他模块可以执行这些操作 我可以用作参考吗 欢迎任何指点 Linux 2 6 30 如果你真的绝对必须那么使用filp open filp close vfs
  • 大会,你好世界问题

    我正在 Linux 上学习 asm noobuntu 10 04 我得到了以下代码 http asm sourceforge net intro hello html http asm sourceforge net intro hello
  • Linux 中热插拔设备时检测设备是否存在

    我正在运行 SPIcode http lxr free electrons com source drivers spi spi omap2 mcspi c在熊猫板上 我想知道其中的哪个功能code http lxr free electr
  • 在Linux中断上下文中运行用户线程

    我正在编写一些定制的应用程序 并允许更改 Linux 内核中的中断处理程序代码 我有一个用户线程正在等待中断发生 如果发生中断 那么我要做的第一件事就是执行该用户线程 有什么办法让它发挥作用吗 Thanks 创建一个字符设备 这就是内核所做
  • 树莓派的设备树驱动内核

    我想用设备树驱动的 Linux 内核启动树莓派 有什么特别的事情要做吗 谁能指出为树莓派设置基于设备树的内核启动需要什么 我可能需要有树莓派内核源代码 其中设备驱动程序应与设备树兼容 如果是这样 我在哪里可以找到 Raspberry Pi
  • UNIX系统调用监视器

    如何监控进程的系统调用 Check strace http linux die net man 1 strace 在最简单的情况下 strace 运行指定的命令直到退出 它拦截并记录进程调用的系统调用以及进程接收的信号 每个系统调用的名称
  • Linux内核container_of宏和C90中的通用容器

    是否有可能实施容器的 http lxr linux no linux tools perf util include linux kernel h L18纯C90中的宏 我不确定如何做到这一点 因为内核实现取决于海湾合作委员会黑客 http
  • .ko 文件是如何构建的

    我正在尝试将我自己的驱动程序移植到Beagle 板 xm arm cortex A8 在移植时我试图弄清楚如何 ko文件实际构建 在我们的Makefile我们只有一个命令来构建 o file 怎样是一个 ko文件已建立 使用Linux 2
  • 内核模块未加载(但 insmod 返回 0)

    我必须向现有设备 mips arch 添加一些功能 我已经尝试了几个 SDK 目前我取得了一些进展 但是 insmod 返回 0 成功 并且 lsmod 显示它们 但是 printk 和 create proc entry 都不起作用 但我
  • ARM 的内核 Oops 页面错误错误代码

    Oops 之后的错误代码给出了有关 ARM EX 中的恐慌的信息 Oops 17 1 PREEMPT SMP在这种情况下 17 给出了信息 在 x86 中它代表 bit 0 0 no page found 1 protection faul
  • 民意调查立即从驱动程序中退出

    这是我第一次在 Linux 内核中实现驱动程序并面临这个问题 我正在尝试在我的字符驱动程序中实现 poll 我已调用 poll wait 并传递了一个等待队列 当从用户空间程序打开该驱动程序的设备文件并在此设备文件描述符 fd 上调用 po
  • 已编译 LKM 的互换性

    是否可以使用可加载内核模块 编译为3 0 8 mod unload ARMv5 我自制的内核 在具有版本的内核中3 0 31 gd5a18e0 SMP preempt mod unload ARMv7 安卓股票内核 该模块本身几乎不包含任何
  • 在内核中创建一个简单的只写过程条目

    include
  • __NR_gettid 和 SYS_gettid 之间的区别

    我只是在寻找在 Linux 中获取唯一线程 ID 的方法 我发现的方法是将两个参数中的任何一个作为参数进行系统调用 NR gettid OR SYS gettid 有人能解释一下它们之间有何不同吗 Nothing in
  • linux新手关于嵌入式linux设备驱动的问题

    最近在研究linux驱动 正如我读过的那些文章所说 设备驱动程序模块很可能会根据内核的需要自动加载 因此我想知道内核如何确定为特定设备 声卡 I2C spi 设备 等 我也无法彻底想象内核如何在启动时检测每个硬件设备 与嵌入式linux相关
  • 找出Linux上一个进程使用了​​多少内存页

    我需要找出进程分配了多少内存页 每个页面是 4096 进程内存使用情况我在查找正确值时遇到一些问题 当我查看 gome system monitor 时 内存映射下有几个值可供选择 Thanks 这样做的目的是将内存使用量除以页数并验证页大
  • Linux 内核使用的设备树文件 (dtb) 可视化工具? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个可以图形化表示Linux内核中使用的硬件设备树的工具 我正在尝试了解特定 Arm 芯片组

随机推荐