news 2026/11/5 1:58:22

chmod 777 之后,为什么还是 Permission denied

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
chmod 777 之后,为什么还是 Permission denied

chmod 777 之后,为什么还是 Permission denied

原文链接:chmod 777 之后,为什么还是 Permission denied

先还原一个很常见的现场。

服务换到新机器,日志目录写不进去。值班的同学熟练地敲下:

sudochmod-R777/srv/app

再试一次,还是:

touch: cannot touch '/srv/app/logs/app.log': Permission denied

于是权限被加到 7777,加上-R,再加上sudo,最后开始怀疑内核有 bug。

大多数时候,问题不在权限位,而在于我们默认“权限”只有rwx这一层。Linux 在真正打开一个文件之前,要穿过好几道门:路径上的目录、umask、ACL、挂载选项、LSM、文件属性,任何一道没过去,chmod 777都只是把第一道门拆了。

下面按排查顺序,把这几道门逐个走一遍。

第一步:先分清 errno

报错信息里的英文,其实已经给了线索。Permission denied和Operation not permitted不是一回事。

errno典型含义常见来源
EACCES(13)权限不足权限位、ACL、noexec、SELinux
EPERM(1)操作本身不被允许chattr +i、非文件所有者执行chmod、能力缺失
EROFS(30)只读文件系统只读挂载、容器只读根目录
EDQUOT(122)配额超限用户/项目磁盘配额
ETXTBSY(26)可执行文件正被占用一边运行一边覆盖二进制

看到Operation not permitted还去chmod,方向就已经错了。

第二道门:路径上每一级目录都要有 x

这是最容易被忽略的一条。要访问/srv/app/logs/app.log,内核会依次穿过/、/srv、/srv/app、/srv/app/logs,每一级目录都需要执行位x。目录的x不是“能运行”,而是“能进入、能按名字找到里面的东西”。

$mkdir-p/srv/app/logs $chmod777/srv/app/logs $sudo-unobodytouch/srv/app/logs/a.log touch: cannottouch'/srv/app/logs/a.log':Permission denied

logs已经是 777,为什么还不行?用namei把整条路径的权限摊开看:

$ namei-l/srv/app/logs/a.log f: /srv/app/logs/a.log drwxr-xr-x root root / drwxr-xr-x root root srv drwx------ root root app drwxrwxrwx root root logs

问题出在/srv/app是700。logs再开放,nobody也进不到它父亲那一层。

顺便记住目录三个位的真实含义:

  • r:能列出目录里的名字;
  • x:能进入目录、能访问已知名字的条目;
  • w:能在目录里创建、删除、重命名条目。

只有r没有x时,ls能看到文件名,但ls -l会满屏?,因为拿不到元数据。只有x没有r时,反而可以在知道完整路径的情况下直接访问文件。

还有一个变种:目录带 sticky bit(比如/tmp的1777),即使大家都有w,也只能删除自己的文件。这是“写得进去却删不掉”的常见原因。

第三道门:umask 决定了新文件的起点

chmod 777只改已经存在的对象。之后新建的文件,权限由创建时的mode & ~umask决定。

$umask0022 $touchdemo.txt $stat-c'%a %n'demo.txt644demo.txt

普通文件默认起点是666,目录是777,再被 umask 削掉。所以umask 022下新建文件是644,新建目录是755。

如果某个进程的 umask 是077,它写出来的文件就是600,别的用户自然读不了。systemd 服务可以在 unit 里设置:

[Service] UMask=0027

排查时可以看进程的当前 umask:

$grep-iumask/proc/$(pgrep-fmyapp|head-1)/status Umask: 0022

第四道门:ACL 会把权限“打折”

ls -l末尾出现+,说明这个文件带 ACL:

$ls-lreport.txt -rw-r--r--+1alice dev1024Nov210:00 report.txt
$ getfacl-preport.txt# file: report.txt# owner: alice# group: devuser::rw- user:bob:rwx#effective:r--group::r-- mask::r-- other::r--

bob明明被授予了rwx,有效权限却只有r--。原因是 ACL 里的mask相当于“权限上限”,命名用户和所属组的权限都要和 mask 取交集。

更隐蔽的是:文件一旦有 ACL,chmod g+w改的其实是 mask,不是 group 位。所以你会看到chmod执行成功,getfacl里的具体条目却没变。

修复方式是把 mask 一起放开:

setfacl-mu:bob:rwx,m::rwx report.txt

目录还可以设置默认 ACL,让以后新建的文件自动继承:

setfacl-d-mu:deploy:rwx /srv/app/logs

第五道门:挂载选项可能禁止执行

权限位全是777,./tool仍然报Permission denied,先看挂载参数:

$ findmnt-T/srv/app-oTARGET,SOURCE,FSTYPE,OPTIONS TARGET SOURCE FSTYPE OPTIONS /srv/app /dev/sdb1 ext4 rw,nosuid,nodev,noexec,relatime

noexec会让execve()直接返回EACCES,和文件权限无关。/tmp、/var/tmp、某些数据盘默认这么挂,是常见的安全加固。

一个容易混淆的细节:noexec只拦“把文件本身当作程序执行”。下面这条仍然可能成功:

$bash/srv/app/script.sh

因为真正被execve的是/bin/bash,脚本只是被当成参数读进去。反过来,ro挂载会让所有写操作返回EROFS,容器里只读根文件系统时尤其常见。

第六道门:SELinux 和 AppArmor

权限位、ACL、挂载选项都正常,还是被拒,就该怀疑 Linux Security Module 了。

SELinux 环境下先看上下文:

$ getenforce Enforcing $ls-Z/srv/app/logs unconfined_u:object_r:var_t:s0 /srv/app/logs

