瓦尼什如何遇到切里1/N

我应该事先警告你,罗伯特·沃森是我几十年的朋友,所以我绝不是一个中立的观察者。

但罗伯特是我认识的最聪明的人之一,当他第一次解释他关于硬件能力的想法时,第二天早上,我把我所有的股票都卖了。

罗伯茨的想法后来变成了切里,如果你还没有听说过,你现在应该读一读它:

https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/

Cheri的核心思想是指针不是整数,这意味着您不能再随机编造或修改指针来指向随机事物,无论您的意图是什么。

从安全的角度来看,这限制了几大类常用的攻击载体,微软研究发现,Cheri在2019年阻止了他们看到的所有漏洞的整整43%:

https://msrc-blog.microsoft.com/2022/01/20/an_armful_of_cheris/

(是的,我们可以在你出售所有切片面包的股份时暂停。)

我一直在热切地等待,看看我自己的Varnish HTTP缓存软件在Cheri的领导下会有什么表现,因为我使用Varnish软件的目标之一是将质量刻度盘调到11,看看它在现实生活中是否会有所不同。

罗伯特亲切地借给了我一个关于他的一台闪亮的新Morello机器的空壳账户,这台机器配备了一台带有Cheri功能的ARM64原型CPU。

在这一系列咆哮中,我将唱一首《瓦尼什如何遇见切丽》的传奇--恰好是这样。

我的希望是,它将激励和帮助其他软件项目尝试Cheri,并帮助说服ARM,“Morello”应该成为ARM架构的永久组成部分。

一层非常薄的Varnish

对于那些不熟悉Varnish的人,您需要知道:

  • Varnish是一个连接到HTTP网络服务器的加力缓存,它是用C编写的,大约有100KLOC。

  • 世界上大约20%的网络流量通过Varnish实例。

  • 您使用一种名为VCL的特定于域的编程语言来配置Varnish,该语言将被转换为C源代码,编译为一个共享库,dlopen(3)‘ed并执行。

  • Varnish作为两个进程运行,一个“管理器”和一个“子进程”。子进程不会 exec(2)fork(2)

  • 源代码是以一种非常偏执的风格编写的,大约10%的所有行都是断言,除此之外还有其他几层偏执,例如,我们总是检查 close(2) 返回零。

  • 我们有900多个测试用例,它们执行了90%以上的源代码行。

  • 在过去的16年里,我们只听到了一句“哦,该死!”安全问题。

我仍然讨厌AutoCrap工具

AutoCrap是对黑客攻击的一种攻击,它确实破坏了软件的可移植性,但它是“行业标准”,所以我们也对Varnish使用它,无论我有多讨厌它。

请参阅:https://dl.acm.org/doi/abs/10.1145/2346916.2349257

因为很多软件不能在Cheri模式下工作,所以CheriBSD有两种包:常规的和Cheri的。

请参阅:https://ctsrd-cheri.github.io/cheribsd-getting-started/packages/index.html

AutoCrap不会发现一些程序包最终会在 /usr/local 还有一些是在 /usr/local64 ,所以我要做的第一件事就是解释一下:

export LIBTOOLIZE=/usr/local64/bin/libtoolize
export PCRE2_LIBS=`/usr/local/bin/pcre2-config --libs8`
export PCRE2_CFLAGS=`/usr/local/bin/pcre2-config --cflags`
${SRCDIR}/configure \
        [the usual options]

你不能和切丽一起做的事情

很久很久以前,我为Varnish编写了一个“持久化存储”模块,为了不重写太多剩余的源代码,架构以文件结束 mmap(2) ‘指向一致的地址,包含带有指针的数据结构。

内存空间布局随机化作为缓冲区溢出的创可贴(不要让我开始!)的出现,使该体系结构无法工作,近十年来,这种“装卸工”一直被命名为 deprecated_persistent

我们仍然保留它,因为它帮助我们测试内部API,但它显然不能与Cheri一起工作,因此:

${SRCDIR}/configure \
        --without-persistent-storage \
        [the usual options]

不要惊慌(非常详细)

Varnish有一个内置的恐慌处理程序,可以转储大量有价值的信息,所以人们不需要给我们发送1TB的核心转储。

转储的部分信息是使用 libunwind ,在Cheri版本中尚未提供,因此:

${SRCDIR}/configure \
        --without-unwind \
        [the usual options]

[u] Intptr_t是还是不是?

这两个typedef uintptr_tintptr_t 都足够大,可以容纳一个指针,这样你就可以编写“可移植的”代码,执行Cheri阻止你做的那种整数指针错误计算。

从理论上讲,我们不应该有 [u]intptr_t 在Varnish中,因为我们的质量方针之一是从不将整数转换为指针。

但有几个地方我们将它们用于“私有”结构成员,而不是联合。

这些成为第一个绊脚石::

vsm.c:601:15: error: shift count >= width of type
     vd->serial = VSM_PRIV_LOW(vd->serial + 1);
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~

令人困惑的信息是因为在切里, [u]intptr_t 与指针一样,都是16字节宽,但在这种情况下,整数视图被用作位图。

目前,我将它们更改为 uint64_t ,并把它们放在待办事项清单上。

其中之一作为死机输出的一部分打印::

VSB_printf(vsb, "priv2 = %zd,\n", vfe->priv2);

但这不适用于更广泛的类型,因此::

VSB_printf(vsb, "priv2 = %jd,\n", (intmax_t)vfe->priv2);

然后在Cheri下编译Varnish,我们可以使用以下命令进行检查:

% file bin/varnishd/varnishd
bin/varnishd/varnishd: […] CheriABI […]

首次试运行

只是为了看看有多糟糕,我们运行主要的测试脚本::

% cd bin/varnishtest
% ./varnishtest -i -k -q tests/*.vtc
[…]
38 tests failed, 33 tests skipped, 754 tests passed

这还不算坏,…

/phk