之前在学习内核的时候,清楚时钟中断的重要性,但所参考的书籍貌似都不大重视这一个,所以也就没有好好研究一下。今天想好好研究一下的缘由在于毕业论文所参考的一篇论文涉及到了时钟中断服务程序 do_timer。这篇文章名叫 OS support for detecting Trojan circuit attacks
,作者是 Gedare Bloom、Bhagirath Narahar 和 Rahul Simha。
下边我们就先来看看这篇文章所涉及到的时钟中断部分。
引子:硬件木马实时检测
硬件木马研究是我个人的硕士毕业论文方向。硬件木马跟软件木马类似,是指对电子电路或设计的恶意修改,从而导致电子设备的异常运行。鉴于硬件木马对集成电路所造成的巨大威胁,我们需要对其进行检测或者防御。而文章 OS support for detecting Trojan circuit attacks
所涉及的就是对硬件木马的实时(Run-time)检测。其中,跟时钟中断相关的是针对拒绝服务攻击
(Denial of Service, DoS)的实时监测。
拒绝服务攻击具体指的是对 CPU(Central Processing Unit)的攻击。为了检测这种攻击,作者提出了如下图所示的系统架构。作者假定操作系统和管家电路(Guard)是可信的。其中,作者使用的操作系统是 Linux,每 1ms 就会发生一次时钟中断,且该中断服务程序是与平台无关的 do_timer 函数。作者通过修改该函数,在每一个时钟中断发生时向该管家电路发送一个心跳(Liveness)。另外,管家电路的时钟,会在系统发生时钟中断时,与 CPU 的时钟同步。当管家电路在收到操作系统发给它的心跳后,会设置其看门狗定时器的值为一个随机值,开始倒数。
当 CPU 被硬件木马攻击而导致挂起(也即拒绝服务)时,CPU 不再响应系统时钟中断,意味着管家电路的时钟不会被同步,也意味着看门狗定时器的值也不会被重置。这样,当看门狗定时器值递减为 0 时,管家电路就认为CPU没有正常工作、遭受了拒绝服务攻击,这时管家电路可以对 CPU 进行复位或者告诉用户。
注
另外,这篇文章还针对权限提升攻击
提出了具体的检测方案。因为该方案设计到内核,所以暂将该方案写到该博文中,虽然它跟本文主题毫无关系。
权限提升攻击需要软硬件协同。首先,硬件木马被恶意软件触发,关闭系统的内存保护(Memory protect, MP)。没有内存保护,所有进程都可以访问内存的任何地方。接着,如下图所示,恶意软件访问操作系统的进程链表,并搜索该链表,找到该软件对应的进程控制块(Process control block, PCB),将其有效用户 ID(Effective user ID, euid)改为0,也即将其权限提升至跟超级用户一样,这样该软件就可以像超级用户一样为所欲为了。
上述恶意软件攻击过程可用类似C语言伪代码表示如下:
1 | // 代码段:攻击伪代码 |
针对该攻击,作者提出在硬件和操作系统 Linux 之间再加一层内核层 Xenomai 实时框架,如下图所示。Xenomai 只是拓展了 Linux 内核,算是 Linux 内核的一部分。Xenomai 能够提供实时进程调度。当没有实时进程(Real-time task)的时候,Xenomai 触发 Linux 内核的进程调度模块;反之则使用 Xenomai 的实时进程调度模块。
Xneomai 对 Linux 的扩展
作者通过新建一个实时进程,来实现对内存保护标志位的检查。作者经过测试,扫描一次进程链表所需时间在 15~20 微秒,所以将实时进程被调度的时间周期定为 15 微秒。如下图所示,每过 15 微秒,该实时进程就对内存保护标志位进行检查,确保系统安全;当该进程被挂起时,Xenomai 触发 Linux 内核的进程调度模块,由 Linux 内核对进程进行调度。
Xenomai实时进程调度。其中,浅蓝色的代表的是实时进程,深绿色代表的是常规的Linux进程调度时间
时钟中断
时钟中断是 Linux 内核工作的脉搏,是进程调度的基础。
时钟中断设置
时钟中断是由计数器 8254 间隔定时产生的。在 Linux 0.11 中,该定时器被设置为每个 10ms 产生一次时钟中断,具体代码如下:
1 | // kenel/sched.c ------------------------------- |
8254 计数器总共有 6 个工作方式。在 Linux 0.11 中,该计数器被设置为工作在方式 2 —— 频率发生器(Rate Generator)
:
该方式的功能类似于一个 N 分频器。通常用于产生一个实时时钟中断。初始状态下 OUT(计数器输出) 为高电平。当计数值递减为 1 时,OUT 变为低电平后再变为高电平。间隔时间为一个 CLK 脉冲宽度。此时计数器会重新加载初始值并重复上述过程。因此,对于初始计数值为 N 的情况,会在每 N 个时钟脉冲时输出一个低电平脉冲信号。在这种方式下 GATE(计数器的门控制输入端) 可控制计数的暂停和继续。当 GATE 变高时会让计数器重新加载初始值并开始重新计数。
关于 8254 详细信息请参考《Linux 内核完全注释》(修正版 V3.0)第 8.7 节。
另外,时钟中断处理程序如下:
1 | // kenel/system_call.s ------------------------- |
其中,do_timer 是时钟中断服务程序。
时钟中断服务程序 do_timer
do_timer 定义如下:
1 | // kenel/sched.c ------------------------------- |