我设法做objcopy来查看和提取.rodata段内容作为不可变完整性检查的引用,但是,我意识到内核驱动程序无法读取文件。从这个意义上讲,我们如何编写驱动程序来确定它在运行时的自身完整性?
制作一些插图的示例代码会很好。
答案 0 :(得分:5)
您可以使用加密签名的模块在运行时验证内核模块的完整性。
从this Unix and Linux Stack Exchange answer开始。
Here是Jake Edge关于截至2011年主线内核加密签名状态的更新。补丁最终迁移到mainline in 3.7。
模块签名是最近内核中的配置选项。您可以在使用menuconfig
配置内核时进行设置:“启用可加载模块支持” - >“模块签名验证”。
答案 1 :(得分:1)
另一种看法。
内核设备驱动程序只能由root加载。因此,二进制图像可以放置在只有root可以访问的某个地方。安装后,驱动程序和单独的检查程序应用程序都可以放在此目录中。此时,除非由root完成,否则磁盘上的代码不能更改(硬件错误和恶意软件除外)。
如果某人拥有root密码,那么他们可以做任何事情,因此请确保您的系统已正确锁定,整个完整性问题就会消失。
您甚至可以在每次启动时运行CRC校验程序以验证驱动程序文件的内容(尽管驱动程序已经加载),可以记录有关驱动程序完整性的消息。
答案 2 :(得分:1)
我的建议是使用不同的软件进行检查。被恶意篡改的驱动程序可能会运行静默,所以如果您希望检查只在每个驱动程序内完成,那么您将无法通过其内部检查告知流氓驱动程序。
为了避免这种情况,最好有一个与外界没有联系的主监督恶魔,他的工作只是检查所有的司机。如果你仍然担心主检查员可能被劫持,那就让3个偏执的机器人看到彼此的完整性。
驱动程序将有一个界面与监督软件交换定期握手,或者他们可以将一部分内存暴露给主管(只读访问),然后可以在后台执行偏执检查,而无需驱动程序甚至需要浪费时间在通信协议中。
根据我对您的问题的理解,您计划使用静态数据作为检查完整性的方法。在那种情况下,主检查器将拥有所述.rodata的副本和指向驱动程序内存的指针,并执行定期CRC或任何检查代码计算,以确保驱动程序未被篡改。
编辑:我不是精通Linux驱动程序,但伪代码看起来像这样:1)(重新)构建驱动程序时的初步工作
将驱动程序的相关检查数据(例如.rodata的内容)保存在只能由主管访问的特定位置
2)每个驱动程序内部
在加载时与主管进行一次通信,以提供指向.rodata的用户空间只读指针
3)主管
连续读取每个驱动程序的.rodata(每隔几秒一次),并将它们与相应的文件进行匹配。
简单的CRC可能足够代替整个.rodata副本,但使用.rodata作为一个整体将允许更改完整性检查机制,而无需触及现有的驱动程序。
编辑(之二):获取.rodata的地址可以通过一个简单的方法完成,就像在区域的开头定义一个静态变量一样简单。我不是ELF专家,但我想一些编译器和链接器指令应该可以解决这个问题:
通过在运行时获取此虚拟对象的地址,我们在驱动程序执行上下文中加载了.rodata的起始地址。
同样的技巧可以与位于.rodata
之后的另一个假人一起使用,以获得该部分的大小
这将允许确定将为主管提供的用户空间映射区域的大小。
通过使用mmap,您可以将驱动程序内存的某些部分映射到用户空间。
查看示例here
定义映射后,您可以使用IOCTL将其传递给主管。
如果你想要一个额外的安全层,IOCTL可以包含密码交换,这样恶意软件就无法轻松读取.rodata(虽然我想知道这样的软件是如何在你的中间运行的内核没有你明确地把它放在那里)。
这里的诀窍是驱动程序本身永远不需要读取文件。