CatCoding

苹果:为了安全让 M2 吃灰

2023-03-06

苹果新的芯片性能真是不错,并且续航很可观,所以我最近买了个 M2 Pro。有几年没使用 Mac 系统了,所以日常使用还有些别扭,但最让我闹心是发现了苹果一个让人大跌眼镜的设计,而我几乎没找到关于这点的中文资料,所以写下来分享给你。

我日常会花时间在 Rust 编译器项目上,经常需要编译 rustc 和跑单元测试。单元测试大概是 1.4 w 个测试用例,测试框架会并行跑编译并执行后对比结果。我发现这台 Mac 跑测试一共需要 16 分钟,这是不可接受的,因为我之前使用 WSL 也不过 20-30 分钟左右。我用一台 32 c 64 g 的 Linux VM 跑同样的测试只需要 1.5 分钟。

我这台 Mac 选的配置一般,CPU 核数是 6 性能 + 4 效能,另外内存 32 G,这样算来也不可能有 10 倍的性能之差。在 Rust 代码仓库跑单元测试:

./x test tests/ui --force-rerun

可以通过 htop 看到明显没有充分利用所有的 CPU,上图是 Mac 的系统资源统计,下图是 Linux VM 的:

我实在想不通为什么会这样,因为我之前看到过 Mara Bos 发的 M1 Mac 的数据,她大概只需要 9 分钟跑完所有的单元测试。

然后我在 Rust 开发者论坛 rust-zulip 里发起一个帖子,很快得到了一些开发者的回复。刚开始有人怀疑是 mdworker_shared 进程的问题,这个进程是为 Spotlight 做索引用的,因为跑测试会不断生成新的临时文件,从 htop 上看这个进程会占用不少 CPU。但我把 Spotlight 彻底关闭掉,性能确实有一点点提高,但这明显不是根本原因。

我怀疑是不是测试框架用的 threads 数目不对,看代码是通过这个 get_concurrency 获取的,我通过 RUST_TEST_THREADS 尝试把数目提高,但是也没卵用。

Eric Huss 用的是 M2 Max,他跑测试花费的时间是 9 分钟,这个结果显然也不能匹配上高贵的 Max 配置。

后来有人提到是不是因为 SIPHuss 关闭 SIP 之后跑测试时间立马从 9 分钟减少到 1 分 36 秒 ! 这几乎是 5 倍多的提速。 另外,如果把 SIP 打开但把网络给关闭掉,同样能得到类似的提速。

这就是说跑单元测试的时候系统在不断地发送网络请求,这也解释了为什么我对比国外的用户跑测试所用的时间会更长,因为我走了 VPN 啊!我关闭 SIP 之后测试时间从 16 分钟提高到 153 秒,这可是 10x 的提速!

那么 SIP 是什么?

这东西全称 System Integrity Protection,译为系统完整性保护:

System Integrity Protection (SIP) in macOS protects the entire system by preventing the execution of unauthorized code. The system automatically authorizes apps that the user downloads from the App Store. The system also authorizes apps that a developer notarizes and distributes directly to users. The system prevents the launching of all other apps by default.

During development, it may be necessary for you to disable SIP temporarily to install and test your code. You don’t need to disable SIP to run and debug apps from Xcode, but you might need to disable it to install system extensions, such as DriverKit drivers.

SIP 是 OS X El Capitan 时开始采用的一项安全技术,目的是为了限制 root 账户对系统的完全控制权,也叫 Rootless 保护机制。从文档看出,苹果自家的 Xcode 系统是做了特殊处理的,但第三方软件需要经过 SIP 的检查。

更多细节请参考这篇文章 macOS 10.15: Slow by Design简而言之 SIP 会在我们跑任软件之前,把你的执行文件做一个校验和,然后通过网络请求发送到让人敬畏的苹果服务器,就是为了检测是否是恶意软件!

在我跑单元测试的时候,通过查看 Mac 的系统日志可以发现这么一条关键信息:

log stream | grep Xprotect

