Linux 内核添加自定义系统调用

网上的教程[1]大多使用老版本内核,许多内容已经不再适用了。本文依托于我的项目 mycall 进行讲解,旨在把自己踩过的坑全部记录下来,具体实现请参考源码。实验在 ubuntu 20.04 amd64 虚拟机(内核版本 5.15.0-105-generic)中进行,如有错误或建议(如不适用于 6.x 内核),欢迎在我的 Github Page repo 提 issue。 本文将先后介绍给内核添加自定义系统调用的两种方式: 通过内核模块将系统调用插入正在运行的内核中。 将系统调用添加到内核源码中,再重新编译安装内核。 通过内核模块添加系统调用 这个方法最简单但是坑也最多,因为内核开发组显然不希望我们通过内核模块修改/覆盖系统调用[2],并且做了诸多限制,为此我们只能用一些 trick。 定义系统调用 从 Linux 4.17 开始,x86 下系统调用服务例程只接收 struct pt_regs * 一个参数[9]。因此系统调用的定义为如下形式: 1 2 3 4 asmlinkage long sys_mycall(struct pt_regs *regs) { ... } 根据 Linux x86 calling convention,Linux 系统调用通过寄存器传递参数:rax 存储系统调用号,rdi 存储第一个参数, etc. pt_regs 就是一个包含了寄存器值的结构体[10],需要从中读取参数。 获取系统调用表地址 要插入系统调用,首先需要能够找到系统调用表的地址 sys_call_table。可惜 2.6 版本以后内核就不再 export sys_call_table 了[3],只能寻求其他办法: 从 System.map 读取 编译内核时生成的内核符号表中包含系统调用表的地址,可以通过以下命令获取: 1 cat /boot/System.map-$(uname -r) | grep sys_call_table 但是若内核开启了 KASLR (Kernel Address Space Layout Randomization),实际地址会和 System....

April 27, 2024 · 3 min · 501 words

虚拟地址空间:局部空间与全局空间 | 用户态与内核态

局部空间与全局空间 32 位机的虚拟地址位数为 32 位,每个任务都有自己独立的 4GB 虚拟地址空间。所谓独立,指的是不同任务相同的虚拟地址映射到不同的物理地址,本质上是依赖每个任务有自己的 PDT/PT。 这 4GB 虚拟地址空间又分为两部分:低端虚拟地址位于局部空间/用户空间、高端虚拟地址位于全局空间/内核空间。虚拟地址的高低端分界线依赖于操作系统的实现,如 Linux 的分界线位于 3GB 处,0 - 3GB 为低端虚拟地址,3GB - 4GB 为高端虚拟地址。 所有任务共享全局空间(所有任务的高端虚拟地址指向相同的内核页表),有各自的局部空间(LDTR 指向当前任务的 LDT,低端线性地址指向各自的页表)。 下图参考《x86 汇编语言 从实模式到保护模式》绘制,虚拟空间中 0 - 2GB 为局部空间,2 - 4GB 为全局空间,所有段均处于平坦模式。 用户态与内核态 特权级是处理器用来区分不同执行环境的一种机制。例如,在 x86 架构中,有四个特权级(Ring 0 到 Ring 3),其中 Ring 0(最高特权级)是内核态,操作系统内核在这里运行,拥有全部权限;Ring 3(最低特权级)是用户态,普通应用程序运行于此,权限受到限制。由固件负责实施特权级保护。 DPL:在描述符中指定,代表着一个段的特权级。 CPL:在 CS 段选择子中指定,代表着当前执行的代码段的特权级。 RPL:在段选择子中指定,代表请求者的特权级。 IOPL: 在 TSS 的 EFLAGS 中指定,代表着当前任务的输入输出特权级。 在绝大多数时候,请求者都是当前程序自己,因此 CPL = RPL。有时可能用户程序需要传入一个选择子作为参数,让内核例程代为访问,进入内核态后 CPL 变为 0,这时操作系统必须负责把这个选择子的 RPL 设置为用户程序自己的 CPL。 特权级在以下场景中发挥作用: 特权指令使用条件:CPL = 0。 访问数据段条件:CPL 和 RPL $\leq$ 目标 DPL。 访问代码段条件:除从高特权级例程返回外,不允许从高到低转移,因为操作系统不会引用可靠性比自己低的代码。一般来说,控制转移只允许发生在两个特权级相同的代码段之间(CPL 和 RPL = 目标 DPL);若目标代码段是依从的,可以从低到高,但转移后不允许改变 CPL(CPL 和 RPL $\geq$ 目标 DPL);还可以通过调用门从低到高(用 jmp far 不改变 CPL,用 call far 会把 CPL 提升到目标 DPL)。 访问调用门条件:目标 DPL $\leq$ CPL 和 RPL $\leq$ 调用门描述符 DPL。 态 !...

September 9, 2022 · 1 min · 206 words