Linux 基础 04:权限与属主——rwx 在文件和目录上不是一回事

发布于 2022-04-12 20:30 更新于 2022-04-12 22:10 1775 字 9 min read ... 访问量 手写 每个字都是我自己敲的。

Linux 基础 25:收尾——自查清单与继续深入的方向Linux 基础 24:启动流程与救援——UEFI、GRUB、initramfs 与 emergency modeLinux 基础 23:容器与内核边界——namespace、cgroup 与 docker exec 背后Linux 基础 22:日志与故障排查方法论——从现象到根因的六步Linux 基础 21:定时任务——crontab 的坑与 systemd timerLinux 基础 20:Shell 脚本(下)——trap、日志、幂等与并发锁Linux 基础 19:Shell 脚本(上)——引号、条件与退出码Linux 基础 18:性能观测与 strace——机器到底卡在哪Linux 基础 17:防火墙——iptables、nftables、firewalld 与 ufw 的关系Linux 基础 16:SELinux——当权限都对,服务还是被拒绝Linux 基础 15:权限进阶——sudoers 的通配陷阱、ACL 与 capabilitiesLinux 基础 14:SSH 与远程运维——密钥、权限与三种隧道Linux 基础 13:网络基础——自下而上的排错顺序Linux 基础 12:磁盘与文件系统——从块设备到挂载点Linux 基础 11:systemd——unit、systemctl 与 journalctl 的正确用法Linux 基础 10:包管理——apt 到底做了什么,以及四个高频报错Linux 基础 09:用户与组——passwd、shadow、sudoers 三件套Linux 基础 08:环境变量与 shell 启动文件——为什么 ssh 跑命令找不到你的 PATHLinux 基础 07:进程与信号——TERM 和 KILL 到底差在哪Linux 基础 06:管道与重定向——三条流、一个顺序问题Linux 基础 05:文本处理——把 grep/sort/uniq 变成你的分析工具Linux 基础 04:权限与属主——rwx 在文件和目录上不是一回事Linux 基础 03:ls、cp、mv、rm 的真实语义,以及那个由 shell 展开的 *Linux 基础 02:/ 底下为什么是这些目录,inode 里到底存了什么Linux 基础 01:终端、Shell,和命令是怎么被找到的
九位权限的真正含义、为什么"能删掉自己没写权限的文件"、"ls 看得到名字却读不了内容"的原因、umask 的算法、粘滞位保护了什么,以及 setuid 是怎么把 passwd 变提权入口的。

这一节要解决什么

很多人对权限的理解停在“chmod 777 就能解决”。但真实现场里最常见的 403 不是权限不够,而是某一级目录缺了 x;最常见的误解是“我没有这个文件的写权限,怎么可能删掉它”。这两个问题只有一个解释:rwx 在文件上和目录上是两套语义。

一、九位权限:三种身份 × 三组权限

ls -l /etc/passwd /tmp /usr/bin/passwd; stat -c '%a %A %U:%G %n' /etc/passwd /tmp
-rw-r--r--  1 root root 2612 ... /etc/passwd
drwxrwxrwx   9 root root 4096 ... /tmp        ← 真的 777 吗?继续看粘滞位
位含义数字
r读4
w写2
x执行 / 穿过1

三组分别是属主(u)/ 属组(g)/ 其他(o)。改权限两种写法:chmod 644 f(数字)或 chmod u+x,g-w,o=r f(符号)。我平时用数字看结果、用符号做增量修改:

chmod 640 secret.txt            # 属主读写,属组只读,其他人无权
chmod u+x script.sh             # 只给属主加执行位
chmod -R o-rwx /srv/private     # 递归去掉其他人的一切权限
chmod --reference=a.txt b.txt   # 抄 a 的权限
umask -S                        # 看当前 umask 的符号形式

二、核心:rwx 在目录上完全不同

文件上:r 读内容、w 改内容、x 可执行。 目录上:r 列举目录项(ls)、w 增删改目录项(改名、删除、新建)、x 穿过/进入(cd、访问子项)。

这三种能力可以互相独立,于是出现了两个经典现象:

mkdir -p t/sub; echo hi > t/sub/f
chmod 400 t        # 目录: r-- 
ls t               # ✅ 能看到名字(r 够用)
cat t/sub/f        # ❌ Permission denied(没有 x,穿不过去)
chmod 100 t        # 目录: --x
ls t               # ❌ 不能列举(没有 r)
cat t/sub/f        # ✅ 知道确切路径就能读(x 够用)

我的批注:第一条是排障的钥匙。很多“网页 403”“打开某目录报 Permission denied”都是路径上某一级目录缺 x——哪怕目标文件本身是 644。排查时从 / 开始逐级 namei -l <路径>:

namei -l /srv/www/site/public/index.html

第二条更反直觉:能不能删掉一个文件,取决于父目录的 w+x,跟文件自己的权限无关。

