Linux 下的文件和文件夹除了拥有 rwx 这三种基本权限以外,还可能有三种特殊的权限:setuid(SUID)、setgid(SGID)和sticky bit(SBIT),其具体描述如下:
setuid(SUID)
首先要强调,SUID 仅对二进制程序文件有效。
当一个二进制程序设有 SUID 时,其权限显示如下(以 /bin/passwd 为例):
[admin@localhost ~]$ ll /bin/passwd
-rwsr-xr-x. 1 root root 27864 Aug 18 2014 /bin/passwd
owner 的 x 权限位是一个小写字母 s,那么 SUID 能够起到什么作用呢?
简单点说就是:如果一个程序设有 SUID,当程序所有者以外的用户有这个程序的 x 权限时,他执行这个程序时就暂时的拥有这个程序所有者的权限。听不懂?我们来看一个测试程序:
//test.c
#include<stdio.h>
int main()
{
FILE *fp;
fp = fopen("tmp", "w"); //在当前目录建立名为 tmp 的文件,这需要对该文件夹的 w 权限
fclose(fp);
return 0;
}
这个程序执行时会在当前文件夹下建立一个名为“tmp“的文件,这当然需要对当前文件夹的 w 权限。我们将 test.c 编译连接,得到a.out二进制可执行文件,然后建立一个 test 用户,这个用户不属于 admin 用户组,因此没有对当前目录的 w 权限,先使用 admin 用户测试:
[admin@localhost test]$ ll -d
drwxrwxr-x. 2 admin admin 80 May 30 22:49 . #当前目录的权限设置
[admin@localhost test]$ ll
total 16
-rwxrwxr-x. 1 admin admin 8608 May 30 22:24 a.out
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c
[admin@localhost test]$ ./a.out #执行a.out
[admin@localhost test]$ ll
total 16
-rwxrwxr-x. 1 admin admin 8608 May 30 22:24 a.out
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c
-rw-rw-r--. 1 admin admin 0 May 30 22:50 tmp #生成了 tmp 文件
然后删除 tmp 文件,使用 test 用户运行该程序:
[admin@localhost test]$ rm -f tmp #删除 tmp 文件
[admin@localhost test]$ ll
total 16
-rwxrwxr-x. 1 admin admin 8608 May 30 22:24 a.out
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c
[admin@localhost test]$ su -- test #登录 test 用户
Password:
[test@localhost test]$ ./a.out #运行 a.out
Segmentation fault (core dumped) #运行时出错
[test@localhost test]$ ll
total 16
-rwxrwxr-x. 1 admin admin 8608 May 30 22:24 a.out
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c #并未生成 tmp 文件
test 用户虽然拥有对 a.out 的 x 权限,但要想执行成功这个程序,生成 tmp 文件是需要对当前文件夹的 w 权限的。由于 test 用户并没有对当前文件夹的 w 权限,所以运行程序时会出错。
如果对 a.out 设置了 SUID 呢?测试如下:
[test@localhost test]$ exit #登出 test 用户,使用 admin 用户
exit
[admin@localhost test]$ chmod u+s a.out #为 a.out 设置 SUID
[admin@localhost test]$ ll
total 16
-rwsrwxr-x. 1 admin admin 8608 May 30 22:24 a.out #设置成功
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c
[admin@localhost test]$ su -- test #使用 test 用户登录
Password:
[test@localhost test]$ ./a.out #执行 a.out
#无出错信息
[test@localhost test]$ ll
total 16
-rwsrwxr-x. 1 admin admin 8608 May 30 22:24 a.out
-rw-rw-r--. 1 admin admin 187 May 30 22:24 test.c
-rw-rw-r--. 1 admin test 0 May 30 23:00 tmp #成功生成 tmp 文件
哈哈,这次成功了,因为 a.out 设置了SUID,当 test 执行这个程序时是拥有 admin 所拥有的权限的,也就是拥有对当前文件夹的 w 权限,所以才成功生成了 tmp 文件。不信你把 admin 对当前目录的 w 权限拿掉,试试还能不能生成 tmp 文件。
你每次修改你密码时,都和这个 SUID 有很大关系,因为普通用户是没有权限修改 shadow 文件的,但是由于 passwd 设置有 SUID,所以普通用户都能执行 passwd 间接修改 shadow 文件,进而达到修改密码的目的。
setgid(SGID)
二进制文件或文件夹设有 SGID 时,权限如下(以我自己创建的 test 文件夹为例):
[admin@localhost test]$ ll -d
drwxrwsr-x. 2 admin admin 40 May 30 23:41 .
group 的 x 权限位是一个小写字母 s。
SGID 对二进制程序和文件夹有效,当二进制程序设有 SGID 时,和设有 SUID 相似,只是普通用户执行程序时,临时地获得了程序所属用户组的权限,而不是所属用户的权限,在此不再验证。
当文件夹设有 SGID 权限时,那么如果文件夹所有组以外的用户拥有对该文件夹的 w 权限时,如果用户在该文件夹建立一个新文件,这个新文件的所有组为文件夹所有组:
[admin@localhost test]$ ll -d
drwxrwxrwx. 2 admin admin 40 May 30 23:41 . #初始无 SGID
[admin@localhost test]$ su -- test
Password:
[test@localhost test]$ touch testdoc #test用户建立一个新文件
[test@localhost test]$ ll
total 0
-rw-rw-r--. 1 test test 0 May 30 23:47 testdoc #新文件所有组为 test 所属组
[test@localhost test]$ exit
exit
[admin@localhost test]$ chmod g+s . #设置 SGID
[admin@localhost test]$ ll -d
drwxrwsrwx. 2 admin admin 60 May 30 23:47 .
[admin@localhost test]$ su -- test
Password:
[test@localhost test]$ touch newtestdoc # test 用户建立一个新文件
[test@localhost test]$ ll
total 0
-rw-rw-r--. 1 test admin 0 May 30 23:48 newtestdoc #新文件所有组为 admin
-rw-rw-r--. 1 test test 0 May 30 23:47 testdoc
SGID 在小组协作时起到了重要的作用。
sticky bit(SBIT)
SBIT 只对文件夹有效。
/tmp文件夹就是一个设有 SBIT 的例子:
drwxrwxrwt. 16 root root 400 May 30 23:59 tmp
others 的 x 位是一个小写字母t,SBIT 又能起到什么作用呢?
当一个文件夹设有 SBIT 时,如果一个用户有权限在该文件夹下新建文件(夹),那么新建的文件(夹)只有该用户和 root 能够进行删除、重命名、移动操作,而其他用户不能进行该操作,即使其他用户拥有对该目录的 w 权限:
[admin@localhost tmp]$ touch admindoc # admin 用户创建一个新文件
[admin@localhost tmp]$ chmod 777 admindoc #设置新文件权限
[admin@localhost tmp]$ su -- test #使用 test 用户登录
Password:
[test@localhost tmp]$ ll -d
drwxrwxrwt. 16 root root 400 May 31 00:09 . #当前目录的权限设置,test 用户拥有 w 权限
[test@localhost tmp]$ ll admindoc #文件的权限设置
-rwxrwxrwx. 1 admin admin 0 May 31 00:09 admindoc
[test@localhost tmp]$ mv admindoc testdoc
mv: cannot move ‘admindoc’ to ‘testdoc’: Operation not permitted #无权限
[test@localhost tmp]$ rm admindoc
rm: cannot remove ‘admindoc’: Operation not permitted #无权限
以上即为我对 setuid(SUID)、setgid(SGID)和sticky bit(SBIT)的理解。
(setuid 和 setgid 实际上可以从进程权限的角度分析)