如果服务应该读写httpd_sys_content_t之类的类型,而目录被打成了var_t,即使777也会被拒绝。查最近一次的拒绝记录:

$sudoausearch-mavc-tsrecent $sudodmesg|grep-i'avc: denied'

确认是标签问题后,用restorecon恢复默认上下文,而不是直接setenforce 0:

sudorestorecon-Rv/srv/app

AppArmor 则看aa-status和dmesg,被 profile 拦下时同样表现为EACCES。

把安全模块一关了之,问题会暂时消失,但下次上线还会回来,而且是以更难查的形式。

第七道门:chattr 的文件属性

chattr +i设置的不可变属性,连 root 都改不了:

$sudochattr +i /etc/resolv.conf $sudosh-c'echo "nameserver 1.1.1.1" > /etc/resolv.conf'sh: /etc/resolv.conf: Operation not permitted

注意报错是Operation not permitted,不是Permission denied。查看属性:

$ lsattr /etc/resolv.conf ----i---------e------- /etc/resolv.conf

i表示不可变,a表示只能追加。去掉再改:

sudochattr-i/etc/resolv.conf

这里还有一个 shell 层面的坑:

sudoecho"nameserver 1.1.1.1">/etc/resolv.conf

即使文件可写也会失败,因为重定向是当前 shell 做的,sudo只提升了echo的权限。正确写法是让特权进程自己打开文件:

echo"nameserver 1.1.1.1"|sudotee/etc/resolv.conf

还有两类环境因素

NFS 的 root squash。服务端开启root_squash后,客户端的 root 会被映射成nobody,在共享目录里并不具备超级用户权限。表现就是“我是 root,为什么还写不进去”。

容器里的 UID 映射。容器内的uid 1000和宿主机上的uid 1000未必是同一个用户,启用 user namespace 后更是如此。挂载卷的属主看起来对,实际对不上,chmod 777在容器内也可能作用在另一层文件系统上。

一张排查清单

遇到权限问题,按这个顺序走,通常五分钟内能定位:

  1. 看 errno:EACCES、EPERM、EROFS指向完全不同的方向;
  2. namei -l /path/to/file,确认路径上每一级目录都有x;
  3. getfacl,检查 ACL 和 mask;
  4. findmnt -T /path,确认没有ro、noexec;
  5. lsattr,排除i、a属性;
  6. getenforce、aa-status、ausearch,检查安全模块;
  7. 最后才考虑 NFS 映射、容器 UID、磁盘配额这些环境因素。

chmod 777的问题不在于它危险——虽然它确实危险——而在于它只覆盖了整条链路上的一小段。真正让人加班到凌晨的,往往是那个700的父目录,或者一行noexec。

下次再看到Permission denied,先别急着加权限。让namei把路径摊开,答案通常就在里面。


参考文档
  • Primers 编程伙伴/Bash/帮助手册/sudo
  • Primers 编程伙伴/Bash/帮助手册/chmod
  • Primers 编程伙伴/HTML/HTML 元素/i
  • Primers 编程伙伴/Bash/帮助手册/mkdir
  • Primers 编程伙伴/Bash/帮助手册/touch
  • Primers 编程伙伴/Bash/帮助手册/namei
  • Primers 编程伙伴/Bash/帮助手册/umask
  • Primers 编程伙伴/Bash/帮助手册/stat
  • Primers 编程伙伴/Bash/帮助手册/grep
  • Primers 编程伙伴/Bash/帮助手册/head
  • Primers 编程伙伴/Bash/帮助手册/ls
  • Primers 编程伙伴/Bash/帮助手册/findmnt
  • Primers 编程伙伴/HTML/HTML 元素/var
  • Primers 编程伙伴/Bash/帮助手册/dmesg
  • Primers 编程伙伴/Bash/帮助手册/echo
  • Primers 编程伙伴/HTML/HTML 元素/a
  • Primers 编程伙伴/Bash/帮助手册/tee
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/5 1:58:06

《QGIS空间数据处理与高级制图》045:拓扑的概念与GIS应用意义

《QGIS空间数据处理与高级制图》045:拓扑的概念与GIS应用意义 作者介绍:本文作者"翰墨之道",QGIS 资深用户与空间数据处理专家,专注 GIS 空间数据分析、高级制图与预处理工作流自动化,拥有丰富的国土、生态、水利等行业项目经验。 本专栏地址:【QGIS 空间数据处…

作者头像 李华
网站建设 2026/11/5 1:57:41

OpenStack 网络管理(实操):建网络、连路由、浮动 IP 与安全组

网络管理的实操可以一次走完:先用 Dashboard 把「建网络 → 验证隔离 → 连路由 → 上外网 → 绑浮动 IP → 配安全组」走通,再用 CLI 把同一套流程复现一遍,最后看 OVN 下的现象与经典 Linux Bridge 有什么不同。每一步都给出验证方法——建…

作者头像 李华
网站建设 2026/11/5 1:56:40

让程序 “联网“!TCP、UDP、HTTP 一次讲透,手写聊天程序和爬虫接口

前面写的程序都是 "自己跟自己玩"。真实的应用要联网—— 浏览器请求网页、聊天软件收发消息、爬虫抓数据。这篇老哥带你打通网络编程。一、网络编程三要素进程之间要通信,靠三个东西:协议:定义通信规则(数据格式、传输…

作者头像 李华
网站建设 2026/11/5 1:56:38

基于Springboot3 + Vue3实现的同城兴趣活动组局平台

项目描述本项目是一个面向校园与社区场景的活动发布与报名管理平台,围绕“活动发起—报名参与—过程管理—数据统计”的完整链路进行设计,覆盖访客、普通用户、活动发起人和管理员四类角色,力求让活动组织更高效、参与体验更顺畅。平台按角色…

作者头像 李华