1、由于用户在 UNIX 下经常会遇到 SUID、SGID 的概念,而且 SUID 和 SGID 涉及到系统安全,所以用户也比较关心这个问题。关于 SUID、SGID 的问题也经常有人提问,但回答的人一般答得不够详细,加上曾经回答过两个网友的问题,还查了一些资料,决定整理成本文,以供大家参考。限于本人的水平问题,文章中如果有不当之处,请广大网友指正。 设置文件权限位时我们一般忽略了 suid/guid 的存在,现在看看它们到底是怎么回事。 suid/guid 是什么? suid 意味着如果 A 用户对属于他自己的 shell 脚本文件设置了这种权限,那么其他用户在执行这个脚本的时候就拥有了 A 用
2、户的权限。所以,如果 root 用户对某一脚本设置了这一权限的话则其他用户执行该脚本的时候则拥有了 root 用户权限。同理,guid 意味着执行相应脚本的用户则拥有了该文件所属用户组中用户的权限。为什么使用 suid/guid? 举个例子:要对数据库系统进行备份需要有系统管理权限,那么我可以写几个脚本,并设置了它们的 guid,这样我指定的一些用户只要执行这些脚本就能够完成相应的工作,而无须以数据库管理员的身份登录,以免不小心破坏了数据库服务器。通过执行这些脚本,他们可以完成数据库备份及其他管理任务,但是在这些脚本运行结束之后,他们就又回复到他们作为普通用户的权限。 有相当一些命令也设置了
3、suid 和 guid。如果想找出这些命令,可以进入/bin 或/sb in 目录,执行下面的命令: $ ls -l | grep .s 上面的命令是用来查找 suid 文件的; $ ls -l | grep .ss 上面的命令是用来查找 suid 和 guid 的。 如何设置 suid/guid? 如果希望设置 suid,那么就将相应的权限位之前的那一位设置为 4;如果希望设置guid,那么就将相应的权限位之前的那一位设置为 2;如果希望两者都置位,那么将相应的权限位之前的那一位设置为 4+2。 一旦设置了这一位,一个 s 将出现在 x 的位置上。记住:在设置 suid 或 guid 的同时
4、,相应的执行权限位必须要被设置。例如,如果希望设置 guid,那么必须要让该用户组具有执行权限。 如果想要对文件 login 设置 suid,它当前所具有的权限为 rwx rw- r- (741),需要在使用 chmod 命令时在该权限数字的前面加上一个 4,即 chmod 4741,这将使该文件的权限变为 rws rw- r-。 $ chmod 4741 login 还可以使用符号方式来设置 suid/guid。如果某个文件具有这样的权限: rwx r-x r-x,那么可以这样设置其 suid/guid: chmod u+s chmod u+g 一、UNIX 下关于文件权限的表示方法和解析
5、SUID 是 Set User ID, SGID 是 Set Group ID 的意思。 UNIX 下可以用 ls -l 命令来看到文件的权限。用 ls 命令所得到的表示法的格式是类似这样的:-rwxr-xr-x 。下面解析一下格式所表示的意思。这种表示方法一共有十位: 9 8 7 6 5 4 3 2 1 0 - r w x r - x r - x 第 9 位表示文件类型,可以为 p、d 、l 、s 、c、b 和-: p 表示命名管道文件 d 表示目录文件 l 表示符号连接文件 -表示普通文件 s 表示 socket 文件 c 表示字符设备文件 b 表示块设备文件 第 8-6 位、5-3 位、
6、2-0 位分别表示文件所有者的权限,同组用户的权限,其他用户的权限,其形式为 rwx: r 表示可读,可以读出文件的内容 w 表示可写,可以修改文件的内容 x 表示可执行,可运行这个程序 没有权限的位置用-表示 例子: ls -l myfile 显示为: -rwxr-x- 1 foo staff 7734 Apr 05 17:07 myfile 表示文件 myfile 是普通文件,文件的所有者是 foo 用户,而 foo 用户属于 staff 组,文件只有 1 个硬连接,长度是 7734 个字节,最后修改时间 4 月 5 日 17:07。 所有者 foo 对文件有读写执行权限,staff 组的
7、成员对文件有读和执行权限,其他的用户对这个文件没有权限。 如果一个文件被设置了 SUID 或 SGID 位,会分别表现在所有者或同组用户的权限的可执行位上。例如: 1、-rwsr-xr-x 表示 SUID 和所有者权限中可执行位被设置 2、-rwSr-r- 表示 SUID 被设置,但所有者权限中可执行位没有被设置 3、-rwxr-sr-x 表示 SGID 和同组用户权限中可执行位被设置 4、-rw-r-Sr- 表示 SGID 被设置,但同组用户权限中可执行位没有被社 其实在 UNIX 的实现中,文件权限用 12 个二进制位表示,如果该位置上的值是 1,表示有相应的权限: 11 10 9 8 7
8、 6 5 4 3 2 1 0 S G T r w x r w x r w x 第 11 位为 SUID 位,第 10 位为 SGID 位,第 9 位为 sticky 位,第 8-0 位对应于上面的三组 rwx 位。 11 10 9 8 7 6 5 4 3 2 1 0 上面的-rwsr-xr-x 的值为: 1 0 0 1 1 1 1 0 1 1 0 1 -rw-r-Sr-的值为: 0 1 0 1 1 0 1 0 0 1 0 0 给文件加 SUID 和 SUID 的命令如下: chmod u+s filename 设置 SUID 位 chmod u-s filename 去掉 SUID 设置 ch
9、mod g+s filename 设置 SGID 位 chmod g-s filename 去掉 SGID 设置 另外一种方法是 chmod 命令用八进制表示方法的设置。如果明白了前面的 12 位权限表示法也很简单。 二、SUID 和 SGID 的详细解析 由于 SUID 和 SGID 是在执行程序(程序的可执行位被设置)时起作用,而可执行位只对普通文件和目录文件有意义,所以设置其他种类文件的 SUID 和 SGID 位是没有多大意义的。 首先讲普通文件的 SUID 和 SGID 的作用。例子: 如果普通文件 myfile 是属于 foo 用户的,是可执行的,现在没设 SUID 位,ls 命令
10、显示如下: -rwxr-xr-x 1 foo staff 7734 Apr 05 17:07 myfile 任何用户都可以执行这个程序。UNIX 的内核是根据什么来确定一个进程对资源的访问权限的呢?是这个进程的运行用户的(有效)ID ,包括 user id 和 group id。用户可以用 id 命令来查到自己的或其他用户的user id 和 group id。 除了一般的 user id 和 group id 外,还有两个称之为 effective 的 id,就是有效 id,上面的四个 id 表示为: uid,gid,euid ,egid 。内核主要是根据 euid 和 egid 来确定进程
11、对资源的访问权限。 一个进程如果没有 SUID 或 SGID 位,则 euid=uid egid=gid,分别是运行这个程序的用户的 uid 和 gid。例如 kevin 用户的 uid 和 gid 分别为 204 和 202,foo 用户的 uid 和gid 为 200,201,kevin 运行 myfile 程序形成的进程的euid=uid=204,egid=gid=202,内核根据这些值来判断进程对资源访问的限制,其实就是 kevin 用户对资源访问的权限,和 foo 没关系。 如果一个程序设置了 SUID,则 euid 和 egid 变成被运行的程序的所有者的 uid 和gid,例如
12、kevin 用户运行 myfile,euid=200,egid=201,uid=204,gid=202,则这个进程具有它的属主 foo 的资源访问权限。 SUID 的作用就是这样:让本来没有相应权限的用户运行这个程序时,可以访问他没有权限访问的资源。passwd 就是一个很鲜明的例子。 SUID 的优先级比 SGID 高,当一个可执行程序设置了 SUID,则 SGID 会自动变成相应的 egid。 下面讨论一个例子: UNIX 系统有一个/dev/kmem 的设备文件,是一个字符设备文件,里面存储了核心程序要访问的数据,包括用户的口令。所以这个文件不能给一般的用户读写,权限设为:cr-r- 1
13、 root system 2, 1 May 25 1998 kmem 但 ps 等程序要读这个文件,而 ps 的权限设置如下: -r-xr-sr-x 1 bin system 59346 Apr 05 1998 ps 这是一个设置了 SGID 的程序,而 ps 的用户是 bin,不是 root,所以不能设置 SUID来访问 kmem,但大家注意了, bin 和 root 都属于 system 组,而且 ps 设置了 SGID,一般用户执行 ps,就会获得 system 组用户的权限,而文件 kmem 的同组用户的权限是可读,所以一般用户执行 ps 就没问题了。但有些人说,为什么不把 ps 程序
14、设置为 root 用户的程序,然后设置 SUID 位,不也行吗?这的确可以解决问题,但实际中为什么不这样做呢?因为SGID 的风险比 SUID 小得多,所以出于系统安全的考虑,应该尽量用 SGID 代替 SUID 的程序,如果可能的话。下面来说明一下 SGID 对目录的影响。 SUID 对目录没有影响。如果一个目录设置了 SGID 位,那么如果任何一个用户对这个目录有写权限的话,他在这个目录所建立的文件的组都会自动转为这个目录的属主所在的组,而文件所有者不变,还是属于建立这个文件的用户。 三、关于 SUID 和 SGID 的编程 和 SUID 和 SGID 编程比较密切相关的有以下的头文件和函
15、数: #include #include uid_t getuid(void); uid_t geteuid(void); gid_t getgid (void); gid_t getegid (void); int setuid (uid_t UID); int setruid (uid_t RUID); int seteuid (uid_t EUID); int setreuid (uid_t RUID,uid_t EUID); int setgid (gid_t GID); int setrgid (gid_t RGID); int setegid (git_t EGID); int s
16、etregid (gid_t RGID, gid_t EGID); 具体这些函数的说明在这里就不详细列出来了,要用到的可以用 man 查。 SUID/SGID : 假如你有文件 a.txt #ls -l a.txt -rwxrwxrwx #chmod 4777 a.txt -rwsrwxrwx =注意 s 位置 #chmod 2777 a.txt -rwxrwsrwx =注意 s 位置 #chmod 7777 a.txt -rwsrwxswt =出现了 t,t 的作用在内存中尽量保存 a.txt,节省系统再加载的时间. 现在再看前面设置 SUID/SGID 作用: #cd /sbin #./l
17、susb . #su aaa(普通用户) $./lsusb . 是不是现在显示出错? $su #chmod 4755 lsusb #su aaa $./lsusb . 现在明白了吗?本来是只有 root 用户才能执行的命令,加了 SUID 后,普通用户就可以像 root 一样的用,权限提升了。上面是对于文件来说的,对于目录也差不多! 目录的 S 属性使得在该目录下创建的任何文件及子目录属于该目录所拥有的组,目录的T 属性使得该目录的所有者及 root 才能删除该目录。还有对于 s 与 S,设置 SUID/SGID 需要有运行权限,否则用 ls -l 后就会看到 S,证明你所设置的 SUID/S
18、GID 没有起作用。 Why we need suid,how do we use suid? r - 读访问 w - 写访问 x - 执行许可 s - SUID/SGID t - sticky 位 那么 suid/sgid 是做什么的? 为什么会有 suid 位呢? 要想明白这个,先让我们看个问题:如果让每个用户更改自己的密码? 用户修改密码,是通过运行命令 passwd 来实现的。最终必须要修改/etc/passwd 文件,而 passwd 的文件的属性是: #ls -l /etc/passwd -rw-r-r- 1 root root 2520 Jul 12 18:25 passwd 我
19、们可以看到 passwd 文件只有对于 root 用户是可写的,而对于所有的他用户来说都是没有写权限的。 那么一个普通的用户如何能够通过运行 passwd 命令修改这个 passwd 文件呢? 为了解决这个问题,SUID/SGID 便应运而生。而且 AT&T 对它申请了专利。 呵呵。 SUID 和 SGID 是如何解决这个问题呢? 首先,我们要知道一点:进程在运行的时候,有一些属性,其中包括 实际用户 ID,实际组 ID,有效用户 ID,有效组 ID 等。 实际用户 ID 和实际组 ID 标识我们是谁,谁在运行这个程序,一般这 2 个字段在登陆时决定,在一个登陆会话期间, 这些值基本上不改变。
20、 而有效用户 ID 和有效组 ID 则决定了进程在运行时的权限。内核在决定进程是否有文件存取权限时,是采用了进程的有效用户 ID 来进行判断的。 知道了这点,我们来看看 SUID 的解决途径: 当一个程序设置了为 SUID 位时,内核就知道了运行这个程序的时候,应该认为是文件的所有者在运行这个程序。即该程序运行的时候,有效用户 ID 是该程序的所有者。举个例子:rootsgrid5 bin# ls -l passwd -r-s-s-x 1 root root 16336 Feb 14 2003 passwd 虽然你以 test 登陆系统,但是当你输入 passwd 命令来更改密码的时候,由于
21、passwd设置了 SUID 位,因此虽然进程的实际用户 ID 是 test 对应的 ID,但是进程的有效用户 ID则是 passwd 文件的所有者 root 的 ID,因此可以修改/etc/passwd 文件。 让我们看另外一个例子。 ping 命令应用广泛,可以测试网络是否连接正常。ping 在运行中是采用了 ICMP 协议,需要发送 ICMP 报文。但是只有 root 用户才能建立 ICMP 报文,如何解决这个问题呢?同样,也是通过 SUID 位来解决。 rootsgrid5 bin# ls -l /bin/ping -rwsr-sr-x 1 root root 28628 Jan 25
22、 2003 /bin/ping 我们可以测试一下,如果去掉 ping 的 SUID 位,再用普通用户去运行命令,看会怎么样。rootsgrid5 bin#chmod u-s /bin/ping rootsgrid5 bin# ls -l ping -rwxr-xr-x 1 root root 28628 Jan 25 2003 ping rootsgrid5 bin#su test testsgrid5 bin$ ping ping: icmp open socket: Operation not permitted SUID 虽然很好了解决了一些问题,但是同时也会带来一些安全隐患。 因为设置了 SUID 位的程序如果被攻击( 通过缓冲区溢出等方面), 那么 hacker 就可以拿到 root 权限。 因此在安全方面特别要注意那些设置了 SUID 的程序。 通过以下的命令可以找到系统上所有的设置了 suid 的文件: rootsgrid5 /# find / -perm -04000 -type f -ls 对于这里为什么是 4000,大家可以看一下前面的 st_mode 的各 bit 的意义就明白了。 在这些设置了 suid 的程序里,如果用不上的,就最好取消该程序的 suid 位