阶段三 · 文件与系统命令

权限管理

1. Linux 权限模型

Linux 权限系统回答三个问题: 可以对什么文件什么操作.

谁(Who)          什么文件(What)        什么操作(How)
───────── ────────────── ──────────────
所有者(owner) 普通文件 r = 读(read)
所属组(group) 目录 w = 写(write)
其他人(others) 符号链接 x = 执行(execute)
设备文件

"其他人" 的含义: 不是 owner,也不在文件的 group 中的任何用户. root 是例外--内核对 root 的权限检查是特殊处理的.

文件 vs 目录的 rwx 含义

同一个字母 r,对文件和目录含义不同:

权限 对文件 对目录
r 可以读取文件内容(cat/open) 可以列出目录内容(ls)
w 可以修改文件内容 可以在目录中创建/删除文件
x 可以作为程序执行 可以进入目录(cd)或访问目录内文件

最常见的困惑: 目录的 x 权限

对目录有 r 但没有 x: 能 ls 看到文件名,但读不了文件内容,进不了子目录.
对目录有 x 但没有 r: 能 cd 进去,能访问已知名字的文件,但不能 ls 列出有哪些文件.

权限检查顺序是: 先 x(能否进入目录),再 r(能否列出),最后检查文件自身的 rwx.

2. 读懂权限字符串

$ ls -l
-rw-r--r-- 1 yutong staff 18844 Jun 10 10:21 index.html
drwxr-xr-x 2 yutong staff 64 Jun 11 09:30 terminal/
lrwxr-xr-x 1 yutong staff 12 Jun 12 10:00 link -> target

-rw-r--r-- 为例,10 个字符分 4 组:

-  rw-  r--  r--
1 234 567 890
含义
1 文件类型 - 普通文件,d 目录,l 符号链接
2-4 所有者(owner) 权限 rw- = 可读可写不可执行
5-7 所属组(group) 权限 r-- = 只读
8-10 其他人(others) 权限 r-- = 只读
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root wheel 168448 Jan 1 2024 /usr/bin/passwd*
# ↑ 注意这个 s--setuid 位,后面会讲

$ ls -l /tmp
drwxrwxrwt 8 root wheel 256 Jun 15 10:00 /tmp/
# ↑ 注意末尾的 t--sticky bit

3. chmod: 修改权限(符号模式)

chmod(change mode)修改文件的权限位. 符号模式用字母表达意图--最直观的学习方式.

谁(who) 操作 权限
u = user(所有者) + 添加 r
g = group(所属组) - 移除 w
o = others(其他人) = 精确设为 x 执行
a = all(以上三者)
$ chmod u+x script.sh        # 所有者加执行权限:-rw-r--r-- → -rwxr--r--
$ chmod g-w report.txt # 组去掉写权限:-rw-rw-r-- → -rw-r--r--
$ chmod o-rwx secret.txt # 其他人全部禁止:-rwxr-xr-x → -rwxr-x---
$ chmod a+r public.html # 所有人加读:---------- → -r--r--r--
$ chmod ug+x deploy.sh # 所有者+组加执行

# 可以一次设多组
$ chmod u=rwx,g=rx,o= app # 所有者 rwx,组 rx,其他人无权限

4. chmod: 八进制模式

符号模式直观但啰嗦. 日常更多用八进制(octal)--三位数字,一位对应一组权限. 这正是 chmod 755, chmod 644 的由来.

4.1 八进制速算表

每组的 rwx 三个位正好对应 3 个二进制位,一个八进制数字完美表达:

r  w  x     二进制     八进制     含义
───────── ────── ────── ──────────
- - - 0 0 0 0 无权限
- - x 0 0 1 1 仅执行
- w - 0 1 0 2 仅写
- w x 0 1 1 3 写+执行
r - - 1 0 0 4 仅读
r - x 1 0 1 5 读+执行
r w - 1 1 0 6 读+写
r w x 1 1 1 7 全部权限

