本文由 简悦 SimpRead转码, 原文地址 developer.apple.com
本帖是与可信执行系统相关的帖子集的一部分。如果您发现自己的 w......
本帖是与可信执行系统相关的帖子集的一部分。如果您是直接找到这里的,我建议您 从顶部开始。
Resolving Gatekeeper Problems Caused by Dangling Load Command Paths
Gatekeeper 致力于确保只有受信任的软件才能在用户的 Mac 上运行。你的代码必须通过 Gatekeeper 的审核。否则,你很可能会失去大量客户和用户来之不易的信任。
Gatekeeper 阻止应用程序的最常见原因是一个悬空的加载命令。要了解这个问题,首先需要了解库验证。
库验证是 macOS 上的一项重要安全功能。如果在可执行文件上启用了库验证,运行该可执行文件的进程就只能加载经 Apple 签名或与可执行文件具有相同团队 ID 的代码。这可以防止各种动态库冒充攻击。
库验证由Hardened Runtime启用,但你可以使用Disable Library Validation Entitlement(com.apple.security.cs.disable-library-validation)权限来退出。
重要 请启用库验证。只有当你的应用程序需要加载来自其他第三方开发者的插件时,才将其禁用。
Gatekeeper 检查应用程序时,会查看库验证的状态。如果禁用了库验证,Gatekeeper 会对应用程序的 Mach-O 映像进行全面检查,以防止动态库冒充攻击。如果启用了库验证,Gatekeeper 会跳过检查,因为库验证可以防止此类攻击。这样做的结果是,如果禁用库验证,就更难通过 Gatekeeper。
注意 当你为 Mac 构建命令行工具时,Swift 包管理器会创建一个悬挂的加载命令。有关该问题的更多信息,请参阅 Swift Forums 上的 Compiler adds RPATH to executable, making macOS Gatekeeper angry 线程。
如果您的应用程序被 Gatekeeper 拒绝,请在系统日志中查找类似这样的条目:
type: error
time: 2022-05-11 15:00:36.296159 -0700
process: XprotectService
subsystem: com.apple.xprotect
category: xprotect
message: File /Applications/DanglingRPath.app/Contents/MacOS/DanglingRPath failed on rPathCmd /Users/mrgumby/Work/TrustedExecutionFailures/CoreWaffleVarnishing.framework/Versions/A/CoreWaffleVarnishing (rpath resolved to: (path not found), bundleURL: /Applications/DanglingRPath.app)
在此示例中,条目提到了 rPathCmd,这是搜索此类问题的好方法。还可以搜索 loadCmd,它也会显示类似的问题。
重要 如果日志条目中的路径都是
<private>,请启用系统日志中的隐私数据。有关如何操作的信息,请参阅 在系统日志中记录私人数据。有关系统日志的一般信息,请参阅 你的朋友系统日志。
在本例中,Gatekeeper 拒绝了 DanglingRPath 应用程序,因为
-
它使用 rpath 相关引用引用了 CoreWaffleVarnishing 框架。
-
rpath 包含一个指向应用程序捆绑包之外的条目,指向名为
/Users/mrgumby/Work的目录。
这会使应用程序遭受动态链接库冒充攻击。如果攻击者在 /Users/mrgumby/Work中放置了恶意的 CoreWaffleVarnishing 副本,DanglingRPath 应用程序就会加载它。
要找到违规的 rpath 条目,可针对应用程序中的每个 Mach-O 映像运行 otool 查找悬空的 LC_RPATH 加载命令。例如
% otool -l DanglingRPath.app/Contents/MacOS/DanglingRPath | grep -B 1 -A 2 LC_RPATH
Load command 18
cmd LC_RPATH
cmdsize 48
path @executable_path/../Frameworks (offset 12)
Load command 19
cmd LC_RPATH
cmdsize 56
path /Users/mrgumby/Work (offset 12)
此应用程序有两个 LC_RPATH 命令。其中一条是 @executable_path/.../Frameworks,这条命令没有问题: 它指向应用程序 bundle 中的一个位置。相比之下,指向 /Users/mrgumby/Work 的命令显然是悬空的。
在本例中,悬空的 rpath 条目位于主可执行文件中,但情况并非总是如此;你可能会发现它潜伏在某个深度嵌套的动态链接库中。
请记住,这只是因为应用程序禁用了库验证而产生的问题:
% codesign -d --entitlements - DanglingRPath.app
Executable=/Users/mrgumby/Desktop/DanglingRPath.app/Contents/MacOS/DanglingRPath
[Dict]
[Key] com.apple.security.cs.disable-library-validation
[Value]
[Bool] true
如果启用了库验证,Gatekeeper 将完全跳过此检查,这样应用程序就能通过 Gatekeeper 的检查。
重要 在本例中,应用程序的主可执行文件禁用了库验证,但情况并非总是如此。这种问题常见于有多个可执行文件的应用程序,如应用程序本身和一两个嵌入式辅助工具,其中一个可执行文件禁用了库验证。
最后,上述示例基于 rpath 相关路径。如果您看到日志条目包含文本 loadCmd,请在 LC_LOAD_DYLIB 加载命令中搜索悬挂路径。
Fix Dangling Load Command Paths
解决这一问题的最佳方法是不禁用库验证。库验证是一项重要的安全功能。如果禁用它,就会引入这个问题 并 降低应用程序的安全性。反之,如果重新启用库验证,就能解决这个问题并提高整体安全性。
只有在应用程序加载其他第三方开发人员的插件时,禁用库验证才有意义。在这种情况下,要解决这个问题,就必须找到并消除所有悬空的加载命令路径。这里有两种可能性:
-
有冲突的加载命令路径存在于你从源代码构建的 Mach-O 镜像中。
-
或者是从供应商处获得的 Mach-O 映像,例如第三方 SDK 中的一个库。
在第一种情况下,可以通过调整构建系统,使其不包含悬空的加载命令路径来解决这个问题。
在第二种情况下,与供应商合作,消除悬空加载命令路径。
如果供应商不愿意这样做,那么在万不得已的情况下,可以通过自己修改加载命令来解决这个问题。有关如何做到这一点的示例,请参阅 在软件包中嵌入非标准代码结构。一旦您完成了这项工作,并且您的产品已经发货,请仔细考虑是否要继续与该供应商合作。
2022-06-13 添加了指向 Swift 论坛相关主题的 链接。
2022-05-20 首次发布。