
Linux(二):文件权限 —— rwx、chmod、chown 与超越它们的机制
系统讲清 Linux 权限模型:rwx 在文件与目录上的不同语义、数字和符号写法、chmod/chown 用法、umask 默认值、SUID/SGID/Sticky 与 ACL,附排障清单。
文件权限看似简单——敲个 chmod 755 就完事了——但它却是生产环境中频繁引发问题的罪魁祸首之一:服务启动失败、部署脚本悄无声息地卡住、Nginx 返回 403 错误、共享目录泄露敏感数据,或者 rm 拒绝删除一个“看起来能删”的文件。死记硬背那些数字代码解决不了这些问题,真正管用的是同时搞清楚以下三点:

- 同样的
r/w/x权限位,在普通文件和目录上有着截然不同的含义——尤其是目录相关的部分,最容易让人掉坑。 - 内核在检查权限时,遵循的是 owner / group / others 的三段式
if/else if/else判断逻辑,而不是把匹配的权限简单相加——因此,“恰好属于某个组”有时反而比“完全无关的外人”更受限。 umask、SUID、SGID、sticky bit 和 ACL 这些机制,每一种都有其特定的用途,如果超出它们的设计初衷随意使用,系统被攻破的风险就会大大增加。
本文从最基础的概念讲起,逐步深入:权限位的实际意义、数字表示法与符号表示法的区别、chmod/chown/chgrp 的用法、通过 umask 设置默认权限、三个特殊权限位的作用、以及如何用 getfacl/setfacl 管理 ACL。最后还附上一份可以直接拿来排查问题的清单。所有例子都来自实际场景——比如 webroot 目录权限配置、团队共享目录管理、/tmp 的安全设置、被 +i 标记为不可变的配置文件——而不是那种脱离实际的玩具案例。
权限模型:owner / group / others#

Linux 是一个多用户操作系统,因此每个 inode(包括普通文件、目录、符号链接、设备等)都绑定了三个身份标识:
- 属主(
u):拥有该 inode 的用户 UID,通常是创建者。 - 属组(
g):一个 GID,属于该组的成员共享组级别的访问权限。 - 其他人(
o):既不是属主,也不在属组中的所有其他用户。
内核在进行权限检查时并不是简单地“累加匹配的权限位”,而是采用一种严格的优先级匹配机制:
| |
这种机制带来了一个常让人意外的结果:即使你属于某个组,但如果属主权限位禁止了某操作,组权限也无法帮你绕过限制。比如执行 chmod 047 myfile,文件的属主将无法读取自己的文件,而其他人却可以随意读写甚至执行。
root 用户(UID 为 0)可以通过 CAP_DAC_OVERRIDE 完全绕过权限检查。唯一反向的例外是 sticky bit,稍后会详细说明。
字符的 mode 字符串#
运行 ls -l 时,你会看到类似 -rwxr-xr-x 的输出,从左到右逐位解读如下:
| 位置 | 含义 |
|---|---|
| 1 | 文件类型:- 普通文件、d 目录、l 符号链接、c/b 字符设备/块设备、s 套接字、p 管道 |
| 2–4 | 属主的权限位 rwx |
| 5–7 | 属组的权限位 rwx |
| 8–10 | 其他人的权限位 rwx |
每一位权限的具体含义如下:
r(4)—— 读权限w(2)—— 写权限x(1)—— 执行权限(对于目录来说,表示“进入”或“遍历”)
每三位权限的数值相加,得到一个八进制数字,三个数字连起来就是我们熟悉的权限表示法,例如 755、644、600。如果在 x 的位置看到 s/S/t/T,则说明还设置了特殊权限位——接下来会展开讲解。
rwx 在文件与目录上:最容易翻车的地方#
权限问题大多出在这里。字母相同,意义却大不相同。
普通文件的权限#
| 权限位 | 含义 | 没有它会怎样 |
|---|---|---|
r | 读取文件内容 | 无法使用 cat、less 或 cp 拷贝文件 |
w | 修改文件内容(覆盖、截断或以 O_TRUNC 方式打开) | 无法用 > 重定向写入,也无法进行原地编辑 |
x | 将文件作为程序执行(需有合法的 ELF 头,或脚本包含 shebang) | 无法运行 ./prog |
需要注意的是,w 仅影响文件内容的修改。删除文件并不需要文件本身的 w 权限,而是由父目录的 w 权限决定。
目录的权限#
| 权限位 | 含义 | 没有它会怎样 |
|---|---|---|
r | 列出目录中的文件名 | 无法使用 ls dir/ 查看目录内容 |
w | 创建、删除或重命名目录中的文件(同时需要 x 权限) | 无法执行 touch dir/x、rm dir/x 或在目录内使用 mv |
x | 访问目录中的文件(通过路径查找文件并进入目录) | 无法使用 cd dir、cat dir/已知名字 或访问任何包含 dir 的路径 |
通过三个简单实验可以更直观地理解这些规则:
实验 A —— 有 r 无 x(权限模式 644)
| |
实验 B —— 有 x 无 r(权限模式 311)
| |
这就是“私密 bin”技巧的原理:允许进入目录,但不允许列出内容。
实验 C —— 有 w 无 x(权限模式 622)
| |
单独给目录设置 w 权限是没用的,必须搭配 x 才能生效。
目录权限的经验总结:x 是核心,决定了能否访问目录;w 只有和 x 搭配才有意义;r 则是锦上添花,方便列出内容。
chmod:数字 vs 符号写法#

