Linux
Linux 中不那么基础的权限
0X00 前言
首先声明这篇博客针对的是中级 Linux 用户,如果你还不清楚 Linux 中的基本权限机制 user/group/other
和 rwx
的话需要先去了解一下对应的基础内容才行。既然标题上写了是“不那么基础的权限”,也就能看出来虽然内容不是很基础,但是也不会很高深。
另外,这篇博客里提到的好多内容都是并不复杂的东西,但是非常零碎,也许你用了十年 Linux 还是不知道其中的一些小知识点,不过也没什么,毕竟这些知识点的使用率真的很低。
如果你看完了这篇博客有那么一点点收获,那我也算是完成目标了;如果你看完后发现所有的内容都是你以前就知道的,那我只能说你对 Linux 权限这部分的掌握超过了大多数人。因为我确实给周围好多人分享过这些内容,从刚实习的朋友到比我工作经历多很多综合实力也强很多的人,几乎没有谁是完全了解这些内容的。(所以说虽然这篇博客并不难,并不是什么高深的知识,但是我比较有信息让你从中获得那么一点点的收获)
本博客不涉及某个命令的具体用法,只起到一个让你“知道自己哪里不知道”的作用。如果想要仔细了解某个命令或者某个机制,可以自行搜索相关资料。
0X01 root 究竟是谁
“root是谁?”这个问题听起来很蠢,但是实际上好多人并没有思考过这个问题。我们都知道 Linux 中有一个叫做 uid
的东西,其实 root 用户指的就是 uid为0的用户,而非用户名为root的用户,我们可以通过 id
命令来查看用户的 uid。

而且值得注意的一点是 uid 是会被回收利用的。也就是说你创建了一个用户,系统分配了 1002 这个 uid 后,如果删掉这个用户紧接着再创建一个新用户是会敷用 1002 这个 uid 的。假设你删掉了系统中的一个老用户,又创建了个新的用户,那么万一 uid 是重复的就有可能导致这个新用户拥有之前老用户的权限,这是一种很危险的操作。

0X02 一分钟带过的 rwx
然后进入正题,也就是真正意义上的权限:rwx/ugo
机制。不过这里就不细说了,假设你已经掌握了基础的这套权限机制。如果你之前不知道 rwx
是三个二进制位,从而用 111/101/110
来表示的 rwx/r-x/rw-
的话现在也知道了。
0X03 基础 rwx 之后的一级:ACL
我们会发现基础的 rwx/ugo 权限机制只能将权限分配给三种人:文件所属用户、文件所属组、其他。如果你想专门指定给某个用户某个权限的话,是做不到的。那么 ACL 就是来解决这个问题的。

用于操作 ACL 的命令有两个 getfacl/setfacl
,分别用来读取和设置 ACL 权限。其中 getfacl
可以比 ls -l 看到更详细的权限信息。而且你可能注意到权限位最后的 +
了,这里是加号的时候 ls -l
出来的权限位和我们平时看的就不一样了,想要看的清晰些最好就使用 getfacl
。
这里具体的展示方式各个发行版本可能会有所不同,有些在没有设置 acl 的时候后面什么都没有,有些则会留一个 .
在那里。而且 acl 在某些发行版上还需要额外安装,默认是不带的。所以需要具体发行版本具体分析。
0X04 suid sgid 和 sbit
suid
和 sgid
之前先来看一下这一小段代码,这段 C 代码的唯一功能就是在 /root
下创建一个文件。

然后将这段代码编译成二进制程序,再给它赋予相应的用户和权限

这里就看到了一个“奇怪的现象”:这个二进制程序会在 /root
创建一个文件,但是执行这个二进制程序的用户并没有向 /root
写入文件的权限(第三行可以看到有一个红色的 [1]
,是指的上一条命令的返回值),那是怎么成功的呢?就是因为上面的两行命令:sudo chown root.root create_file_2_root
和 sudo chmod +s create_file_2_root
。
这两条命令分别是:将文件分配给 root
用户;为文件设置 suid
。那么这个 suid
究竟是做什么用的呢? **设置了 suid
的程序,在执行过程中会临时变更为文件所属人的用户状态。**也就是说上面的 create_file_2_root
命令在执行过程中是 root 用户的身份,既然是 root 用户那向 /root
写入个文件也就没什么大不了的了。

所以 suid
的意思就是 set uid ID upon execution
,那么 sgid
也就显而易见的是 set group ID upon execution
了。
唯一需要注意的就是,设置 s
权限的时候,需要已经拥有 x
权限。如果没有设置 x
就直接给了 s
权限,则在 ls
的时候会发现 S
会变成大写的标识,表示当前没有执行权限。
其中suid
只能使用在二进制可执行程序上;sgid
不只是二进制程序,也可以用在目录上;
设置了sgid
后,用户在此目录下的有效用户组将变成该目录的用户组;
设置了sgid
后,若用户在此目录下拥有 w 权限,则用户所创建的新文件的用户组与该目录的用户组相同(默认情况下自己创建的文件所属人和组都是自己,如果与目录相同就自然会有风险)
还有一个跟 suid/sgid
不是很很相关,但是又比较相关(诡异的描述 hhhhh)的sbit
叫做 the restricted deletion flag or sticky bit
,也就是用来标记限制删除的 bit。一旦文件被设置了 sbit
后就只有文件所属人和 root 才有办法删除了。好多发行版本的默认情况下 /tmp
这个目录就被设置了 sbit
,因为你肯定不想你自己创建的临时文件被其他人删掉嘛。
当然,suid/sgid/sbit
都可以通过 getfacl
命令查看到。

