macOS 文件执行权限不由传统强制访问控制(MAC)直接约束,而是由POSIX权限、代码签名、公证和SIP共同构成分层防护体系;Gatekeeper、Hardened Runtime与SIP在运行时实施强制拦截,确保即使具备x权限也无法绕过安全策略执行。
macos 中文件执行权限本身不直接受强制访问控制(mac)机制约束,而是由 posix 权限、代码签名、公证(notarization)和系统完整性保护(sip)共同作用,形成一套分层防护体系。真正起“强制”作用的,不是传统 mac 模型里的安全标签比对,而是 apple 自研的运行时策略——比如 gatekeeper、hardened runtime 和 sip 的组合拦截。
执行权限 ≠ 自动可运行
即使一个文件拥有 x(执行)位(如 -rwxr-xr-x),macOS 也不会让它直接运行。系统会在启动前做三重校验:
- Gatekeeper 检查:验证是否来自 App Store、已公证的开发者,或用户明确允许的“任何来源”
-
Hardened Runtime 启用时:禁止动态代码注入、限制
dlopen()加载未签名库、阻止调试器附加(除非显式授权) -
SIP 干预:若尝试执行位于
/usr/bin、/bin等受保护路径下的篡改二进制,内核会直接返回Operation not permitted,不看权限位也不走 DAC 流程
POSIX 执行权只是第一道门槛
终端中 chmod +x script.sh 只是让 shell 认为“可以尝试执行”,但后续能否真跑起来,取决于更高层策略:
- 脚本类(如 Bash/Python):依赖解释器是否被允许启动,且脚本所在路径是否在用户可控区域(如
~/Downloads);若放在/usr/local/bin,需确保解释器本身未被 SIP 锁定或重定向 - 二进制程序:必须有有效签名;若启用 Hardened Runtime,还要求开启
com.apple.security.cs.allow-jit才能运行 JIT 编译代码 - 无签名工具(如自制 CLI 工具):首次运行会弹窗提示“无法验证开发者”,用户点击“仍要打开”后,系统才临时豁免 Gatekeeper,但不会更改文件权限位
真正的“强制”发生在内核与用户态边界
macOS 的 MAC-like 行为体现在运行时强制策略上,而非传统标签系统:
-
进程级沙盒:App Sandbox 通过
entitlements严格限定可访问路径、网络、硬件等,哪怕文件权限是777,没对应 entitlement 就读不了 -
Code Signing 验证链:每次
execve()调用,内核都会检查签名有效性、团队 ID 是否匹配、是否被撤销——用户无法绕过 -
System Policy Framework:例如,未启用“完全磁盘访问”的 App 即使有 root 权限,也无法读取
~/Documents,因为此访问由NSFileProvider和隐私框架在用户态拦截,不进入底层 POSIX 判定环节
开发中要注意的实际表现
写脚本或打包工具时,别只盯着 chmod:
- 用
xattr -d com.apple.quarantine清除下载标记,避免 Gatekeeper 二次拦截 - 发布前务必公证(notarize),否则 macOS Sonoma 及以后版本默认拒绝运行
- 若需访问用户文档目录,Info.plist 中声明
com.apple.security.files.user-selected.read-write并触发NSOpenPanel,而不是靠 chmod 试图“硬闯” - 调试时遇到
Permission denied,先用codesign --display --verbose=4 your_binary查签名状态,再看系统日志里是否有amfid或trustd拒绝记录


















