本周在Hubris中发现一个巧妙的 bug,最初代码正确但因其他变化而变成 bug。
什么是 Hubris?
Hubris 是为深度嵌入式系统设计的操作系统,用于处理 Oxide Rack 中“大”处理器的启动任务,相关背景可阅读参考手册或介绍它的演示文稿。
犯罪现场
同事 Arjen Roodselaar 测试网络交换机固件的电源序列和时钟配置更改时,交换机无法开机,部分固件能响应但电源序列器似乎死机,可能是电源序列混乱导致硬件损坏,这是个谜。
从有限内存中挤出更多
在使用 Hubris 的相对便宜的微控制器中,RAM 和闪存有限,Hubris 因由多个单独编译的任务组成,资源需求比其他系统高,同事 Matt Keeter 让系统更智能地利用内存,回收了 30%的 RAM。
确凿证据
Arjen 用 Hubris 的调试器 Humility 检查,发现负责电源序列的sequencer
任务状态异常,多次重启,每次启动时都会出错,涉及 Hubris IPC 中重要方面。
在 Hubris IPC 中跨任务扩展 Rust 借用
Hubris 任务通过 IPC 消息通信,任务可借内存给其他任务,这利用了 Rust 的资源所有权模型,但如果实现错误会是安全漏洞,尝试借未拥有的内存是被禁止的,内核会记录触发事件信息。
特性攻击时
内存违规的地址0x801bffd
在处理器闪存的一个特殊边界下,且属于同一任务,这是因为内存访问权限检查代码假设借的内存能 fit 进一个区域,而 Matt 的任务打包更改使这假设过时。
两个无辜特性如何合谋杀死网络交换机
构建系统中的任务打包是机会性的,会在任务的闪存和 RAM 区域中间引入区域边界,一个任务的大小变化可能会移动另一个无关任务的 MPU 区域边界,导致随机崩溃,Matt 关闭了构建系统中的任务打包功能。
电话来自屋内!
内核因错误的内存保护算法而杀死任务,需要改变算法,新算法更复杂,已被提取到更可单元测试的 crate 中,开启任务打包功能也不会有问题,从发现网络交换机故障到修复内核 bug 大约三小时。
Hubris 失败的情况
从网络交换机无法用新固件开机,到两位相距 3000 英里的工程师分别分析故障快照并修复内核 bug,过程中体现了故障隔离(部分系统崩溃不影响其他部分)、向安全方向失败(内核内存访问检查 bug 无安全影响)、更安全的共享内存(IPC 机制使共享内存更安全)、内核调试器代码签名(方便定位崩溃代码)、固件崩溃转储很棒(能获取崩溃转储)、设计和实现的简单性(代码量少便于查找问题)以及团队紧密的非层次化集成(团队成员能快速解决问题)等。
总之,这个故事展示了 Hubris 系统在面对问题时的一些特点和优势,也强调了团队合作和简单设计的重要性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。