无论使用哪种方式,最终修改的都是那九个权限位。它们的区别在于:你是要明确指定一个最终状态,还是基于当前状态进行调整。
数字表示法 —— 绝对定义#
将每个身份的权限值相加(r=4、w=2、x=1),然后拼接成三位数字:
| |
这种写法适合需要明确指定最终权限状态的场景,比如脚本化部署、新创建的文件,或者你完全不关心之前的权限设置。
符号表示法 —— 相对调整#
通过 身份(u 用户、g 组、o 其他用户、a 所有人)+ 操作符(+ 添加、- 移除、= 设置)+ 权限位(r 读、w 写、x 执行、X 特殊执行、s setuid/setgid、t 粘滞位)来调整权限:
| |
符号表示法的杀手锏是大写的 X,特别适合处理目录树:
| |
这里的 X 只会为目录以及原本就至少有一个执行位的文件添加执行权限。如果没有它,chmod -R 755 project/ 会让所有的 .md、.png 和 .csv 文件都变成“可执行”——虽然没什么实际危害,但看起来很不专业,还可能成为扫描配置不当的 webroot 的攻击者的线索。
符号表示法更适合只调整某个维度的权限,而不需要改动其他部分的场景。
chown / chgrp:改所有权#
| |
需要记住的几条规则:
- 只有 root 用户可以随意更改文件的所有权。普通用户不能“赠送”文件给别人,否则他们完全可以通过将文件转移到其他用户名下,轻松绕过磁盘配额限制。
- 文件的所有者可以使用
chgrp将文件的所属组更改为自己所属的任意组,但无法将文件移动到自己未加入的组中。 - 出于安全考虑,
chown会自动清除普通文件上的setuid和setgid权限位——这一点非常重要!如果你对一个设置了 SUID 的二进制文件执行了chown root操作,记得在完成后重新设置 SUID 权限。
一些你会反复用到的常见命令模式:
| |
umask:默认权限的过滤掩码#
umask 是一个用于调整新文件或目录默认权限的掩码,它通过屏蔽某些权限位来限制初始权限设置。系统的默认权限如下:
- 普通文件:
0666(不赋予执行权限x,防止数据文件被意外执行) - 目录:
0777(需要执行权限x才能进入或访问目录内容)
实际生效的权限可以通过公式计算得出:
实际权限 = 默认权限 AND NOT umask
以下是常见的 umask 设置及其适用场景:
| umask | 文件权限 | 目录权限 | 适用场景 |
|---|---|---|---|
022 | 644 | 755 | 桌面环境默认值;适合公开可读的文件和目录 |
027 | 640 | 750 | 服务器/生产环境 —— 仅允许属主和同组用户访问,其他用户无权限 |
002 | 664 | 775 | 开发工作站,使用 USERGROUPS(每个用户独立主组)进行协作 |
077 | 600 | 700 | 最严格配置 —— 适用于敏感目录如 ~/.ssh 或存储密钥的目录 |
查看与修改 umask#
以下是一些常用的命令和方法:
| |
系统级配置#
系统范围的默认 umask 通常定义在以下文件中:
/etc/login.defs(UMASK参数)/etc/profile/etc/pam.d/*
对于使用 systemd 的服务,建议直接在服务单元文件中通过 UMask= 指定权限掩码,而不是依赖用户的 shell 配置文件(如 ~/.bashrc)。这是因为服务进程不会加载用户的 shell 配置文件。
特殊权限位:SUID、SGID、sticky#

chmod 命令实际上支持四位八进制数。第一位用于表示三个特殊权限标志:4(SUID)、2(SGID)、1(sticky)。这些标志可以组合使用,例如 chmod 6755 表示同时设置 SUID、SGID 和权限模式 755。
SUID(4xxx)—— 以文件所有者身份运行#
当 SUID 被设置在可执行文件上时,无论谁运行该程序,进程都会以文件所有者的有效 UID 来执行。最典型的例子如下:
| |
passwd 程序需要修改 /etc/shadow 文件(权限为 0640 root:shadow),但普通用户也需要能够更改自己的密码。通过结合 SUID 和一个经过严格审计的小型程序,这种需求得以优雅解决。
| |
小写的 s 表示 SUID 已启用且底层的 x 位也被设置;大写的 S 则表示 SUID 已启用但 x 位未设置——这通常是配置错误。
SUID 是一把双刃剑。SUID-root 的二进制文件中如果存在漏洞,可能直接导致本地提权。因此,定期检查系统中的 SUID 文件至关重要:
| |
除了标准列表中的程序(如 passwd、sudo、mount、su 以及一些老版本发行版中的 ping 等),任何其他带有 SUID 的文件都需要明确其存在的理由。
SGID(2xxx)—— 两种用途#
应用于可执行文件:进程将以文件所属组的有效 GID 运行。这种机制常用于需要访问特定组资源的工具,例如 wall 命令向 /dev/tty*(属于 tty 组)写入消息。
应用于目录(更为常见):在设置了 SGID 的目录中创建的文件和子目录会自动继承该目录的组所有权,而不是创建者的主组。这是实现团队共享目录的最佳实践:
| |
这样一来,developers 组中的任何成员在该目录下创建的文件都会自动归属于 developers 组,从而确保组内其他成员也能读写这些文件。如果没有 SGID,每次创建文件后都需要手动执行 chgrp——而这很容易被遗忘。
Sticky bit(1xxx)—— 限制删除权限#
当 sticky bit 被设置在目录上时,它会改变一条规则:即使目录对所有人可写,也只有文件的所有者(或 root)才能删除或重命名该文件。/tmp 是这一机制的经典应用场景:
| |
如果没有 sticky bit,/tmp(权限为 1777)就会变成一个“自由市场”,任何人都可以删除他人的会话套接字或锁文件,导致混乱。
| |
对于文件而言,sticky bit 是历史遗留特性(曾用于指示“将文本段保留在交换区”),在现代 Linux 系统中已被忽略。
常见场景 —— 可直接拷走,附原理#

执行脚本时提示 “Permission denied”#
| |
问题出在缺少 x(执行权限)。解决方法如下:
| |
如果加上执行权限后仍然报错 exec format error,说明脚本缺少 shebang(例如 #!/usr/bin/env bash),导致内核不知道该用哪个解释器来运行。
Web 服务器返回 403 错误#
nginx 或 apache 在 Debian/Ubuntu 上以 www-data 用户运行,在 RHEL 系列上则以 nginx 用户运行。要让它们正常工作,必须满足以下条件:
- 目标文件需要有
r(读权限) - 从根目录到目标文件的每一级目录 都需要有
x(执行权限)
第二点常常被忽略。例如,/home/alice/site/ 的权限通常是 700,这意味着 www-data 用户连进入目录都无法做到。解决方法有两种:要么将文档根目录移到 /var/www/ 下,要么调整路径权限:
| |
团队共享项目目录#
目标是让 developers 组的所有成员都能读写项目中的所有文件,而组外用户完全无法访问。
| |
这里的关键点在于:
2(SGID)确保新创建的文件和目录继承父目录的属组770权限阻止组外用户访问umask 002让新文件默认权限为664(而不是644),从而允许组内成员编辑
多用户临时目录#
你的 Linux 发行版已经为你配置好了 /tmp,它的权限是 1777。如果你需要类似的共享暂存空间,可以这样设置:
| |
保护私钥文件#
| |
ssh 会拒绝使用任何对组或其他用户可读的私钥文件——这是为了安全设计的功能,而非缺陷。
ACL:当三个桶不够用时#

传统的权限模式只有三个“桶”:属主、属组和其他人。但在实际工作中,需求往往更复杂。比如,“让审计员 eve 能读取这份报告,但她并不在 developers 组里”,或者“禁止某个特定外包人员访问某个目录”。这时,POSIX ACL 就派上用场了。
查看 ACL#
| |
在 ls -l 输出中,如果权限字符串末尾带有 +(例如 -rw-r-----+),就表示该文件设置了 ACL。
设置 ACL#
| |
对于目录,-R 参数可以递归应用 ACL,而默认 ACL 还能作用于未来在目录中创建的新文件或子目录 —— 类似 SGID 的效果,但粒度更细:
| |
ACL mask 的注意事项#
mask:: 表示的是除 user::(属主)和 other:: 之外,所有额外条目的有效权限上限。一个常见的坑是:在设置了 ACL 的文件上运行 chmod g=... 时,实际上修改的是 mask,而不是真正的组权限条目。如果需要直接修改组权限条目,可以这样做:
| |
需要注意的是,文件系统必须挂载时启用 ACL 支持。现代的 ext4、xfs 和 btrfs 文件系统默认已支持 ACL,可以通过 tune2fs -l 或 mount | grep acl 来确认。
chattr / lsattr:文件系统层的属性#
chattr 用于设置 ext4 或 xfs 文件系统的属性,这些属性独立于权限系统,甚至对 root 用户也有效。
| |
使用 +i 可以锁定关键配置文件(如 /etc/fstab、/etc/passwd、/etc/sudoers),避免因手误执行 sed -i 等命令导致系统无法启动。使用 +a 可以保护日志文件,防止事后篡改。这两种方式都能有效回答“如何防止 root 用户意外删除文件”的问题——除非先用 chattr -i 移除保护,否则即使是 root 用户也无法删除文件。
排障清单#
按照以下步骤操作,可以解决大约 90% 的权限相关问题。
第一步 —— 确认当前身份#
| |
如果问题涉及某个服务,那么关键的身份信息是 systemd 配置中的 User= 和 Group=,而不是你登录时使用的用户。
第二步 —— 检查路径上的每一级目录#
仅仅确保目标文件有 r 和 x 权限是不够的,内核会对路径上的每一级目录重新检查 x 权限。最快捷的工具是 namei:
| |
从输出中找到第一行缺少 x 权限的目录,那就是问题的根源。
第三步 —— 是否涉及 ACL、文件属性或挂载选项?#
| |
如果 /tmp 被挂载为 noexec,无论你如何修改 chmod,执行 ./script.sh 都会被静默拒绝。
第四步 —— SELinux 或 AppArmor#
在 RHEL/Fedora/CentOS 系统上,运行 getenforce 如果返回 Enforcing,可以通过 ls -lZ file 查看 SELinux 标签,并用 audit2why 分析最近的拒绝原因。在 Ubuntu 上,aa-status 可以列出 AppArmor 的配置。这些安全机制即使在经典权限看似允许的情况下,也可能拒绝访问。
常见问题及排查方向#
已知正常的脚本报 Permission denied 错误 → 可能缺少 x 权限、缺少 shebang,或者脚本位于 noexec 挂载点上。
Web 服务器返回 403 错误 → www-data 通常被视为 others;使用 namei -l 检查路径上是否有缺少 x 权限的目录。
rm: cannot remove ...: Operation not permitted(注意:不是 Permission denied) → 使用 lsattr 检查是否设置了 +i 属性;如果有,先用 chattr -i 移除。
能够写入一个不属于自己的文件 → 检查父目录的 w 权限;文件属主对删除或重命名操作无关紧要。
心智模型与延伸阅读#
把下面三条嚼透,几乎所有真实情况都能扛过去:
- 文件 vs 目录:在文件上
x是“它是不是程序”。在目录上x是唯一通向内容的闸门。 - 首匹配级联:owner 或 group 或 others——永远不是相加。审计的时候问自己“调用者落进哪个桶?”
- 特殊位各司其职:SUID = “让无权调用者去做某件被精确审计过的特权操作”;目录上的 SGID = “团队目录”;sticky = “公共可写但不能互删”。在这些场景之外,不要乱开。
继续往深里走的方向:
man 1 chmod、man 2 chmod、man 5 acl、man 1 chattr—— 权威来源,意外地好读。- 《Linux 用户管理》(本系列下一篇)——
/etc/passwd、/etc/shadow、组、sudoers、PAM。 - 《Linux 管道与重定向》 —— 在文件描述符与
stdin/stdout/stderr之上继续搭。 - 强制访问控制(MAC)框架:SELinux(RHEL 系)和 AppArmor(Debian/SUSE 系)在我们这里讲的自主访问控制之上再加一层。同样的问题,不同的答案。
如果现在让你看 drwxr-s---+ 4 alice developers 这一行,你能立刻说出属主、属组、设了哪个特殊位、还有一份 ACL 在场,并且说出 “developers 组里的 bob” 和 “组外的 eve” 各自能做什么——那模型就在你脑子里了,剩下就是肌肉记忆。
Linux 9 篇
- 01 Linux(一):使用基础
- 02 Linux(二):文件权限 —— rwx、chmod、chown 与超越它们的机制 当前
- 03 Linux(三):磁盘管理
- 04 Linux(四):软件包管理
- 05 Linux(五):用户管理
- 06 Linux(六):系统服务管理
- 07 Linux(七):进程与资源管理 —— 从 top 到 cgroups
- 08 Linux(八):文件操作深入解析
- 09 Linux(九):Vim 编辑器精要