跳转至

本文档中的所有示例都使用 root 用户进行操作,普通用户操作会单独注释。 在 markdown 代码块中,命令描述将在前一行用 # 表示。

查看基本权限

众所周知,GNU/Linux 的基本权限可以使用 ls -l 查看:

Shell > ls -l 
-  rwx  r-x  r-x  1  root  root    1358  Dec 31 14:50  anaconda-ks.cfg
↓                                                 1   2    3    4   5   6     7       8        9            10

其含义如下:

部分 描述
1 文件类型。 - 表示这是一个普通文件。 稍后将介绍七种文件类型。
2 所有者用户的权限,rwx 的含义分别是:读、写、执行。
3 所属组的权限。
4 其他用户的权限。
5 子目录数(包括 ...)。 对于一个文件,它表示硬链接的数量,1 表示文件本身。
6 所有者用户名称。
7 所属组名称。
8 对于文件,它显示文件的大小。 对于目录,它显示了文件命名占用的固定值 4096 字节。 要计算目录的总大小,请使用 du -sh
9 最后修改日期。
10 文件(或目录)的名称。

七种文件类型

文件类型 描述
- 表示一个普通文件。 包括纯文本文件(ASCII);二进制文件(binary);数据格式文件(data);各种压缩文件。
d 表示一个目录文件。 默认情况下,每个目录中都会有一个 ...
b 块设备文件。 包括各种硬盘、USB 驱动器等。
c 字符设备文件。 串口接口设备,如鼠标、键盘等。
s 套接字文件。 它是一个专门用于网络通信的文件。
p 管道文件。 它是一种特殊的文件类型,主要目的是解决多个程序同时访问一个文件所引起的错误。 FIFO 是 first-in-first-out 的缩写。
l 软链接文件,也称为符号链接文件,类似于 Windows 中的快捷方式。 硬链接文件,也称为物理链接文件。

基本权限的含义

对于文件:

数字表示 权限 描述
4 r(read) 表示您可以读取此文件。 您可以使用诸如 catheadmorelesstail 等命令。
2 w(write) 表示文件可以修改。 可以使用 vim 等命令。
1 x(execution) 可执行文件(如脚本或二进制文件)的权限。

对于目录:

数字表示 权限 描述
4 r(read) 表示可以列出目录的内容,例如 ls -l
2 w(write) 表示您可以在此目录中创建、删除和重命名文件,例如命令 mkdirtouchrm 等。
1 x(execute) 表示您可以进入到目录,例如命令 cd

信息

对于目录而言,rx 权限通常会同时出现。

特殊权限

在 GNU/Linux 中,除了上述基本权限外,还有一些特殊权限,我们将逐一介绍。

ACL 权限

Q:什么是 ACL?

ACL(Access Control List,访问控制列表),其目的是解决 Linux 下三种身份无法满足资源权限分配需求的问题。

例如,老师给学生们上课,而老师会在操作系统的根目录下创建一个目录。 只有这个班的学生可以上传和下载,其他人不允许。 此时,目录的权限为770。 有一天,一位来自另一所学校的学生来听这位老师的讲课,应该如何分配权限? 如果您将此学生放入到 所属组 中,他将拥有与此班学生相同的权限 - rwx。 若将学生放入到 其他用户 中,他将没有任何权限。 此时,基本权限分配无法满足要求,需要使用 ACL。

Windows 操作系统中也有类似的功能。 例如,要为用户分配文件的权限,对于用户定义的目录/文件,右键单击 ---> 属性 ---> 安全 ---> 编辑 ---> 添加 ---> 高级 ---> 立刻查找,查找相应的用户/组 ---> 分配特定权限 ---> 应用 并完成。

GNU/Linux 也是如此:将指定的用户/组添加到文件/目录中,并授予适当的权限以完成 ACL 权限分配。

Q:如何启用 ACL?

您需要找到挂载点所在设备的文件名及其分区号。 例如,在我的机器上,你可以这样做:

