文件权限
Linux 系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux 系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。在 Linux 中我们可以使用 ll
命令或者 ls –l
命令来显示一个文件的属性以及对应的文件权限,如:
[root@localhost vincent]# ll
total 96
-rw-rw-r-- 1 vincent vincent 40960 Apr 17 21:12 doucument.tar
drwxrwxr-x 3 vincent vincent 4096 Mar 13 15:28 package
-rw-rw-r-- 1 vincent vincent 53 Mar 7 09:14 result1
-rw-rw-r-- 1 vincent vincent 107 Mar 7 09:20 result2
-rw-rw-r-- 1 vincent vincent 664 Mar 9 17:06 result3
-rwxrw-r-- 1 vincent vincent 49 Mar 2 15:45 script1
-rwxrw-r-- 1 vincent vincent 85 Mar 5 13:49 test2
-rwxrw-r-- 1 vincent vincent 109 Mar 5 14:27 test3
-rw-rw-r-- 1 vincent vincent 41 Mar 13 09:55 test3.txt
-rwxrw-r-- 1 vincent vincent 119 Mar 6 16:18 test4
-rw-rw-r-- 1 vincent vincent 64 Mar 1 21:00 test.txt
文件都有一个特定的所有者,也就是对该文件具有所有权的用户。同时,在 Linux 系统中,用户是按组分类的,一个用户属于一个或多个组。文件所有者以外的用户又可以分为文件所有者的同组用户和其他用户。因此,Linux 系统按文件所有者、文件所有者同组用户和其他用户来规定了不同的文件访问权限。 每个文件的属性由左边第一部分的 10 个字符来确定(如下图)。
示例中,文件的第一个属性表示文件类型,所有可用的值如下:
- 当为 [d] 则表示目录。
- 当为 [-] 则表示文件。依照文件的内容,Linux 下的文件又大略可以分为:
- 二进制文件(binary file):以纯二进制形式存储的文件。像 ls、cat 等可执行的命令,以及压缩文件都是二进制文件。可以以十六进制的形式查看文件的二进制内容。一般固定类型的二进制文件都有其特定的文件签名头,可以根据文件签名头来确定二进制文件的实际类型(根据文件名中类型后缀区分文件类型一点也不靠谱,因为文件类型后缀是可以随意修改的,仅用于表明其文件类型)。
- 文本文件(text file):文本文件虽然最终也是按也是按二进制存储的,但其内容是我们人类可以直接读到的数据,例如数字、字母等等。几乎只要我们可以用来做为设置的文件都属于这一种文件类型。
- 数据文件(data file):有些程序在运作的过程当中会读取某些特定格式的文件,那些特定格式的文件可以被称为数据文件(data file)。举例来说,我们的 Linux 在使用者登入时,都会将登录的数据记录在
/var/log/wtmp
那个文件内,该文件就是一个数据文件,可以通过last
指令读取该文件,但是使用 cat 读取该文件内容时会出现乱码,因为它是一种特殊格式的文件。
除了以上常规类型以外,还有以下特殊文件类型:
- 若是 [l] 则表示为符号链接(symbolic link file)。类似 Windows 系统中的快捷方式。更多解释请参考
ln
命令的文档; - 若是 [b] 则表示块文件(block file)。块文件表示与储存相关的一些设备文件,提供系统随机存取的接口设备,比如硬盘与软盘等。此类文件通常都集中在
/dev
这个目录中。比如,执行ls -l /dev/sd*
命令会发现第一个属性为 [b]。 - 若是 [c] 则表示字符文件(character file)。字符文件表示一些提供串行输入或输出的设备和终端,比如,声卡、显卡、键盘、鼠标、
tty
终端等。这些设备的特性就是一次性读取,不能够截断输出。举例来说,你不可能让鼠标跳到另一个画面,而是连续性滑动到另一个地方。此类文件通常都集中在/dev
这个目录中。 - 若是 [s] 则表示套接字文件(socket file)。套接字文件用于在应用程序之间传递信息以进行通信,通常被用在网络上的数据发送接收。我们可以启动一个程序来监听客户端的要求,而客户端就可以通过这个套接字文件来进行数据的沟通了。通常可以在
/run
或/tmp
这些目录中看到这种文件类型。可以使用socket()
系统调用创建一个套接字文件。 - 当为 [p] 则表示网络设备(pipe file 或 named pipe file)。管道文件或命名的管道文件表示存取文件时进出的字节顺序是相同的,它的主要目的在解决多个程序同时存取一个文件所造成的错误。命名的管道文件的 name 实际上是文件系统内的文件名。有时这种文件也称为 FIFO 文件,其中, FIFO 是
First-In, First Out
的缩写。
接下来的字符中,以三个为一组,且均为 rwx
的三个参数的组合。其中:
- [r]代表可读(read);
- [w]代表可写(write);
- [x]代表可执行(execute);
- [-]代表没有对应的权限。
文件属性从左至右用 0-9 这些数字来表示。第 0 位确定文件类型(前面已经说过可以为哪些文件类型),第 1-3 位确定属主(即该文件的所有者)拥有该文件的权限。第 4-6 位确定所属群组(所有者的同组用户)对该文件的权限,第 7-9 位确定其他用户对该文件的权限。其中,第 1、4、7 位表示读权限,如果用 r
字符表示,则有读权限,如果用 -
字符表示,则没有读权限;第 2、5、8 位表示写权限,如果用 w
字符表示,则有写权限,如果用 -
字符表示没有写权限;第 3、6、9 位表示可执行权限,如果用 x
字符表示,则有执行权限,如果用 -
字符表示,则没有执行权限。
对于 root 用户来说,一般情况下,文件的权限对其不起作用,即 root 用户对所有文件拥有所有权限。
权限对目录和文件含义
文件是实际含有数据的地方,包括一般文本文件、数据库内容文件、二进制可执行文件(binary program)等等。 因此,权限对于文件来说,它的意义是这样的:
-
r (read)
:可读取此文件的实际内容,如读取文本文件的文字内容等; -
w (write)
:可以编辑、新增或者是修改该文件的内容(但不代表可以删除该文件); -
x (eXecute)
:该文件具有可以被系统执行的权限。
那个可读(r)代表可以读取文件内容。在 Windows 中一个文件是否具有执行的能力是借由扩展名(如 .exe
、.bat
、.com
等)来判断的。但是在 Linux 中,文件是否能被执行,则是借由是否具有 x
这个权限来决定的,跟文件名没有绝对的关系。当你对一个文件具有 w
权限时,你可以具有写入/编辑/新增/修改文件的内容的权限, 但并不具备删除该文件本身的权限。对于文件的 rwx
来说,主要都是针对文件的内容而言,与文件名没有关系,因为文件记录的是实际的数据 。
目录主要的内容在于记录其中的文件名列表,所以 rwx
对目录含义如下:
r
(read contents in directory):表示具有读取目录中文件列表的权限,所以当对一个目录具有r
权限时,表示可以查询该目录下的文件列表。即可以利用ls
这个命令将该目录的内容列表显示出来。-
w
(modify contents of directory):表示具有改动该目录中文件列表的权限,也就是下面这些权限:- 建立新的文件与目录;
- 删除已经存在的文件与目录(不论该文件的权限是什么);
- 将已存在的文件或目录进行更名;
- 移动该目录内的文件、目录位置。
总之,目录的
w
权限就与该目录下的文件名改动有关。 x
(access directory):目录只是记录文件名而已,但不可以被执行,目录的x
权限仅表示可以进入该目录使其成为工作目录(work directory),如果你在某目录下不具有 x 的权限, 那么你就无法切换到该目录下,也就无法执行该目录下的任何指令,即使你具有该目录的 r 或 w 的权限。
Linux 中的文件名限制
长度限制
在 Linux 底下,使用传统的 ext2/ext3/ext4
文件系统以及近来被 CentOS 7 当作预设文件系统的 xfs
而言,针对文件的文件名长度限制为:单一文件或目录的最大容许文件名为 255 字节,以一个 ASCII 英文占用一个字节来说,则大约可达 255 个字符长度。若是以每个中文字占用 2 字节来说, 最大档名就是大约在 128 个中文字之多。
字符限制
因为一些 Linux 文字操作指令的关系,一般来说,在为文件和目录命名时最好可以避免一些特殊字符:\
、*
、?
、>
、<
、;
、&
、!
、[
、]
、|
、\
、'
、"
、(
、)
、{
、}
。
有一些 Linux 命令可用于修改文件权限,比如 chmod
、chown
、chgrp
等命令。
chmod
命令
chmod
命令用来变更文件或目录的权限。设置方式采用文字或数字代号皆可。符号链接的权限无法变更,如果用户对符号连接修改权限,其改变会作用在被链接的原始文件。
语法
chmod [OPTION]... MODE[,MODE]... FILE...
chmod [OPTION]... OCTAL-MODE FILE...
chmod [OPTION]... --reference=RFILE FILE...
选项
-c, --changes:类似 verbose,但仅在已变化之后报告;
-f, --silent, --quiet:不输出多数错误信息;
-v, --verbose:输出每个文件处理的诊断信息;
--no-preserve-root:不特别处理根目录 `/`;
--preserve-root:不递归处理根目录 `/` ;
--reference=RFILE:使用 RFILE 的属性而不是 MODE 值;
-R, --recursive:递归处理文件和目录;
--help:显示帮助信息并退出;
--version:显示版本信息并退出。
参数
MODE:文件权限模式。可以是数值,也可以是字符格式;
FILE:待变更的文件。
指定的变更格式 [ugoa...][[+-=][rwxXst]...][,...]
。文件权限范围的表示法如下:
-
u
User,即文件或目录的拥有者; -
g
Group,即文件或目录的所属群组; -
o
Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围; -
a
All,即全部的用户,包含拥有者,所属群组以及其他用户; -
+
表示添加权限; -
-
表示去除权限; -
=
表示重新分配权限; -
r
读取权限,数字代号为“4”; -
w
写入权限,数字代号为“2”; -
x
执行或切换权限,数字代号为“1”。-
替换 r、w、x位置时表示没有对应的权限,对应数字为 0; -
X
表示如果对象是目录或者它已有执行权限,赋予执行权限 ; -
s
运行时重新设置 UID 或 GID ; -
t
设置粘着位(sticky bit),防止文件或目录被非属主删除。
示例
$ chmod u+x file # 给file的属主增加执行权限
$ chmod 751 file # 给file的属主分配读、写、执行(7)的权限,给file的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限
$ chmod u=rwx,g=rx,o=x file # 上例的另一种形式
$ chmod =r file # 为所有用户分配读权限
$ chmod 444 file # 同上例
$ chmod a-wx,a+r file # 同上例
$ chmod -R u+r directory # 递归地给directory目录下所有文件和子目录的属主分配读的权限
$ chmod 4755 # 设置用ID,给属主分配读、写和执行权限,给组和其他用户分配读、执行的权限。
chown
命令
chown
命令改变某个文件或目录的所有者和所属的组,该命令可以向某个用户授权,使该用户变成指定文件的所有者或者改变文件所属的组。用户可以是用户或者是用户D,用户组可以是组名或组id。文件名可以使由空格分开的文件列表,在文件名中可以包含通配符。
只有文件主和超级用户才可以便用该命令。
语法
chown [OPTION]... [OWNER][:[GROUP]] FILE...
chown [OPTION]... --reference=RFILE FILE...
选项
-c, --changes:类似 verbose,但仅在已变化之后报告;
-f, --silent, --quiet:不输出多数错误信息;
-v, --verbose:输出每个文件处理的诊断信息;
--dereference:影响每个符号链接的参照(默认),而不是符号链接本身;
-h, --no-dereference:影响符号链接而不是符号链接的参照(在可以改变符号链接的属主的系统上有用);
--from=CURRENT_OWNER:CURRENT_GROUP:改变能匹配到指定属主和/或属组的每个文件的属主和/或属组。属主和属组都可以省略,就不用匹配省略的属性;
--no-preserve-root:对根目录 `/` 不做特殊处理;
--preserve-root:不处理根目录 `/`(默认);
--reference=RFILE:使用 RFILE 的属性而不是 MODE 值;
-R, --recursive:递归操作目录和文件;
# 下面的选项可修改 -R 选项遍历的层级。如果指定了多个这样的选项,仅最后一个有效。
-H:如果命令行参数是一个符号链接,则遍历它;
-L:遍历每个出现的符号链接;
-P:不遍历任何符号链接(这是默认行为);
--help:显示帮助信息并退出;
--version:输出版本信息并退出。
参数
OWNER:指定文件的所有者和;
GROUP:指定文件的所属工作组;
FILE:指定要改变所有者和工作组的文件列表。支持多个文件和目标,支持 shell 通配符。
示例
将目录 /usr/meng
及其下面的所有文件、子目录的文件属主改成 liu
。
chown -R liu /usr/meng
chgrp
命令
chgrp
命令用来改变文件或目录的所属群组。其中,组名可以是用户组的 id,也可以是用户组的组名。文件名可以是由空格分开的要改变属组的文件列表,也可以是由通配符描述的文件集合。如果用户不是该文件的属主或超级用户(root),则不能改变该文件的属组。
语法
chgrp [OPTION]... GROUP FILE...
chgrp [OPTION]... --reference=RFILE FILE...
选项
-c, --changes:类似 verbose,但仅在已变化之后报告;
-f, --silent, --quiet:不输出多数错误信息;
-v, --verbose:输出每个文件处理的诊断信息;
--dereference:影响每个符号链接的参照(默认),而不是符号链接本身;
-h, --no-dereference:影响符号链接而不是符号链接的参照(在可以改变符号链接的属主的系统上有用);组都可以省略,就不用匹配省略的属性;
--no-preserve-root:对根目录 / 不做特殊处理;
--preserve-root:不处理根目录 /(默认);
--reference=RFILE:使用 RFILE 的属性而不是 MODE 值;
-R, --recursive:递归操作目录和文件;
# 下面的选项可修改 -R 选项遍历的层级。如果指定了多个这样的选项,仅最后一个有效。
-H:如果命令行参数是一个符号链接,则遍历它;
-L:遍历每个出现的符号链接;
-P:不遍历任何符号链接(这是默认行为);
--help:显示帮助信息并退出;
--version:输出版本信息并退出。
参数
- GROUP:指定的新的属组名;
- FILE:要改变属组的文件列表。多个文件或者目录之间使用空格隔开。
示例
将 /usr/meng
及其子目录下的所有文件的用户组改为 mengxin
。
chgrp -R mengxin /usr/meng
文件目录的默认权限与 umask
命令
Windows 系统中,新建的文件和目录时通过继承上级目录的权限获得的初始权限,而在 Linux 和其他类 Unix 的操作系统中, 是通过使用 umask
命令来给所有新建的文件和目录赋予初始权限的。umask
命令用来设置新建文件的权限的掩码,或者获取它当前的值。所谓掩码,就是 umask
的数值指的是该默认值需要减掉的权限。比如,r、w、x 分别是 4、2、1,当要去掉写权限,就输入 2,而如果要去掉读权限,也就是输入 4,要去掉读与写的权限,就输入 6,而要去掉执行权限与写权限,就输入 3,而 5 就是去掉读权限与执行权限。
在默认权限的属性上,目录与文件是不一样的。默认情况下:
- 如果创建的是目录,则对一般用户来说,
umask
默认值为 0002,对应的实际文件权限为 775,对于 root 用户来说,umask
默认值为 0022,对应的实际文件权限为 755。 - 如果创建的是文件,则对一般用户来说,
umask
默认值为 0113,对应的实际文件权限为 664,对于 root 用户来说,umask
默认值为 0133,对应的实际文件权限为 644。
第一个零是一个特殊的权限数字,可以忽略,即 0002 与 002 相同。umask
默认输出的也是针对新建目录的权限掩码,而不是新建文件的权限掩码。
语法
umask [-p] [-S] [mode]
选项
-p
:如果提供了-p
选项,将忽略mode
,输出的内容可以当作输入重新使用。-S
:接受或返回一个代表掩码的符号而不是一个八进制数字(默认值)。mask
:如果指定了一个合理的掩码,这个umask
就将被设置为这个值。如果没有指定掩码,返回当前的掩码值。-
mode
:如果mode
以数字开头,则将 mode 转换为八进制。否则,将按照与chmod
相似的权限符号处理。指定的权限符号格式为[ugoa...][[+-=][rwxXst]...][,...]
。文件权限范围的表示法如下:u
User,即文件或目录的拥有者;g
Group,即文件或目录的所属群组;o
Other,除了文件或目录拥有者或所属群组之外,其他用户皆属于这个范围;a
All,即全部的用户,包含拥有者,所属群组以及其他用户;+
表示添加权限;-
表示去除权限;=
表示重新分配权限;r
读取权限,数字代号为“4”;w
写入权限,数字代号为“2”;x
执行或切换权限,数字代号为“1”。-
替换 r、w、x位置时表示没有对应的权限,对应数字为 0;X
表示如果对象是目录或者它已有执行权限,赋予执行权限 ;s
运行时重新设置 UID 或 GID ;t
设置粘着位(sticky bit),防止文件或目录被非属主删除。
如果省略了
mode
,将打印出当前的umask
值。如果mode
设置成功或者没有提供mode
,则返回状态为0
,否则返回false
。
示例
查看当前用户创建文件的默认权限。
# root 用户默认值为 0022,对应的文件权限为 755
[root@localhost ~]# umask
0022
[root@localhost ~]# umask -S
u=rwx,g=rx,o=rx
[root@localhost ~]# umask -p
umask 0022
[root@localhost ~]# umask -p -S
umask -S u=rwx,g=rx,o=rx
[root@localhost ~]# mkdir test_dir
[root@localhost ~]# touch test.txt
[root@localhost ~]# ll
# 目录默认为 755(umask 为022),文件默认为 644(133)
drwxr-xr-x. 2 root root 6 Nov 23 23:45 test_dir
-rw-r--r--. 1 root root 0 Nov 23 23:45 test.txt
[root@localhost ~]#
# 一般用户默认值为 0002,对应的文件权限为 775
[root@localhost ~]$ su vincnet
[vincent@localhost ~]$ umask
0002
[vincent@localhost ~]$ umask -p
umask 0002
[vincent@localhost ~]$ umask -S
u=rwx,g=rwx,o=rx
[vincent@localhost ~]$ umask -p -S
umask -S u=rwx,g=rwx,o=rx
[vincent@localhost ~]# mkdir test_dir
[vincent@localhost ~]# touch test.txt
[vincent@localhost ~]$ ll
# 目录默认为 775(umask 为002),文件默认为 664(113)
drwxrwxr-x. 2 vincent vincent 6 Nov 23 23:40 test_dir
-rw-rw-r--. 1 vincent vincent 0 Nov 23 23:40 test.txt
修改新建目录和文件的默认权限。
# 新增其他用户对新建文件和目录的写权限
[vincent@localhost ~]$ umask o+w
# 查看 umask 的当前值,发现已经改变,不是 0002 了
[vincent@localhost ~]$ umask
0000
# 新建文件测试
[vincent@localhost ~]$ touch test2.txt
# 发现其他用户默认对新建文件具有写权限了
[vincent@localhost ~]$ ll
-rw-rw-rw-. 1 vincent vincent 0 Nov 23 23:55 test2.txt
drwxrwxr-x. 2 vincent vincent 6 Nov 23 23:40 test_dir
-rw-rw-r--. 1 vincent vincent 0 Nov 23 23:40 test.txt
# 去除其他用户对新建文件和目录的读权限和写权限
[vincent@localhost ~]$ umask o-rw
# 查看 umask 的当前值,发现已经改变
[vincent@localhost ~]$ umask
0006
# 新建目录测试
[vincent@localhost ~]$ mkdir test2_dir
[vincent@localhost ~]$ ll
# 发现其他用户默认对新建目录已不具备读权限和写权限了
drwxrwx--x. 2 vincent vincent 6 Nov 24 00:00 test2_dir
-rw-rw-rw-. 1 vincent vincent 0 Nov 23 23:55 test2.txt
drwxrwxr-x. 2 vincent vincent 6 Nov 23 23:40 test_dir
-rw-rw-r--. 1 vincent vincent 0 Nov 23 23:40 test.txt
[vincent@localhost ~]$
文件隐藏权限
lsattr
命令
lsattr
命令用于列出 Linux 第二扩展文件系统上的文件属性。
语法
lsattr [ -RVadv ] [ files... ]
选项
-
-a
:显示所有文件和目录,包括以.
为名称开头的当前目录.
与上层目录..
。 -
-d
:显示目录的属性,而非其每个文件列表项目的属性。 -
-R
:递归处理,将指定目录下的所有文件及子目录一并处理。 -
-v
:显示文件或目录版本。 -
-V
:显示程序的版本信息。
chattr
命令
chattr
命令用于更改 Linux 文件系统上的文件属性。
语法
chattr [ -RVf ] [ -v version ] [ -p project ] [ mode ] files...
选项
-
-R
:递归地更改目录以及其中所有内容属性。 -
-V
:详细记录chattr
的输出并打印程序版本。 -
-f
:抑制大多数错误消息。 -
-v version
:设置文件的 version/generation number。 -
-p project
:设置文件的 project number。
属性
符号模式的格式为 +-=[aAcCdDeFijmPsStTux]
。其中,
-
+
运算符用于向文件的现有属性添加新的属性。 -
-
运算符用于从文件的现有属性中移除指定的属性。 -
=
运算符用于将当前文件属性设置指定指定的属性。
aAcCdDeFijmPsStTux
字母表示选择属性。chattr
命令的属性只能在 Ext2/Ext3/Ext4
的 Linux 传统文件系统上面完整生效,其他的文件系统可能就无法完整的支持该命令的属性了。请参考 btrfs
、ext4
、和 xfs
文件系统的文档。
a
:具有a
属性集的文件只能在追加模式下打开以进行写入。只有超级用户或拥有CAP_LINUX_IMMUTABLE
功能的进程可以设置或清除此属性。A
:当访问具有A
属性集的文件时,其atime
记录不被修改。这避免了笔记本电脑系统上的一些的磁盘 I/O。c
:内核会在磁盘上自动压缩设置了c
属性的文件。读取此文件将返回未压缩的数据。写入此文件会在将数据存储到磁盘之前压缩数据。注意:对于btrfs
文件系统,如果设置了c
,则无法设置C
标志。还与btrfs
挂载选项nodatasum
冲突。-
C
:设置了C
属性的文件将不会进行写时复制(copy-on-write)更新。此标志仅在执行写时复制(copy-on-write)的文件系统上受支持。注意:对于
btrfs
文件系统,应在新文件或空文件上设置C
标志。如果在已具有数据块的文件上设置了C
,则在分配给该文件的块完全稳定时,该标志未定义。如果在目录上设置了C
标志,则该标志对该目录没有影响,但在该目录中创建的新文件将具有No_COW
属性。如果设置了C
标志,则无法设置c
标志。 d
:运行dump
程序时,具有d
属性集的文件不是备份的候选文件。D
:当修改设置了D
属性的目录时,更改会同步写入磁盘;这相当于应用于文件子集的dirsync
挂载选项。e
:e
属性表示文件正在使用扩展数据块映射磁盘上的块。不能使用chattr
将其删除。E
:文件系统对具有E
属性集的文件、目录或符号链接进行加密。虽然可以通过lsattr
显示该属性,但不能使用chattr
设置或清除该属性。F
:设置了F
属性的目录表示该目录中的所有路径查找都是以不区分大小写的方式进行的。此属性只能在启用casefold
功能的文件系统上的空目录中更改。i
:无法修改具有i
属性的文件。无法删除或重命名该文件,无法创建到此文件的链接,无法修改该文件的大部分元数据,并且无法在写入模式下打开该文件。只有超级用户或具有CAP_LINUX_IMMUTABLE
功能的进程才能设置或清除此属性。I
:htree
代码使用I
属性来指示正在使用哈希树对目录进行索引。虽然可以通过lsattr
显示,但不能使用chattr
设置或清除该值。j
:如果文件系统使用data=ordered
或data=writeback
选项挂载,并且文件系统具有日志,则具有j
属性的文件在写入到文件本身之前,其所有数据都已写入 ext3 或 ext4 日志。当使用data=journal
选项挂载文件系统时,所有文件数据都已记录,并且此属性无效。只有超级用户或拥有CAP_SYS_RESOURCE
功能的进程才能设置或清除此属性。m
:在支持逐个文件压缩的文件系统上,具有m
属性的文件将被排除在压缩范围之外。N
:设置了N
属性的文件表示该文件在inode
本身内以 inline 方式存储了数据。虽然可以通过lsattr
显示,但不能使用chattr
设置或清除该值。P
:具有P
属性集的目录将强制项目 id 的层次结构。这意味着在目录中创建的文件和目录将继承目录的项目 id,重命名操作受到约束,因此当文件或目录移动到另一个目录中时,项目 id 必须匹配。此外,只有当文件的项目 id 与目标目录匹配时,才能创建指向文件的硬链接。s
:删除具有s
属性集的文件时,其块将归零并写回磁盘。S
:当修改属性设置为S
的文件时,更改将同步写入磁盘;这相当于应用于文件子集的sync
挂载选项。t
:具有t
属性的文件在与其他文件合并的文件末尾不会有部分块片段(对于支持尾部合并的文件系统)。这对于像 LILO 这样的应用程序是必需的,它们直接读取文件系统,并且不理解尾部合并文件。注意:在撰写本文时,ext2、ext3 和 ext4 文件系统不支持尾部合并。T
:对于Orlov
块分配器(block allocator),具有T
属性的目录将被视为目录层次结构的顶部。这是对 ext3 和 ext4 所使用的块分配器的一个提示,即该目录下的子目录不相关,因此应该分开以进行分配。例如,在/home
目录上设置T
属性是一个非常好的主意,这样/home/john
和/home/mary
就被放置在单独的块组中。对于未设置此属性的目录,Orlov
块分配器将尝试尽可能将子目录分组在一起。u
:删除具有u
属性集的文件时,将保存其内容。这允许用户请求取消删除。x
:可以在目录或文件上设置x
属性。如果在现有目录上设置了该属性,则随后在该目录中创建的所有文件和子目录都将继承该属性。如果现有目录包含一些文件和子目录,则修改父目录上的属性不会更改这些文件和子目录上的属性。V
:具有V
属性集的文件已启用 fs-verity。它无法写入,文件系统将根据覆盖整个文件内容的加密散列(例如通过 Merkle 树)自动验证从中读取的所有数据。这使得有效地对文件进行身份验证成为可能。虽然可以通过lsattr
显示该属性,但不能使用chattr
设置或清除该属性。
在当前的主线 Linux 系统中实现的 ext2、ext3 和 ext4 文件系统不支持 c、s 和 u 属性内尔斯。j
选项仅对 ext3 和 ext4 文件系统有用。D
选项仅在 Linux 内核2.5.19 及更高版本上有用。
示例
最重要的当属 +i
与 +a
这个属性了。+i
可以让一个文件无法被更改,对于需要强烈的系统安全的人来说很重要。
[root@localhost vincent]# lsattr test.txt
---------------- test.txt
[root@localhost vincent]# chattr +i test.txt
[root@localhost vincent]# lsattr test.txt
----i----------- test.txt
[root@localhost vincent]# chattr -i test.txt
[root@localhost vincent]# lsattr test.txt
---------------- test.txt
文件系统特殊权限:SUID、SGID、SBIT
我们再来看一下 /tmp
和 /usr/bin/passwd
文件的权限。
[vincent@localhost ~]$ ls -ld /tmp; ls -l /usr/bin/passwd
drwxrwxrwt. 15 root root 4096 Nov 23 21:14 /tmp
-rwsr-xr-x. 1 root root 27856 Apr 1 2020 /usr/bin/passwd
s
与 t
这两个权限的意义与系统的账号及系统的进程相关。暂且先说明一下如何使用这两个权限。
SUID
在 Linux 系统中,所有账号的密码都记录在 /etc/shadow
这个文件里面,这个文件的权限为:---------- 1 root root
,意思是这个文件仅有 root
可读且仅有 root
可以强制写入而已。那么一般账号为什么可以修改自己的密码呢?passwd
的拥有者是 root 这个账号,而一般用户在执行 passwd
的过程中,会“暂时”获得 root
的权限,/etc/shadow
就可以被一般用户所执行的 passwd
所修改。而一般用户如果使用 cat
去读取 /etc/shadow
,则会提示 Permission denied
,因为 cat
不具有 SUID 的权限。
当 s 这个标志出现在文件拥有者(owner)的 x 权限位置上时被称为 Set User ID,简称为 SUID 的特殊权限。SUID 有这样的限制与功能:
-
SUID 权限仅对二进制程序(binary program)有效,对一般不可执行的文件无意义。当文件所有者权限的第三位是一个大写的
S
时,则表示原先的x
权限位置内容为-
。SUID 也不能够用在 shell script 上面,因为 shell script 只是将多个二进制程序组合在一起执行而已,所以 SUID 的权限部分,还是得要看 shell script 中的程序是否具有 SUID 权限而定,而不是 shell script 本身。
SUID 对于目录也是无效的。
程序执行者需要对该程序具有可执行权限。如果文件所有者没有可执行权限,则此处将显示为大写字母 S。
在默认情况下,如果用户发起一个进程,则该进程的属主是发起者而并非是文件的拥有者,此时进程是以发起者的身份去运行。但是,如果给可执行的二进制程序文件添加了 SUID 权限后,当调用该程序时,则对应进程的属主为程序文件的拥有者而并非是发起者。可以看作调用者暂时获得该文件拥有者的权限,所获的权限仅在执行该二进制程序的过程中有效。
SGID
当 s 这个标志出现在文件群组(group)的 x 权限位置上时被称为 Set Group ID,简称为 SGID。与 SUID 不同的是,SGID 可以对于文件或目录来说均有效。看下面的文件。
[vincent@localhost ~]$ ls -l /usr/bin/locate
-rwx--s--x. 1 root slocate 40520 Apr 11 2018 /usr/bin/locate
对文件来说, SGID 有如下的功能:
- SGID 仅对可执行二进制程序有用。如果在浏览文件时,当文件群组权限的第三位是一个大写的
S
时,则表示原先的x
权限位置内容为-
。 - 程序执行者需要对该程序来具备
x
的权限。 - 在执行该文件时,程序执行者将获得该文件所属组的权限。
在看下面的文件。
[vincent@localhost ~]$ sudo -i
[root@localhost ~]# ll /usr/bin/locate /var/lib/mlocate/mlocate.db
-rwx--s--x. 1 root slocate 40520 Apr 11 2018 /usr/bin/locate
-rw-r-----. 1 root slocate 2831122 Nov 23 21:14 /var/lib/mlocate/mlocate.db
与 SUID 非常的类似,若使用一般账号去执行 locate
命令时将会取得 slocate
群组的权限,因此一般用户就能够去读取 mlocate.db
文件了。
除了可执行二进制程序之外,SGID 也能够用在目录上。当一个目录设定了 SGID 的权限后,它将具有如下的功能:
- 当用户若对于此目录具有
r
与x
的权限时,该用户能够进入此目录。 -
用户在该目录下的有效群组(effective group)将会变成该目录所属的群组。所以,当用户对该目录具有
w
的权限(可修改该目录下的文件列表),则使用者所建立新文件的群组与该目录所属的群组相同。
Sticky Bit
SBIT 全称 Sticky Bit(粘滞位),它出现在其他用户(other)的 x 权限位置上,只能用来修饰一个目录。当某一个目录拥有 SBIT 权限时,用户在这个目录下所建立的文件和目录只有该用户自己和 root 可以删除,其他用户均不可以。
当其他用户(other)对某个目录具有可执行权限时则显示为 -t
,当其他用户(other)对某个目录不具有可执行权限时则显示为 -T
。
SBIT 对于 /var/tmp
和 /tmp
等共享目录很有用,因为用户可以创建文件、读取和执行其他用户拥有的文件,但不允许删除其他用户拥有的文件。
SUID、SGID 和 SBIT 的设置
可以通过数字方式来设置这三个特殊权限。三个权限对应的数字分别是:
SUID:4
SGID:2
SBIT:1
假设要为一个文件设置权限 -rwsr-xr-x
时,由于 s 在所有者权限的执行位上,所以是 SUID,因此在原先的 755 之前加上 4 即可,即使用 chmod 4755 filename
来设置。
此外,也可以通过符号法来设置三个特殊权限,其中 SUID 为 u+s,SGID 为 g+s,SBIT 则是 o+t,来看看如下的范例:
[root@localhost ~]# chmod u=rwxs,go=x test
[root@localhost ~]# ll test
-rwsr-sr-t 1 root root 0 Feb 14 15:51 haha
总结如下:
如果本来在 x 位上设置了 x,设置这些位将会显示小写字幕,否则会显示为大写字母,即无效。这三位如果转化为 8 进制表示的话,分别对应的是 4(SUID),2(SGID)、1(sticky bit)、0(什么也不是)。