XprotectService 这个就是在检查我跑测试用到的一个 dylib 文件。Xprotect 是一个病毒扫描器,它会检查可执行文件是否在已知恶意软件列表中。

这真是个让人无语的设计!

这不仅适用于从网络下载的文件,也适用于你自己编译的程序或者是写的一小段脚本。因此,即使你编写了一行 shell 脚本并在终端中运行它,可能也会有延迟,在 HackerNews 上看到一个中国开发者发的可能有几秒的延迟:

echo $'#!/bin/sh\necho Hello' > /tmp/test.sh && chmod a+x /tmp/test.sh
time /tmp/test.sh && time /tmp/test.sh

PS:如果你运行过这个命令把 Terminal 加到可信列表,跑脚步就没这个问题了:

sudo spctl developer-mode enable-terminal

更让人吐血的是,此问题已报告给了苹果,然而苹果回应说这是“设计使然”!而你也会看到更多人在网络上反馈同样的性能问题,比如:

Hugo runs twice as fast in Asahi Linux than macOS on the same M1 Mac system

好了,如果你也会频繁跑大量的程序,可能也会受此影响。为什么我说”可能“,是因为这东西太复杂了,我还没搞清楚所有细节!官方文档关于 SIP 只有寥寥数语,如果你想了解更多关于 SIP 的资料,可以参考这篇博文 System Integrity Protection – Adding another layer to Apple’s security model

当我粗看这篇文章的时候,以为可以配置一下 /System/Library/Sandbox/rootless.conf 就可以忽略某些目录的文件,结果是我太幼稚了。我问 bjorn3 怎么回事,得到的回答是:

The system file protection is only a small part of the protections against malware macOS has. Xprotect is a virus scanner which checks all executables against a liat of known malware. There is signature checking (AMFI) which also checks if the certificate the executable has been signed with has been revoked (using an internet service from apple). This also checks if the entitlements the executable declares are allowed or for example only allowed by apple signed executables (like the SIP bypass entitlement). There is also a check that the application is allowed to access certain protected directories like your documents or images directory. And there are a couple of other checks. These are performed independent of where the executable is stored.

看起来就只有全关闭这条路了?如果你想关闭 SIP,还有那么点麻烦:

  1. 重启 Mac,按住 Command + R 直到屏幕上出现苹果的标志和进度条,进入 Recovery 模式。(如果是新的 Mac 就在启动的时候长按住电源键)
  2. 在屏幕上方的工具栏找到并打开终端,输入命令 csrutil disable
  3. 关掉终端,重启 Mac;
  4. 重启以后可以在终端中查看状态确认。

关闭也许会让你的 Mac 处于裸奔状态,我也不清楚有多大的安全隐患。开启 SIP 只需在上面第 2 步命令改为 csrutil enable 即可。


我上一个 Mac 是 2012 年买的,一共用了六七年,那台 Mac 真是非常耐用,所有的硬件这些年都没出现问题。苹果的硬件一直领先业界几个段位,我上次买是因为 Retina 屏幕,这次买是因为苹果自家的芯片。

有人说 Mac 是最适合开发者的设备,但苹果关心开发者么?我在 Rust Zulip 问一个对 Mac 很熟的开发者,这都快七年了为什么苹果不修复这个明显的问题,他的回答是:

从我作为一个局外人的观察来看,苹果公司不再像以前那样关心开发者了。他们曾经有一流的文档资料,但现在你要是能找到一点点文档就该知足了。

也许在苹果眼里只有使用 Xcode 的开发者才能称之为开发者!否则绝不会弄出这么个脑残设计,事实上很多开发者都没有意识到这是系统的默认行为,这么牛逼的芯片很多时候是在吃灰。

这不是 Secure by Design,而是 Slow by Design


Update:
一个读者指出了更简单的办法,把你信任的工具加入到 Developer Tools:

注意必须通过 UI 设置,这条命令虽然提示设置成功了,但是其实没成功 😂:

公号同步更新,欢迎关注👻