macOS 下 ls: .: Operation not permitted,连 sudo su 都没用?一次关于 TCC 的排障记录
在 macOS 上,进入 ~/Downloads 目录后执行 ls,却看到下面这样的报错:
bash
❯ cd /Users/leon/Downloads
❯ ls
ls: .: Operation not permitted
更诡异的是,即使切到 root:
❯ sudo su
Password:
sh-3.2# pwd
/Users/leon/Downloads
sh-3.2# ls
ls: .: Operation not permitted
依然没有任何改善。
第一眼看,这很像是一个"权限不够"的问题;但实际上,这通常不是 Unix 文件权限的问题,而是 macOS 的 TCC 隐私控制 在生效。
一、现象描述
问题发生在 ~/Downloads 目录中:
- cd 可以进入目录
- pwd 可以输出当前路径
- 但 ls 无法列出目录内容
- 即使 sudo su 切到 root,仍然报 Operation not permitted
这说明: - 当前 shell 知道目录路径
- 但当命令真正去 读取目录内容 时,被系统拦截了
也就是说,问题不在"路径是否存在",而在"是否被允许访问这个受保护目录"。
二、第一反应为什么容易走偏
很多人遇到这个错误,第一反应通常是:
- 是不是目录权限不对?
- 要不要 chmod 一下?
- 是不是属主不对,要 chown?
- 既然普通用户不行,那 sudo 总该行吧?
但这个问题最容易误判的地方就在这里:
macOS 有一套独立于 Unix 权限位的隐私访问控制。
从 macOS Mojave 开始,Apple 对一些用户敏感目录增加了额外保护,例如:
- ~/Desktop
- ~/Documents
- ~/Downloads
这些目录的访问,不只看 chmod/chown,还要看 当前应用是否被授予权限。
三、排查过程
1. 先看传统权限位
先检查目录元数据:
shell
ls -ld "/Users/leon/Downloads"
stat -f "%Sp %Su %Sg %N" "/Users/leon/Downloads"
结果如下:
shell
drwx------@ 17 leon staff 544 Apr 23 09:47 /Users/leon/Downloads
drwx------ leon staff /Users/leon/Downloads
这说明:
- 目录属主是 leon
- 权限位是 700
- 从传统 Unix 权限角度看,属主本来就应该可以访问
如果这时候 ls 还是报错:
ls "/Users/leon/Downloads"
ls: /Users/leon/Downloads: Operation not permitted
就可以基本判断:这不是普通权限位的问题。
2. 再看 ACL 和扩展属性
继续检查 ACL:
shell
ls -lde "/Users/leon/Downloads"
结果如下:
shell
drwx------@ 17 leon staff 544 Apr 23 09:47 /Users/leon/Downloads
0: group:everyone deny delete
这里的 ACL 条目只是限制删除,不足以解释"连目录内容都无法列出"。
如果连读取扩展属性都失败:
xattr -l "/Users/leon/Downloads"
xattr: [Errno 1] Operation not permitted: '/Users/leon/Downloads'
那就更像是 内核层面的隐私保护 在拒绝访问,而不是目录本身的权限配置有问题。
四、真正的根因:TCC 拦截了终端应用
这个问题的根因通常是:
终端应用本身没有被授予访问 Downloads 目录的权限。
这里最关键的一点是:
macOS 授权的对象是"应用进程",不是当前 shell 用户,也不是当前 UID。
也就是说:
- 你在 Terminal.app 里打开 shell
- 或者在 iTerm2、Warp、VS Code 内置终端里打开 shell
- 真正被 macOS 管控的是这个"宿主应用"
所以即使你执行了:
sudo su
也只是把 shell 切换成了 root 用户,但它仍然运行在 同一个终端应用内部。
如果这个应用没有被允许访问 Downloads,那结果就是: - 普通用户不行
- root 也不行
- 同一个终端里所有子进程都不行
这就是为什么 sudo 在这里完全救不了场。
五、为什么 pwd 可以,ls 不行
这个现象也很有迷惑性。
pwd 为什么能工作?
pwd 只是输出当前工作目录路径。
它不一定需要去枚举目录内容,所以不会触发同等级别的访问检查。
ls 为什么会失败?
ls 需要调用系统接口去读取目录项,也就是"真正访问目录内容"。
一旦这个目录是 TCC 保护对象,而当前应用没有权限,就会直接得到:
Operation not permitted
所以这两个命令看上去都"在操作目录",但本质上不是同一个访问级别。
六、怎么修复
方案 1:给终端应用开启 Files & Folders 权限
先确认你实际使用的是哪个终端:
- Terminal.app
- iTerm2
- VS Code
- Warp
- WezTerm
- Alacritty
- 其他终端宿主应用
然后在 macOS 中操作:
- 打开 System Settings
- 进入 Privacy & Security
- 找到 Files & Folders
- 找到你的终端应用
- 打开它对 Downloads Folder 的访问权限
如果你之前点过"Don't Allow",这里通常就是问题根源。
方案 2:给终端应用开启 Full Disk Access
如果在 Files & Folders 里没有对应条目,或者状态异常,也可以直接给终端应用开启 Full Disk Access:
- 打开 System Settings
- 进入 Privacy & Security
- 打开 Full Disk Access
- 将你的终端应用加入列表
- 打开开关
- 完全退出该应用并重新打开
这一步通常能直接解决问题。
注意:这里授权的是终端应用本身,而不是 shell、不是 zsh、不是 bash。
方案 3:重置 TCC 权限后重新授权 (推荐)
使用权限最小分配原则,有需要在添加
如果权限状态已经乱掉,比如之前拒绝过、切换过终端、系统没有再次弹窗,可以重置 Downloads 的访问授权。
Terminal.app
tccutil reset SystemPolicyDownloadsFolder com.apple.Terminal
iTerm2
tccutil reset SystemPolicyDownloadsFolder com.googlecode.iterm2
VS Code
tccutil reset SystemPolicyDownloadsFolder com.microsoft.VSCode
重置之后:
- 完全退出对应应用
- 重新打开
- 再次访问 ~/Downloads
- 根据系统提示选择允许
七、修复后如何验证
修复完成后,重新打开终端,再执行:
cd ~/Downloads
ls
如果权限已生效,应该可以正常列出文件。
也可以顺手验证几个命令:
ls -la ~/Downloads
xattr -l ~/Downloads
find ~/Downloads -maxdepth 1
如果这些命令都能正常返回,说明问题已经解决。
八、几个常见误区
误区 1:这是 chmod 能解决的问题
不是。
如果是 chmod 问题,通常 root 可以绕过;而这里连 root 都不行,说明不是传统权限位主导。
误区 2:sudo 应该总能绕过
在 Unix 世界里,很多权限问题确实可以靠 root 解决。
但在 macOS 的 TCC 模型里,root 并不能自动绕过应用层隐私控制。
误区 3:需要关闭 SIP
通常 不需要。
这个问题发生在用户目录的 Downloads 访问上,优先应该排查:
- Files & Folders
- Full Disk Access
- TCC 授权状态
而不是直接上升到 SIP。
误区 4:是 Downloads 目录坏了
大多数情况下不是目录损坏,而是:
- 当前终端应用没有获得访问授权
- 或者之前被拒绝后,系统把状态记住了
九、这个问题背后的本质
这个问题本质上暴露了 macOS 权限模型和传统 Unix 权限模型的差异。
在 Linux 或传统 Unix 的理解里,我们习惯认为:
"只要 UID 对了,或者拿到 root,就应该能访问。"
但在 macOS 上,很多敏感资源访问实际上变成了双层判断:
- 文件系统权限
- 隐私与安全策略(TCC)
只满足第一层,不代表一定能访问成功。
十、结论
如果你在 macOS 的 ~/Downloads 目录里看到:
ls: .: Operation not permitted
并且连 sudo su 都无效,那么最可能的根因不是 Unix 权限,而是:
当前终端应用没有被授予访问 Downloads 的 TCC 权限。
最直接的修复路径是:
- 到 Privacy & Security > Files & Folders 检查终端应用的 Downloads 权限
- 必要时到 Full Disk Access 给终端应用授权
- 如果状态异常,用 tccutil reset 重置后重新授权
- 完全退出终端应用并重新打开,再验证
一句话总结:
在 macOS 上,sudo 能切换用户,但不能替终端应用拿到 TCC 授权。
参考
- Apple Support: Allow apps to access your Downloads folder
- Apple Support: Control access to files and folders on Mac