原来Linux的文件权限玩法还有这么多啊
说起来我有点火星,我一直以为Linux的文件权限很简单,只能设置文件所有者、所在组和其他人的读、写和执行权限,把它们都用一个比特位表示的话,恰好是一个9位二进制数字,遇到问题大不了777一把梭。
然而实际上Linux的文件权限不是9位,而是12位。
那多出来的3位能做什么呢?
先快速看看前面提到的9位功能
来都来了,先看看刚才提到的9位都有什么功能好了。
所谓的权限,指的是某个角色能做什么,以及不能做什么。在Linux中,权限限制的角色有文件的所有者(User)、所在的组(Group)和其他人(Other)三个。
什么意思呢?顾名思义:
- 所有者(User):这个文件属于哪个用户
- 所在的组(Group):所有者所在的用户组
- 其他人(Other):非文件所有者和所在组的其他用户们
对于这三个角色,我们分别可以控制它们的三件事:
- 读(r):能否读取文件内容
- 写(w):能否往文件里写数据,对文件进行修改
- 执行(x):是否允许把文件当作可执行文件程序进行运行
在Linux中经常用ls指令查看某一目录下的文件列表,其中的一行往往类似这样的:
drwxr-xr-x 2 root root 4096 Oct 31 00:01 dir/
-rwxr-x--x 2 root root 1024 Oct 31 00:01 hello.txt
这里面每一行最开头的这串字符串表示了类型和访问权限。
第一位为类型,例如d表示目录,-表示文件,l代表软链接等。
接下来的9位以三个为一组,有三组,分别为所有者权限、所在组权限与其他人权限。
例如:-rwxr-x--x,表示这是一个文件,所有者有rwx权限(即所有权限),所在组的其他用户有rx权限(即读取和执行权限,不能写),其他用户有x权限(即没有读写权限,但能执行)。
还能用二进制来表示权限,以1表示拥有,0表示没有,仍然是以读、写和执行三个比特位为一组,从前到后写三组,分别表示所有者、所在组合其他用户的权限,就能用九位二进制数表示文件权限了。
为了方便阅读,还常常将每一组写成对应的十进制数字,以一个三位十进制数来表示权限。
例如最高权限rwxrwxrwx表示所有者、所在组和其他用户全都有读、写和执行权限,那可以写做111111111,也可以写作777。
再例如rwxr-x--x,可以表示成111101001,也可以写作751。
其他3位的功能
刚才提到的9位的功能很好理解。那么其它3位都有什么功能呢?
setuid位
其中有一位叫做setuid位。
要理解它的话,需要理解文件的执行用户的关系。
如果我们当前登录的用户叫做tdiant,要运行一个可执行程序prog,我们直接执行这样的指令:
./prog
这样的话,启动出来的进程以我当前登录的用户tdiant以及这个用户所在的用户组运行,也具有对应的用户和用户组权限。
而有时候我们可能不希望它是这样的,我们可能是希望它会以文件自己的所有者和所在组的权限运行。
例如,如果我登录了tdiant这个用户,我现在希望修改密码,我会使用这样的指令:
passwd
实际上passwd是一个程序,对应存储在/bin/passwd。可以用ls看到它的文件权限:
$ ls -l /bin/passwd
-rwsr-xr-x 1 root root 68248 Apr 7 2025 /bin/passwd
这里可以看到所有者权限的执行位的x显示成了s,他表示setuid位为1,而由于其他用户是有执行权限的,所以任何用户都能运行它,并且是以文件所有者root的权限执行的。
实际上这其实是符合直觉的。passwd显然需要高权限把新的用户密码写到对应的文件里,同时也需要所有用户都能够执行它来修改自己的密码,那么对于passwd文件就可以将setuid设置为1。
如果这里显示的不是s而是S(大写而非小写)的话,说明这文件的setuid被设置为了1,但是我们没给它需要的执行权限,那我们这个setuid不就设置了个寂寞,所以这里用S提示这个设置没意义。
setgid位
setgid位如果给一个文件设置,那么就可以类比setuid来理解:setuid的意思是运行的时候以文件所在组执行的意思。
如果setgid被设置为1,可以看到所在组的执行权限的x会被现实为s,这也跟setuid同理。
但是setgid位要是给某个目录设置了的话,意思就不一样了:如果这个目录的所在组是group1的话,有用户在这个目录里创建文件的话,这个新文件的所在组为group1,而非创建者的用户组。
sticky位
sticky位只能给目录设置,不能给文件设置。
它表示在该目录下的所有文件都只能被这个文件的所有者删除或移动。
比如现在有个共享目录/data/shared_files,我希望所有用户都能共享它,可以往里面读写文件,所以我给这个目录一个很高的777权限。
但是由于这个目录是777的,所以用户user1在这个目录里创建的文件能被用户user2删除。
如果此时我不希望发生这种情况的话,就可以设置sticky位来限制这一操作。
如果去查看它的权限的话:
$ ls -l /data/shared_files
drwxrwxrwxt 1 root root 68248 Oct 31 2025 /data/shared_files
可以看到在末尾有一个t,来表示sticky位为1。
如何设置特殊的权限位
可以理解成在原本的9位二进制数的前面再增加三位二进制位,分别表示setuid、setgid和sticky位。
三个三个为一组转为十进制数,就能形成一个四位数的十进制数了。
例如:3775第一位是3(10)=011(2),表示setgid=1, sticky=1,显然是给某个目录设置的权限(如前文所述,sticky只能给目录设置,不能给文件设置),所以可以:
chmod 3775 ./dir1
来给目录dir1来设置这一权限了。