Pitfalls in VM Implementation on CHERI: Lessons from Porting CRuby

本文以 CRuby 移植为例,系统梳理并分类了将虚拟机移植到 CHERI 架构时因 C 语言未定义行为假设与 CHERI 严格内存安全模型冲突而引发的各类实现陷阱,并提供了相应的解决方案与验证。

Hanhaotian Liu (University of Tokyo, Japan), Tetsuro Yamazaki (University of Tokyo, Japan), Tomoharu Ugawa (University of Tokyo, Japan)

发布于 Mon, 09 Ma
📖 1 分钟阅读☕ 轻松阅读

Each language version is independently generated for its own context, not a direct translation.

这篇论文讲述了一个关于**“给旧房子装上新式防盗门”**的故事。

想象一下,传统的计算机程序(比如 Ruby 语言的解释器)就像是在一个老式公寓楼里运行。在这个老楼里,每个人手里都拿着一把普通的钥匙(传统指针)。这把钥匙只能告诉你“去哪个房间”,但它不管这个房间是不是你的,也不管你能不能进隔壁的房间。如果坏人拿到了钥匙,或者你手滑把钥匙插错了锁孔,整个大楼(内存)就可能被破坏,甚至被黑客入侵。

CHERI 就是这项新技术,它给大楼换了一套智能防盗系统。在这个新系统里,钥匙不再是简单的数字,而是一张**“智能通行证”**(Capability)。这张通行证上不仅写着“去哪个房间”,还写着:

  1. 权限:你只能进这个房间,不能进隔壁。
  2. 范围:你只能在这个房间里的这面墙到那面墙之间活动,不能乱跑。
  3. 防伪:这张通行证是硬件生成的,无法伪造。

这篇论文的核心故事是:
作者们试图把著名的 CRuby(Ruby 语言的虚拟机,就像公寓楼的中央管理系统)搬进这个新大楼(CHERI 架构)。虽然初衷很好,但在搬家过程中,他们发现了很多**“水土不服”**的坑。

为什么搬家这么难?(核心冲突)

在老公寓(传统架构)里,管理员(程序员)有一些**“潜规则”“坏习惯”**,大家心照不宣地认为这些是安全的。但在智能大楼(CHERI)里,这些习惯不仅行不通,还会直接触发警报,导致系统崩溃。

作者把这些问题总结成了几个有趣的**“搬家陷阱”**:

1. “借钥匙”的陷阱(Invalid Derived Pointer)

  • 老习惯:在老楼里,管理员拿着一把“总钥匙”(指向栈顶的指针),然后随便算个偏移量,就能得到一把“临时钥匙”去检查下面的房间。大家默认这把总钥匙能打开整层楼。
  • 新现实:在 CHERI 大楼里,这把“总钥匙”被严格限制了,它只能打开当前这一个房间(局部变量)。当你试图用它去开隔壁房间(栈扫描)时,智能系统会立刻报警:“嘿,你越界了!”
  • 解决办法:管理员必须手里一直握着一把**“超级通行证”**(覆盖整个栈的宽范围能力),用它来生成新的临时钥匙,而不是用那个被限制的死钥匙。

2. “假钥匙”的陷阱(Dereferencing Ambiguous Pointers)

  • 老习惯:垃圾回收系统(GC)就像大楼的清洁工。在老楼里,清洁工看到地上有个数字,如果它长得像一把钥匙(比如数字 0x1234),清洁工就盲目地认为它是一把钥匙,并试着去开门。如果那其实只是个数字(比如温度 0x1234),门打不开也没事,系统会忽略。
  • 新现实:在 CHERI 大楼里,如果清洁工拿着一把没有“防伪标签”的假钥匙去开门,警报会直接拉响,大楼会锁死。
  • 解决办法:清洁工必须学会**“验明正身”**。在尝试开门前,先检查这张纸有没有防伪标签(Validity Tag)。如果有,再开;如果没有,就当它是废纸,直接扔掉。这反而让清洁工作得更精准了。

3. “原地扩建”的陷阱(In-Place Reallocation)

  • 老习惯:想象你在租一个房间,房东说:“如果你要扩建,我就把隔壁房间打通给你,你不用换钥匙,原来的钥匙还能用。”在老楼里,这很常见。
  • 新现实:在 CHERI 大楼,如果你扩建了房间,原来的“通行证”范围就不够了。系统会给你一张新通行证,范围更大。如果你还拿着旧钥匙去新扩建的区域,系统会报警:“你越界了!”
  • 解决办法:以后扩建时,必须立刻扔掉旧钥匙,换上新钥匙。不能指望旧钥匙还能用。

4. “乱填格子”的陷阱(Using Padding Bits)

  • 老习惯:程序员喜欢把很多小信息塞进一个大盒子里(比如把几个小数字塞进一个 64 位的整数里)。在老楼里,盒子的所有格子都能用。
  • 新现实:在 CHERI 的盒子里,上半部分的格子被用来贴“防伪标签”和“权限说明”,只有下半部分能用来装数据。如果你试图往上半部分塞数据,或者把整个盒子当成纯数字来移位操作,数据就会乱套,或者被系统忽略。
  • 解决办法:以后只使用**“纯数据盒子”**(精确宽度的整数类型,如 uint64_t),别碰那些带“防伪标签”的盒子。

5. “修改封条”的陷阱(Modifying Temporary Capabilities)

  • 老习惯:有些钥匙上贴着“封条”(Sealed),表示这是系统生成的,不能动。但在老楼里,大家习惯性地拿笔在封条上涂涂改改(做数学运算),只要结果对就行。
  • 新现实:在 CHERI 大楼,封条是硬化的。你一旦试图修改它,系统会直接判定你破坏公物,把钥匙作废。
  • 解决办法:想修改数据?先把封条撕下来(转换成普通数字),改完再重新封上(如果需要)。或者干脆别碰那些带封条的东西。

6. “算错距离”的陷阱(Pointer Arithmetic on Non-Capability Type)

  • 老习惯:计算距离时,大家习惯把钥匙变成数字,加减一下,再变回钥匙。
  • 新现实:如果你用错了“数字类型”(比如用了 size_t 而不是专门的 uintptr_t),变回来的钥匙就会失去防伪标签,变成一把废钥匙。
  • 解决办法:一定要用专用的“钥匙转换器”uintptr_t),确保变回来的钥匙还是有效的。

搬家的结果如何?

作者们成功地把 CRuby 搬进了 CHERI 大楼。

  • 性能:虽然为了遵守新规则,系统稍微慢了一点点(大约慢了 2%),但在大多数情况下,速度几乎和原来一样快。
  • 安全性:虽然还没完全发挥 CHERI 的极限(比如还没给每个对象都设最严格的界限),但已经堵住了很多传统架构下的安全隐患。

总结

这篇论文就像是一份**“智能大楼搬家避坑指南”**。它告诉未来的程序员:

如果你想把软件搬到 CHERI 这个更安全的平台上,千万别再用那些“老派”的编程技巧了。那些在旧系统里能“蒙混过关”的 undefined behavior(未定义行为),在新系统里就是致命错误

只有彻底改变思维,尊重硬件的“智能通行证”规则,才能构建出真正安全的软件系统。