Shell > df -hT
Filesystem     Type      Size  Used  Avail Use% Mounted on
devtmpfs       devtmpfs  3.8G     0  3.8G    0% /dev
tmpfs          tmpfs     3.8G     0  3.8G    0% /dev/shm
tmpfs          tmpfs     3.8G  8.9M  3.8G    1% /run
tmpfs          tmpfs     3.8G     0  3.8G    0% /sys/fs/cgroup
/dev/nvme0n1p2 ext4       47G   11G   35G   24% /
/dev/nvme0n1p1 xfs      1014M  187M  828M   19% /boot
tmpfs          tmpfs     774M     0  774M    0% /run/user/0

Shell > dumpe2fs /dev/nvme0n1p2 | head -n 10
dumpe2fs 1.45.6 (20-Mar-2020)
Filesystem volume name:   <none>
Last mounted on:          /
Filesystem UUID:          c8e6206d-2892-4c22-a10b-b87d2447a885
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum
Filesystem flags:         signed_directory_hash 
Default mount options:    user_xattr acl
Filesystem state:         clean
Errors behavior:          Continue

当您看到行 "Default mount options: user_xattr acl", 时,表示 ACL 已启用。 若未启用,您也可以临时启用它 -- mount -o remount,acl /。 它也可以永久被启用:

Shell > vim /etc/fstab
UUID=c8e6206d-2892-4c22-a10b-b87d2447a885  /   ext4    defaults,acl        1 1

Shell > mount -o remount /
# 或者
Shell > reboot

查看和设置 ACL

要查看 ACL,您需要使用 getfacle 命令 -- getfacle FILE_NAME

如果你想设置 ACL 权限,你需要使用 setfacl 命令。

Shell > setfacl <option> <FILE_NAME>
选项 描述
-m 修改文件的当前 ACL
-x 从文件的 ACL 中删除条目
-b 删除所有扩展 ACL 条目
-d 操作应用于默认 ACL
-k 移除默认 ACL
-R 递归进入子目录

以本文开头所提及的老师的例子为例,来说明 ACL 的使用方法。

# 老师是根用户
Shell > groupadd class1
Shell > mkdir /project
Shell > chown root:class1 /project
Shell > chmod 770 /project
Shell > ls -ld /project/
drwxrwx--- 2 root class1 4096 Jan  12 12:58 /project/

# 把班上的学生分配到 class1 组中
Shell > useradd frank
Shell > passwd frank
Shell > useradd aron
Shell > passwd aron
Shell > gpasswd -a frank class1
Shell > gpasswd -a aron class1

# 一个来自另一所学校的学生来听老师讲课
Shell > useradd tom
Shell > passwd tom
# 如果是一个组,这里的 "u" 应该替换为 "g"
Shell > setfacle -m u:tom:rx  /project

# 输出消息中添加了 "+" 符号
Shell > ls -ld /project/
drwxrwx---+ 2 root class1 4096 Jan  12 12:58 /project/

Shell > getfacl -p /project/
# file: /project/
# owner: root
# group: class1
user::rwx
user:tom:r-x
group::rwx
mask::rwx
other::---

ACL 的最大有效权限

Q: 当使用 getfacl 命令时,输出消息中的 "mask:: rwx" 是什么意思?

mask 用于指定最大有效权限。 授予用户的权限并非真正的权限,真正的权限只能通过将用户的权限与掩码权限进行 "逻辑与" 运算来获得。

信息

"逻辑与" 含义:如果都为真,则结果为真;若有一个假,则结果为假。

用户设置的权限 Mask 权限 结果
r r r
r - -
- r -
- - -

信息

因为默认 mask 是 rwx,所以对于任何用户的 ACL 权限,结果都是用户自身的权限。

您还可以调整 mask 权限:

Shell > setfacl -m u:tom:rwx /project
Shell > setfacl -m m:rx /project

Shell > getfacl  -p /project/
# file: project/
# owner: root
# group: class1
user::rwx
user:tom:rwx                    #effective:r-x
group::rwx                      #effective:r-x
mask::r-x
other::---

