瓦尼什如何遇到切里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_t
和 intptr_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