mkdir d; echo secret > d/f; sudo chown root:root d/f; chmod 444 d/f
ls -l d/f              # -r--r--r--  ← 你自己没有写权限
rm d/f                 # ✅ 照样删得掉(因为 d 属于你,且可写可穿)

rm 动的是目录项,不是文件内容——这就是第 02 篇“文件名属于目录”的实际后果。

三、umask:新建文件/目录的默认权限

新建时的规则是减(按位取反后再与):

文件:666 & ~umask
目录:777 & ~umask
umask            # 常见 0022
umask 027 ; touch f ; mkdir d ; stat -c '%a %n' f d     # 文件 640,目录 750
umask 077 ; touch f2 ; mkdir d2 ; stat -c '%a %n' f2 d2 # 文件 600,目录 700

注意两个例外:cp -p、cp -a、mv 保留源权限,不受 umask 影响;chmod 更是直接覆盖。

真实场景:ssh 私钥必须收紧到 600,否则连接直接被拒。

chmod 600 ~/.ssh/id_rsa
ssh -i ~/.ssh/id_rsa host   # @@@ WARNING: UNPROTECTED PRIVATE KEY FILE! 消失

四、三个特殊位:setuid、setgid、sticky

ls -l /usr/bin/passwd   # -rwsr-xr-x  ← 属主执行位变成 s
stat -c '%a %n' /tmp    # 1777 → 末位的 1 就是 sticky
位数字作用典型场景
setuid4执行时把有效 UID 换成文件属主/usr/bin/passwd 需要改 /etc/shadow(普通用户本无权),靠 setuid root 完成
setgid2文件:执行时有效 GID 换成文件属组;目录:新建文件继承目录的属组团队共享目录 chmod g+s /srv/team
sticky1目录内文件只有属主/目录属主/root 能删/tmp 是 1777,谁都能写,但不能删别人的文件
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort

两个必须知道的坑

  1. shell 脚本的 setuid 位会被内核忽略——所以“给脚本加 setuid 实现提权”在 Linux 上不成立(#!/bin/sh 的脚本 setuid 无效)。真要这样做事,用二进制程序或 sudo 规则。
  2. 自定义 setuid 程序就是提权入口。上面那条 find -perm -4000 列出来的东西值得定期过一眼:多出来的那个,往往是有人装了什么。

五、属主与属组

sudo chown alice file                  # 改属主
sudo chown alice:devs file             # 同时改属主与属组
sudo chown -R alice:devs /srv/app      # 递归(⚠️ 会一路改下去,先 namei -l 看清范围)
sudo chown --reference=/srv/app /srv/app2

批注:chown -R 是最容易造成事故的递归操作之一——/srv/app 里如果挂了别的用户的数据(或者你写错成 /),影响面立刻扩散。我现在固定先 find /srv/app -maxdepth 1 -printf '%u:%g %p\n' 看一眼再动手。

六、三个真实故障的定位顺序

现象真正原因检查命令
网页 403,文件本身是 644路径上某一级目录缺 xnamei -l /srv/www/.../index.html
ssh 报 UNPROTECTED PRIVATE KEY FILE / bad permissions私钥权限过宽;或家目录/.ssh 被其他用户可写(StrictModes)chmod 700 ~ ~/.ssh; chmod 600 ~/.ssh/id_*
“我在这个目录里改不了文件”有 x 没有 w,只能穿过不能改目录项ls -ld .、stat -c '%a %n' .

七、动手清单

mkdir -p t/sub; echo hi > t/sub/f
chmod 400 t; ls t; cat t/sub/f          # 1. r 能列、无 x 不能穿
chmod 100 t; ls t 2>&1 | head -1; cat t/sub/f   # 2. x 能穿、无 r 不能列
chmod 755 t; namei -l t/sub/f           # 3. 逐级看权限
mkdir d; echo x > d/f; chmod 444 d/f; rm d/f    # 4. 删除看父目录
umask; umask -S                         # 5. 默认权限从哪来
ls -l /usr/bin/passwd; stat -c '%a %n' /tmp      # 6. s 位与 sticky
sudo find / -xdev -perm -4000 -type f 2>/dev/null | sort   # 7. setuid 审计

小结

  • 目录的 r/w/x = 列举 / 改目录项 / 穿过;删除文件看父目录权限,不看文件自身。
  • namei -l 是"逐级看权限"的主力工具,专治 403。
  • umask 是"从 666/777 里减掉";cp -p / mv 不受它影响。
  • setuid 换有效 UID、setgid 让新文件继承属组、sticky 保护 /tmp;脚本的 setuid 位无效。
  • 权限问题的排查顺序永远是:路径每一级的 x → 目标文件权限 → 属主/属组是否匹配运行身份。

下一节预告

下一节转向文本:grep、sort、uniq、cut、tr——为什么它们组合起来能顶替大部分“手写小工具”,以及“流式思维”:数据一次只过一个管道,不做中间文件。

执笔 手写

喜欢的话,留下你的评论吧~

加载中...