删除 ACL 权限

# 删除指定目录中用户/组的 ACL 权限
Shell > setfacl -x u:USER_NAME FILE_NAME
Shell > setfacl -x g:GROUP_NAME FILE_NAME

# 删除指定目录的所有 ACL 权限
Shell > setfacl -b FILE_NAME

ACL 权限的默认和递归

Q:ACL权限的递归是什么?

对于 ACL 权限,这意味着当父目录设置 ACL 权限时,所有子目录和子文件将具有相同的 ACL 权限。

信息

递归适用于目录中已存在的文件/目录。

请看以下示例:

Shell > setfacl -m m:rwx /project
Shell > setfacl -m u:tom:rx /project

Shell > cd /project
Shell > touch file1 file2
# 因为没有递归,所以这里的文件没有 ACL 权限。 
Shell > ls -l
-rw-r--r-- 1 root root 0 Jan  12 14:35 file1
-rw-r--r-- 1 root root 0 Jan  12 14:35 file2

Shell > setfacl -m u:tom:rx -R /project
Shell > ls -l /project
-rw-r-xr--+ 1 root root 0 Jan  12 14:35 file1
-rw-r-xr--+ 1 root root 0 Jan  12 14:35 file2

Q:如果我在此目录中创建一个新文件,它是否具有 ACL 权限?

答案是否定的,因为新创建的文件是在执行命令 setfacl-m u:tom:rx -R /project 之后完成的。

Shell > touch /project/file3
Shell > ls -l /project/file3
-rw-r--r-- 1 root root 0 Jan  12 14:52 /project/file3

如果您希望新创建的目录/文件也具有 ACL 权限,则需要使用默认 ACL 权限。

Shell > setfacl -m d:u:tom:rx  /project
Shell > cd /project && touch file4 && ls -l 
-rw-r-xr--+ 1 root root 0 Jan  12 14:35 file1
-rw-r-xr--+ 1 root root 0 Jan  12 14:35 file2
-rw-r--r--  1 root root 0 Jan  12 14:52 file3
-rw-rw----+ 1 root root 0 Jan  12 14:59 file4

Shell > getfacl -p /project
# file: /project
# owner: root
# group: class1
user::rwx
user:tom:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:tom:r-x
default:group::rwx
default:mask::rwx
default:other::---

信息

使用 ACL 权限的默认和递归要求命令的操作对象是目录! 如果操作对象是文件,将输出错误提示。

SetUID

"SetUID" 的规则:

  • 只有可执行二进制文件可以设置 SUID 权限。
  • 命令的执行者应该对程序具有 x 权限。
  • 命令的执行者在执行程序时获得程序文件所有者的身份。
  • 身份变更仅在执行期间有效,一旦二进制程序完成,执行者的身份将恢复为原始身份。

Q:为什么 GNU/Linux 需要如此奇怪的权限?

以最常见的 passwd 命令为例:

SetUID1

如您所见,普通用户只有 r 和 x,但所有者的 x 变为 s,证明 passwd 命令具有 SUID 权限。

众所周知,普通用户(uid >= 1000)可以更改自己的密码。 真实密码存储在 /etc/shadow 文件中,但 shadows 文件的权限为 000,普通用户没有任何权限。

Shell > ls -l /etc/shadow
---------- 1 root root 874 Jan  12 13:42 /etc/shadow

由于普通用户可以更改密码,所以他们必须将密码写入到 /etc/shadow 文件中。 当普通用户执行 passwd 命令时,它将临时更改为文件的所有者 -- root。 对于 shadow 文件而言,root 不受权限限制。 这就是为什么 passwd 命令需要 SUID 权限。

如前所述,基本权限可以用数字表示,如 755、644 等。 SUID 用 4 进行表示。 对于可执行的二进制文件,您可以这样设置权限 -- 4755

# 设置 SUID 权限
Shell > chmod 4755 FILE_NAME
# 或者
Shell > chmod u+s FILE_NAME