八进制权限就像三段密码锁--第一段设给 owner,第二段给 group,第三段给 others.
每段是一个 0-7 的数字.
不需要每次做二进制换算,记住三个就够了: 7(全开), 5(读+执行), 4(只读).

4.2 常用组合

八进制 符号等价 适用场景
755 rwxr-xr-x 可执行文件/脚本,目录
644 rw-r--r-- 普通文件(自己可写,别人只读)
700 rwx------ 私密脚本/SSH 密钥
600 rw------- 私密数据文件(~/.ssh/id_rsa)
777 rwxrwxrwx 几乎绝对不要用--任何人都能修改
000 --------- 临时锁定文件(只有 root 能改)
$ chmod 755 deploy.sh        # 自己全权限,别人可读可执行
$ chmod 644 README.md # 自己可写,别人只读
$ chmod 600 ~/.ssh/id_rsa # SSH 私钥必须 owner-only
$ chmod -R 755 public/ # 递归修改整个目录

chmod 777 是核按钮

chmod 777任何用户都可以读, 写, 执行这个文件. 在多用户服务器上,这意味着任何人都可以篡改或删除文件. 如果看到网上教程让用 chmod 777,停下来想一秒--真的需要 world-writable 吗? 大多数情况 755644 就够了.

5. chown 与 chgrp: 修改归属

$ chown alice file.txt        # 改所有者为 alice
$ chown alice:staff file.txt # 同时改所有者和组
$ chown :staff file.txt # 只改组(保留原所有者)
$ chgrp staff file.txt # 等价于 chown :staff

$ chown -R alice:staff dir/ # 递归修改整个目录

只有 root 能 chown--普通用户不能把自己的文件送给别人. 这是安全限制: 不能创建一个恶意 setuid 程序然后把所有者改成 root.

macOS 与 Linux 的差异

macOS 的 chownuser:group 语法上行为不一致,建议用 chown user file; chgrp group file 分两步,或直接用完整路径 chown user:staff file(在 macOS 上 staff 是默认用户组).

6. umask: 新文件的默认权限

当创建新文件时,权限不是随便给的. 系统用 umask(权限掩码)从 "最大允许权限" 中扣除一些位,得到新文件的默认权限.

$ umask             # 查看当前 umask
022 # 最常见的值

$ touch newfile # 新文件默认是 666 - umask = 644
$ ls -l newfile
-rw-r--r-- 1 yutong staff 0 Jun 15 10:00 newfile

$ mkdir newdir # 新目录默认是 777 - umask = 755
$ ls -ld newdir
drwxr-xr-x 2 yutong staff 64 Jun 15 10:00 newdir/
umask 值 新文件权限 新目录权限
022 644 (rw-r--r--) 755 (rwxr-xr-x)
002 664 (rw-rw-r--) 775 (rwxrwxr-x)
077 600 (rw-------) 700 (rwx------)
$ umask 077          # 临时设为严格模式
$ touch newfile # 新文件只有 owner 可读写
$ ls -l newfile
-rw------- 1 yutong staff 0 Jun 15 10:00 newfile
$ umask 022 # 恢复

公式: 新文件权限 = 666 - umask(目录是 777 - umask). umask 的每一位 "扣除" 对应的权限: 022 扣掉 group 和 others 的写权限(w=2),让 group 和 others 只能读.

7. 特殊权限位

除了 rwx,Linux 还有三个特殊位. 日常不常用,但理解它们能解决很多 "为什么这个命令能工作" 的疑惑.

7.1 setuid(SUID) = 4xxx

当文件设置了 setuid 位,执行这个文件时,进程以文件所有者的身份运行,而不是以执行者的身份.

$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root wheel 168448 Jan 1 2024 /usr/bin/passwd*
# ↑ owner 的 x 位置变成 s → setuid

$ ls -l /usr/bin/sudo
---s--x--x 1 root wheel 2365888 Jan 1 2024 /usr/bin/sudo*
# ↑ 即使 owner 没有 r/w,s 仍然表示 setuid + x

