用于内核测试的内核模块

背景 在调试内核时,最常用的方式就是添加打印。这个方法简单直接,但有个问题:若添加打印的函数会被频繁地调用执行,那这很可能使系统在启动或运行阶段触发海量的打印,反而将关键的信息淹没;或者由此导致系统运行卡顿甚至无法启动。 还有另一种常见的调试需求:我们需要在内核中模拟某种故障,并且是以我们所能掌控的时机和方式来触发。关于这点我们一般会想到内核故障注入,但其手段和所涉及的软件工具比较复杂,且其所能模拟的故障种类和故障位置一般是给定的,无法随意调整。 对于上述两个场景,我们其实可以用同一个方法解决:在内核中预埋一个“开关”,并在内核的用户态接口(如 proc 文件系统)上创建一个专门的接口来控制这个开关。对于第一个场景,我们可以将那些打 …

Spinlock 代码及故障模型分析

代码流程 spinlock 上锁的代码流程: 1# include/linux/spinlock.h 2spin_lock 3 raw_spin_lock 4 # ifdef CONFIG_INLINE_SPIN_LOCK 5 # include/linux/spinlock_api_smp.h 6 # else 7 # kernel/locking/spinlock.c 8 _raw_spin_lock 9 # include/linux/spinlock_api_smp.h 10 __raw_spin_lock 11 preempt_disable() 12 spin_acquire(...) 可见,上锁时 spinlock 是 …

Linux 脚本执行:由一个补丁分析说起

事情背景 补丁链接:a4ae32c71fe9 (“exec: Always set cap_ambient in cap_bprm_set_creds”) 补丁信息中提到,该补丁是为了确保 cap_bprm_set_creds() 每次都会设置 cap_ambient 变量。另外还提到了下述内容: … if there is a suid or sgid script with an interpreter that has neither the suid nor the sgid bits set the interpreter should be able to accept …

进程切换与抢占

进程切换 概念 进程切换,又称上下文切换,分为 自愿(voluntary)切换:进程本身无法继续运行 例如需要等待 IO 完成(TASK_UNINTERRUPTABLE),或等待某个资源或事件的就绪(TASK_INTERRUPTIBLE),或正在被 debug/trace(TASK_STOPPED/TASK_TRACED) 强制(involuntary)切换:进程还可以运行,但内核不让它运行了 例如进程时间片用尽,或有优先级更高的其他进程 又例如进程自己决定主动让出 CPU(注意:这不属于自愿切换,因为进程仍处于 TASK_RUNNING 状态) 用户态程序通过 sched_yield …

关于一个神奇的 Linux 目录权限问题的探究

TL;DR su 与单纯的 set{u,g}id 不一样:前者会通过 setgroups 系统调用来设置进程的 Supplementary Group1;而后者不会,只会修改进程的 {,s,e,fs}{u,g}id。 Supplementary Group 在内核中体现为 struct cred 下的 group_info,本质上是一个长度不固定的 gid 数组(类似 C++ 中的 string_view) 通过内核代码(init_cred 和 init_groups)确认,内核不会为进程添加 Supplementary Group;且 /etc/group 中也没有对应的条目,但 root 用户进程的 Supplementary …