# 移除 SUID 权限
Shell > chmod 755 FILE_NAME
# 或者
Shell > chmod u-s FILE_NAME

Warning

当可执行二进制文件/程序的所有者没有 x 时,使用大写 S 意味着该文件不能使用 SUID 权限。

# 假设这是一个可执行的二进制文件
Shell > vim suid.sh
#!/bin/bash
cd /etc && ls

Shell > chmod 4644 suid.sh

SUID2

Warning

因为 SUID 可以临时将普通用户更改为 root,所以在维护服务器时,您需要特别小心具有此权限的文件。 您可以使用以下命令查找具有 SUID 权限的文件:

Shell > find / -perm -4000 -a -type f -exec ls -l  {} \;

SetGID

"SetGID" 的规则:

  • 只有可执行二进制文件可以设置 SGID 权限。
  • 命令的执行者应该对程序具有 x 权限。
  • 执行程序时命令的执行者获取程序文件所属组的身份。
  • 身份变更仅在执行期间有效,一旦二进制程序完成,执行者的身份将恢复为原始身份。

locate 命令为例:

Shell > rpm -ql mlocate
/usr/bin/locate
...
/var/lib/mlocate/mlocate.db

Shell > ls -l /var/lib/mlocate/mlocate.db
-rw-r----- 1 root slocate 4151779 1月  14 11:43 /var/lib/mlocate/mlocate.db

Shell > ll /usr/bin/locate 
-rwx--s--x. 1 root slocate 42248 4月  12 2021 /usr/bin/locate

locate 命令使用 mlocate.db 数据库文件快速搜索文件。

由于 locate 命令具有 SGID 权限,当执行者(普通用户)执行 locate 命令时,所属组会切换为 slocateslocate/var/lib/mlocate/mlocate.db 文件具有 r 权限。

SGID 的表示方式为数字 2,因此 locate 命令的权限为 2711。

# 设置 SGID 权限
Shell > chmod 2711 FILE_NAME
# 或者
Shell > chmod g+s FILE_NAME

# 移除 SGID 权限
Shell > chmod 711 FILE_NAME
# 或者
Shell > chmod g-s FILE_NAME

Warning

当可执行二进制文件/程序的所属组没有 x 时,使用大写 S 表示无法正确使用该文件的 SGID 权限。

# 假设这是一个可执行的二进制文件
Shell > touch sgid

Shell > chmod 2741 sgid
Shell > ls -l sgid
-rwxr-S--x  1 root root         0 Jan  14 12:11 sgid

SGID 不仅可以用于可执行二进制文件/程序,还可以用于目录,但很少使用。

  • 普通用户必须对目录具有 rwx 权限。
  • 对于普通用户在此目录中创建的文件,默认的所属组是目录的所属组。

例如:

Shell > mkdir /SGID_dir
Shell > chmod 2777 /SGID_dir
Shell > ls -ld /SGID_dir
drwxrwsrwx  2 root root      4096 Jan 14 12:17 SGID_dir

Shell > su - tom
Shell(tom) > cd /SGID_dir && touch tom_file && ls -l
-rw-rw-r-- 1 tom root 0 Jan  14 12:26 tom_file

Warning

由于 SGID 可以临时将普通用户的所属组更改为 root,因此在维护服务器时需要特别注意具有此权限的文件。 您可以通过以下命令找到具有 SGID 权限的文件:

Shell > find / -perm -2000 -a -type f -exec ls -l  {} \;

Sticky BIT

"Sticky BIT" 的规则:

  • 仅对目录有效。
  • 普通用户对此目录具有 w 和 x 权限。
  • 如果没有 Sticky Bit ,拥有 w 权限的普通用户可以删除此目录中的所有文件(包括其他用户创建的文件)。 一旦目录被授予了 SBIT 权限,只有 root 用户可以删除所有文件。 即使普通用户有 w 权限,他们只能删除自己创建的文件(其他用户创建的文件不能删除)。

SBIT 用数字 1 表示。