普通用户执行 passwd 时,进程以 root 身份运行--所以它能修改 /etc/shadow(密码文件,只有 root 可写). 这就是 passwdsudo 不需要 root 登录就能提权的原因.

7.2 setgid(SGID) = 2xxx

可执行文件: 进程以文件所属组的身份运行.

目录: 在该目录下创建的新文件,自动继承目录的组(而不是创建者的默认组).

$ ls -ld /usr/local/share/
drwxrwsr-x 3 root staff 96 Jun 10 10:00 /usr/local/share/
# ↑ group 的 x 位置变成 s → setgid

# 目录 setgid 的实际用途:共享项目目录
$ mkdir shared && chgrp dev-team shared && chmod 2770 shared
# 此后任何人在 shared/ 下创建文件,组都是 dev-team

7.3 sticky bit = 1xxx

只能用于目录. 设置了 sticky bit 的目录中,只有文件所有者和 root 能删除文件--即使目录是 world-writable.

$ ls -ld /tmp
drwxrwxrwt 8 root wheel 256 Jun 15 10:00 /tmp/
# ↑ others 的 x 位置变成 t → sticky bit

# 为什么 /tmp 需要 sticky bit
$ ls -l /tmp
-rw------- 1 alice wheel 0 Jun 15 10:00 alice_file
-rw------- 1 bob wheel 0 Jun 15 10:00 bob_file
# alice 不能删 bob_file(即使 /tmp 是 777),bob 也不能删 alice_file

如果没有 sticky bit,任何人(因为 /tmp 是 777)都能删除别人的临时文件--这在多用户系统上会是一场灾难.

特殊位总结

八进制 名称 哪里出现 效果
4 setuid (SUID) owner 的 x 位 → s 以文件所有者身份运行
2 setgid (SGID) group 的 x 位 → s 文件: 以组身份运行; 目录: 新文件继承组
1 sticky bit others 的 x 位 → t 只有文件所有者能删除
# 设置特殊位的八进制写法(四位数字,首位是特殊位)
$ chmod 4755 script.sh # setuid + 755 → -rwsr-xr-x
$ chmod 2755 dir/ # setgid + 755 → drwxr-sr-x
$ chmod 1777 /tmp # sticky + 777 → drwxrwxrwt

# 符号写法
$ chmod u+s script.sh # 加 setuid
$ chmod g+s dir/ # 加 setgid
$ chmod +t /tmp # 加 sticky

快速回顾

  • 权限三要素: (owner/group/others) x 什么操作(r/w/x). 文件与目录的 rwx 含义不同
  • ls -l 输出: -rwxr-xr-x = 类型 + owner x 3 + group x 3 + others x 3
  • chmod u+x / chmod g-w 用符号表达意图; chmod 755 用八进制快速设好
  • 记住三个八进制: 7(rwx 全开), 5(r-x 读+执行), 4(r-- 只读); 644 普通文件, 755 可执行/目录, 600 私密文件
  • chown alice:staff file 改归属; 只有 root 能 chown
  • umask 控制新文件的默认权限: 022 → 文件 644, 目录 755
  • setuid(4xxx) = 以文件所有者身份运行(如 passwd); setgid(2xxx) = 目录中新文件继承组; sticky bit(1xxx) = 只有所有者能删除(如 /tmp)

动手练习

  1. 查找特殊权限位: 运行 ls -l /bin /usr/bin /tmp ~/.ssh,找找有没有 s 和 t 标志位
  2. 符号模式练习: 创建 test.sh(内容 echo hello),用符号模式 chmod u+x 加执行,然后 ./test.sh 运行
  3. 八进制模式练习: 用 chmod 644 改回,再 chmod 755 加回--两种模式对比练习
  4. umask 实验: 运行 umask; touch a; ls -l a; rm a; umask 077; touch a; ls -l a,观察 umask 对新文件权限的影响
  5. sticky bit 含义: 检查 ls -ld /tmp--末尾的 t 是什么意思? 如果没有这个 t 会怎样?