补充一句,这个只能为目录设置,为普通文件设置暂时没有任何意义和用处。
0X05 umask 默认权限
umask 是配置在用户上的,用于指定用户创建的文件/目录的默认权限的功能。也就是说每个用户可以有自己的 umask,用来指导自己创建的新文件、新目录所具有的权限。
新文件默认权限 = 类型最大权限 (666/777) - umask(按位减而非按数字减)

最大权限问题其实我们可以简单理解成:文件为 666,目录为 777,因为目录默认必须有x
所以比文件多1
。
具体算法可以按照如下来尝试计算,但是我总觉得自己哪里搞得不对,不过又怎么算都是对的,这里我对自己的正确性持保留意见,如果发现什么不对劲的地方可以随时联系我改正。
umask 0022:
文件:
r w - r w - r w - 666
- - - - w - - w - 022
———————————————————————————————
r w - r - - r - - 644
目录:
r w x r w x r w x 777
- - - - w - - w - 022
———————————————————————————————
r w x r - x r - x 755
0X06 删除文件引发的权限问题
接下来就到了一个相对来说有趣的地方了,首先我们来带入一个场景,看看这个

为什么这个文件我已经是所有人了,且权限已经是 777 了还是不能删除呢?这就涉及到了一个子问题“目录是什么”。

都说 Linux 万物皆文件,其实目录也是一个文件,只不过相对特殊一点而已。这个文件里主要存储了 inode
和 filename
,所以我们对一个目录里的文件进行改名和删除的时候需要和创建一样的 w
权限。只有拥有了对一个目录的 rwx
权限才可以进入到目录里并且删除一个文件。所以上面这张截图里不能删除文件的原因是当前用户并没有当前目录的写入权限,所以不能删掉这个文件。

如果给用户添加一个对目录的写入权限,那就可以删掉这个文件了。

接下来再看下一个例子,我们可以看到这个目录下有两个文件,我已经可以删除其中一个了,那为什么不能删除另一个权限完全一样的文件呢?

答案在 setattr
这里。

Linux 中还有一个 attr
的东西,故名思义就是文件的属性了。我们可以给文件设置多个属性,例如下面的这些:
A:文件或目录的 atime (access time)不可被修改(modified), 可以有效预防磁盘I/O错误的发生;
S:硬盘I/O同步选项,功能类似sync;
a:即append,设定该参数后,只能向文件中添加数据,而不能删除;
c:即compresse,设定文件是否经压缩后再存储。读取时需要经过自动解压操作;
d:即no dump,设定文件不能成为dump程序的备份目标;
i:设定文件不能被删除、改名、设定链接关系,同时不能写入或新增内容;
j:即journal,设定此参数使得当通过mount参数:data=ordered 或者 data=writeback 挂 载的文件系统,文件在写入时会先被记录(在journal中)。如果filesystem被设定参数为 data=journal,则该参数自动失效;
s:保密性地删除文件或目录,即硬盘空间被全部收回;
u:与s相反,当设定为u时,数据内容其实还存在磁盘中,可以用于undeletion。
其实还不止这些,但是我们通常会用到的也就这两个:a
和 i
。其中被设置了 a
的文件只能被追加新内容,不能被删除或者复写已经存在的内容;而被设置了 i
的文件则不允许被删除,即使是天王老子来了也不允许被删除(除非你把它的 i
属性彻底)。所以说 a
属性通常会用在重要的日志上,从而保证日志不会被复写;i
属性通常会用在一些极其重要的文件上,防止被误删。而且由于这些属性的特殊性和强大的“拒绝改动性”(我乱取的名字),有一部分属性就只有 root 用户才能设置和删除,比如刚刚提到的 a/i
两个属性就是只有 root 才能操作,如果允许所有用户操作的话,一个用户在机器上创建了一个 10T 的文件又给了 i
属性,10T 的空间就被白白浪费掉了。

0X07 尾巴
这些内容呢都算不上“复杂”或者“困难”或者“高深”,只是有很多人“不知道自己不知道”,所以我来分享一下我自己对这些内容的一些了解。主要目的也不是让读者一下就明白这些工具或者这些机制是怎么用的,是什么原理,而是让读者知道自己不知道什么。从而遇到问题的时候有个解决的思路,想要了解更深入的权限的时候记得还有一个什么ACL/attr/suid/sgid/sbit
的东西可以用,如果让一位读者达到这个目的我就算完成任务了~
0X08 尾巴的尾巴
其实还有一个有关 “权限” 的机制叫做 SELinux
,相信不少人尤其是用过 CentOS/RHEL 的会听说过这东西,不过多数人也仅限于知道有这么个东西,装好系统第一时间关掉它。其实它的功能很强大,但是我了解的也非常非常少,少到甚至不足以写一个小结专门介绍,所以就只有放在尾巴的尾巴里。至于为什么我几乎完全不懂还要写在这儿的唯一理由就是让读者知道自己不知道什么。
感谢您的支持
如果您喜欢这篇文章,可以通过以下方式支持我:






评论区