# 为目录设置 SBIT 权限
Shell > chmod 1777 DIR
# 或者
Shell > chmod o+t DIR

# 从目录中移除 SBIT 权限
Shell > chmod 777 DIR
# 或者
Shell > chmow o-t DIR

Q:文件或目录可以有 7755 权限吗?

不, 它们针对的是不同的对象。 SUID 用于可执行二进制文件;SGID 用于可执行二进制文件和目录;SBIT 仅适用于目录。 也就是说,您需要根据不同的对象设置这些特殊权限。

目录 /tmp 具有 SBIT 权限。 以下是一个示例:

# /tmp 目录的权限为 1777
Shell > ls -ld /tmp
drwxrwxrwt. 8 root root 4096 Jan  14 12:50 /tmp

Shell > su - tom 
Shell > cd /tmp && touch tom_file1 
Shell > exit

Shell > su - jack 
Shell(jack) > cd /tmp && rm -rf tom_file1
rm: cannot remove 'tom_file1': Operation not permitted
Shell(jack) > exit

# 文件已被删除
Shell > su - tom 
Shell(tom) > rm -rf /tmp/tom_file1

信息

root(uid=0)用户不受 SUID、SGID 和 SBIT 权限的限制。

chattr

chattr 权限的功能:用于保护系统中的重要文件或目录不被误操作删除。

chattr 命令的用法 - chattr [ -RVf ] [ -v version ] [ -p project ] [ mode ] files...

符号模式的格式为 +-=[aAcCdDeFijPsStTu]。

  • "+" 表示增加权限;
  • "-" 表示减少权限;
  • "=" 表示等于权限。

最常用的权限(也称为属性)是 ai

属性 i 的描述

删除 自由修改 追加文件内容 查看 创建文件
文件 × × × -
目录 x
(目录和目录下的文件)
路径
(目录中的文件)
路径
(目录中的文件)
路径
(目录中的文件)
×

文件示例:

Shell > touch /tmp/filei
Shell > vim /tmp/filei
123

Shell > chattr +i /tmp/filei
Shell > lsattr -a /tmp/filei
----i---------e----- /tmp/filei

Shell > rm -rf /tmp/filei
rm: cannot remove '/tmp/filei': Operation not permitted

# 不能自由修改
Shell > vim /tmp/file1

Shell > echo "adcd" >> /tmp/filei 
-bash: /tmp/filei: Operation not permitted

Shell > cat /tmp/filei
123

目录示例:

Shell > mkdir /tmp/diri
Shell > cd /tmp/diri && echo "qwer" > f1

Shell > chattr +i /tmp/diri
Shell > lsattr -ad /tmp/diri
----i---------e----- /tmp/diri

Shell > rm -rf /tmp/diri
rm: cannot remove '/tmp/diri/f1': Operation not permitted

# 允许修改
Shell > vim /tmp/diri/f1
qwer-tom

Shell > echo "jim" >> /tmp/diri/f1
Shell > cat /tmp/diri/f1
qwer-tom
jim

Shell > touch /tmp/diri/file2
touch: settng time of '/tmp/diri/file2': No such file or directory

从上面的示例中删除 i 属性:

Shell > chattr -i /tmp/filei /tmp/diri

属性 a 的描述

删除 自由修改 追加文件内容 查看 创建文件
文件 × × -
目录 x
(目录和目录下的文件)
x
(目录中的文件)
路径
(目录中的文件)
路径
(目录中的文件)

文件示例:

Shell > touch /etc/tmpfile1
Shell > echo "zxcv" > /etc/tmpfile1

Shell > chattr +a /etc/tmpfile1
Shell > lsattr -a /etc/tmpfile1
-----a--------e----- /etc/tmpfile1

Shell > rm -rf /etc/tmpfile1
rm: cannot remove '/etc/tmpfile1': Operation not permitted

# 不能自由修改
Shell > vim /etc/tmpfile1

Shell > echo "new line" >> /etc/tmpfile1
Shell > cat /etc/tmpfile1
zxcv
new line

