Linux SetGID(SGID)文件特殊权限用法详解

前面学习了 SetUID,那么,什么是 SetGID 呢?很简单,当 s 权限位于所属组的 x 权限位时,就被称为 SetGID,简称 SGID 特殊权限。例如:

[root@localhost ~]# ll /usr/bin/locate
-rwx--s--x. 1 root slocate 35612 8月24 2010 /usr/bin/locate

与 SUID 不同的是,SGID 既可以对文件进行配置,也可以对目录进行配置。

SetGID(SGID)对文件的作用

同 SUID 类似,对于文件来说,SGID 具有如下几个特点:
  • SGID 只针对可执行文件有效,换句话说,只有可执行文件才可以被赋予 SGID 权限,普通文件赋予 SGID 没有意义。
  • 用户需要对此可执行文件有 x 权限;
  • 用户在执行具有 SGID 权限的可执行文件时,用户的群组身份会变为文件所属群组;
  • SGID 权限赋予用户改变组身份的效果,只在可执行文件运行过程中有效;

其实,SGID 和 SUID 的不同之处就在于,SUID 赋予用户的是文件所有者的权限,而 SGID 赋予用户的是文件所属组的权限,就这么简单。

就以本节开头的 locate 命令为例,可以看到,/usr/bin/locate 文件被赋予了 SGID 的特殊权限,这就意味着,当普通用户使用 locate 命令时,该用户的所属组会直接变为 locate 命令的所属组,也就是 slocate。

我们知道,locate 命令是用于在系统中按照文件名查找符合条件的文件的,当执行搜索操作时,它会通过搜索 /var/lib/mlocate/mlocate.db 这个数据库中的数据找到答案,我们来看看此数据库的权限:

[root@localhost ~]# ll /var/lib/mlocate/mlocate.db
-rw-r-----. 1 root slocate 1838850 1月20 04:29 /var/lib/mlocate/mlocate.db

可以看到,mlocate.db 文件的所属组为 slocate,虽然对文件只拥有 r 权限,但对于普通用户执行 locate 命令来说,已经足够了。一方面,普通用户对 locate命令拥有执行权限,其次,locate 命令拥有 SGID 权限,这使得普通用户在执行 locate 命令时,所属组身份会变为 slocate,而 slocate 对 mlocate.db 数据库文件拥有 r 权限,所以即便是普通用户,也可以成功执行 locate 命令。

再次强调,无论是 SUID,还是 SGID,它们对用户身份的转换,只有在命令执行的过程中有效,一旦命令执行完毕,身份转换也随之失效。

SetGID(SGID)对目录的作用

事实上,SGID 也能作用于目录,且这种用法很常见。

当一个目录被赋予 SGID 权限后,进入此目录的普通用户,其有效群组会变为该目录的所属组,会就使得用户在创建文件(或目录)时,该文件(或目录)的所属组将不再是用户的所属组,而使用的是目录的所属组。

也就是说,只有当普通用户对具有 SGID 权限的目录有 rwx 权限时,SGID 的功能才能完全发挥。比如说,如果用户对该目录仅有 rx 权限,则用户进入此目录后,虽然其有效群组变为此目录的所属组,但由于没有 x 权限,用户无法在目录中创建文件或目录,SGID 权限也就无法发挥它的作用。

举个例子:

[root@localhost ~]# cd /tmp
#进入临时目录做此实验。因为只有临时目录才允许普通用户修改
[root@localhost tmp]# mkdir dtest
#建立测试目录
[root@localhost tmp]# chmod g+s dtest
#给测试目录赋予SetGID权限
[root@localhost tmp]# ll -d dtest
drwxr-sr-x 2 root root 4096 Apr 19 06:04 dtest
#SetGID权限已经生效
[root@localhost tmp]# chmod 777 dtest
#给测试目录赋予777权限,让普通用户可以写
[root@localhost tmp]# su - lamp
[lamp@localhost ~]# grep lamp /etc/passwd /etc/group
/etc/passwd:lamp:x:501:501::/home/lamp:/bin/bash
/etc/group:lamp:x:501:
#切换成普通用户lamp,此用户的所属群组为 lamp
[lamp@localhost ~]$ cd /tmp/dtest/
#普通用户进入测试目录
[lamp@localhost dtest]$ touch abc
[lamp@localhost dtest]$ mkdir zimulu
#在此目录中创建新的文件 abc 和子目录 zimulu
[lamp@localhost dtest]$ ll
total 0
-rw-rw-r--. 1 lamp root 0 Apr 19 06:07 abc
drwxrwsr-x. 2 lamp root 40 Apr 19 06:07 zimulu

可以看到,虽然是 lamp 用户创建的 abc 文件和 zimulu 目录,但它们的所属组都不是 lamp(lamp 用户的所属组),而是 root(dtest 目录的所属组)。