目录示例:

Shell > mkdir /etc/dira
Shell > cd /etc/dira && echo "asdf" > afile

Shell > chattr +a /etc/dira
Shell > lsattr -ad /etc/dira
-----a--------e----- /etc/dira/

Shell > rm -rf /etc/dira
rm: cannot remove '/etc/dira/afile': Operation not permitted

# 自由修改不被允许
Shell > vim /etc/dira/afile
asdf

Shell > echo "new line" >> /etc/dira/afile
Shell > cat /etc/dira/afile
asdf
new line

# 允许创建新文件
Shell > touch /etc/dira/newfile

从上面的示例中删除 a 属性:

Shell > chattr -a /etc/tmpfile1 /etc/dira/

问题

Q:当我对文件设置 ai 属性时会发生什么

你除了查看文件外,无法对文件进行任何操作。

Q:关于目录呢?

允许的包括:自由修改、追加文件内容和查看。 不允许:删除和创建文件。

sudo

"sudo" 的规则:

  • 通过 root 用户,将只能由 root 用户(uid=0)执行的命令分配给普通用户执行。
  • "sudo" 的操作对象是系统命令。

我们知道,在 GNU/Linux 操作系统中,只有管理员 root 用户才有权限使用位于 /sbin//usr/sbin/ 目录中的命令。 一般来说,一家公司会有一个团队来维护一组服务器。 这组服务器系统既可以指一个地理位置内的单个机房,也可以指多个地理位置内的机房。 团队负责人使用 root 用户的权限,而其他团队成员可能只有普通用户的权限。 由于负责人工作量很大,没有时间维护服务器的日常工作,因此大部分工作需要由普通用户来完成。 然而,普通用户在使用命令时有很多限制,此时就需要使用 sudo 权限。

若要向普通用户授予权限,您必须使用 root 用户(uid=0)

您可以通过使用 visudo 命令来提升普通用户的权限,实际上您所修改的是 /etc/sudoers 文件。

Shell > visudo
...
88 Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
89 
90 ## Next comes the main part: which users can run what software on
91 ## which machines (the sudoers file can be shared between multiple
92 ## systems).
93 ## Syntax:
94 ##
95 ##      user    MACHINE=COMMANDS
96 ##
97 ## The COMMANDS section may have other options added to it.
98 ##
99 ## Allow root to run any commands anywhere
100 root    ALL=(ALL)       ALL
                               1       2    3          4
...
部分 描述
1 用户名或所属组名。 指被授予权限的用户或组。 如果是所属组,则需要写入 "%",例如 %root
2 哪些机器可以执行命令。 它可以是单个 IP 地址、网段或 ALL。
3 表示可以转换为哪些身份。
4 一个或多个授权命令(以绝对路径表示)。 多个授权命令需要用逗号分隔。

例如:

Shell > visudo
...
101 tom  ALL=/sbin/shutdown  -r now 
...

# 您可以使用 "-c" 选项检查 /etc/sudoers 编写中的错误。
Shell > visudo -c

Shell > su - tom
# 查看可用的 sudo 命令。
Shell(tom) > sudo -l

# 要使用可用的 sudo 命令,普通用户需要在命令前添加 sudo 。
Shell(tom) > sudo /sbin/shutdown -r now

如果您的授权命令是 /sbin/shutdown,则意味着授权用户可以使用该命令的任何选项。

Warning

由于 sudo 是一种 "提升用户权限" 的操作,所以在处理 /etc/sudoers 文件时必须极其谨慎!

由于 sudo 初始设计时的各种原因(如设计复杂、功能冗余、历史负担重等),目前的 sudo 发现了许多高风险漏洞:

  • ‌CVE-2019-14287
  • ‌CVE-2021-3156
  • ‌CVE-2025-32462
  • ‌CVE-2025-32463

您可以使用 Rust 版本的 sudo 作为替代方案。 有关更多详细信息,请参阅 此处

Author: tianci li

Contributors: Serge, Ganna Zhyrnova