因为用户在UNIX下常常会遇到SUID、SGID的概念,并且SUID和SGID涉及到系统安全,因此用户也比较关心这个问题。关于SUID、SGID的问题也常常有人提问,但回答的人通常答得不够详细,加上曾经回答过两个网友的问题,还查了一些资料,决定整理成本文,以供你们参考。限于本人的水平问题,文章中若是有不当之处,请广大网友指正。git
一. UNIX下关于文件权限的表示方法和解析
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和-:安全
第8-6位、5-3位、2-0位分别表示文件全部者的权限,同组用户的权限,其余用户的权限,其形式为rwx:bash
# 示例 $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组的成员对文件有读和执行权限,其余的用户对这个文件没有权限。网络
若是一个文件被设置了SUID或SGID位,会分别表如今全部者或同组用户的权限的可执行位上。例如:socket
-rwsr-xr-x 表示SUID和全部者权限中可执行位被设置 -rwSr--r-- 表示SUID被设置,但全部者权限中可执行位没有被设置 -rwxr-sr-x 表示SGID和同组用户权限中可执行位被设置 -rw-r-Sr-- 表示SGID被设置,但同组用户权限中可执行位没有被设置
其实在UNIX的实现中,文件权限用12个二进制位表示,若是该位置上的值是1,表示有相应的权限:函数
11 10 9 8 7 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位。测试
-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设置 chmod g+s filename 设置SGID位 chmod g-s filename 去掉SGID设置
另一种方法是chmod命令用八进制表示方法的设置。若是明白了前面的12位权限表示法也很简单。ui
二. SUID和SGID的详细解析.net
因为SUID和SGID是在执行程序(程序的可执行位被设置)时起做用,而可执行位只对普通文件和目录文件有意义,因此设置其余种类文件的SUID和SGID位是没有多大意义的。 首先讲普通文件的SUID和SGID的做用。
例子: 若是普通文件myfile是属于foo用户的,是可执行的,如今没设SUID位,ls命令显示以下:
-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来肯定进程对资源的访问权限。
一个进程若是没有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,例如kevin用户运行myfile,euid=200,egid=201,uid=204,gid=202,则这个进程具备它的属主foo的资源访问权限。
SUID的做用就是这样:让原本没有相应权限的用户运行这个程序时,能够访问他没有权限访问的资源。passwd就是一个很鲜明的例子。
SUID的优先级比SGID高,当一个可执行程序设置了SUID,则SGID会自动变成相应的egid。
下面讨论一个例子:
UNIX系统有一个/dev/kmem的设备文件,是一个字符设备文件,里面存储了核心程序要访问的数据,包括用户的口令。因此这个文件不能给通常的用户读写,权限设为:
cr--r----- 1 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程序设置为root用户的程序,而后设置SUID位,不也行吗?这的确能够解决问题,但实际中为何不这样作呢?由于SGID的风险比SUID小得多,因此出于系统安全的考虑,应该尽可能用SGID代替SUID的程序,若是可能的话。下面来讲明一下SGID对目录的影响。SUID对目录没有影响。若是一个目录设置了SGID位,那么若是任何一个用户对这个目录有写权限的话,他在这个目录所创建的文件的组都会自动转为这个目录的属主所在的组,而文件全部者不变,仍是属于创建这个文件的用户。
三. 关于SUID和SGID的编程
和SUID和SGID编程比较密切相关的有如下的头文件和函数:
#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 setregid (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 # ./lsusb ... $ su aaa(普通用户) $./lsusb ... # 是否是如今显示出错? $ su $ chmod 4755 lsusb $ su aaa $ ./lsusb
如今明白了吗?原本是只有root用户才能执行的命令,加了SUID后,普通用户就能够像root同样的用,权限提高了。上面是对于文件来讲的,对于目录也差很少!
目录的S属性使得在该目录下建立的任何文件及子目录属于该目录所拥有的组,目录的T属性使得该目录的全部者及root才能删除该目录。还有对于s与S,设置SUID/SGID须要有运行权限,不然用ls -l后就会看到S,证实你所设置的SUID/SGID没有起做用。
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
咱们能够看到passwd文件只有对于root用户是可写的,而对于全部的他用户来讲都是没有写权限的。那么一个普通的用户如何可以经过运行passwd命令修改这个passwd文件呢?
为了解决这个问题,SUID/SGID便应运而生。并且AT&T对它申请了专利。 呵呵。
SUID和SGID是如何解决这个问题呢?
首先,咱们要知道一点:进程在运行的时候,有一些属性,其中包括 实际用户ID,实际组ID,有效用户ID,有效组ID等。 实际用户ID和实际组ID标识咱们是谁,谁在运行这个程序,通常这2个字段在登录时决定,在一个登录会话期间, 这些值基本上不改变。 而有效用户ID和有效组ID则决定了进程在运行时的权限。内核在决定进程是否有文件存取权限时,是采用了进程的有效用户ID来进行判断的。
知道了这点,咱们来看看SUID的解决途径:
当一个程序设置了为SUID位时,内核就知道了运行这个程序的时候,应该认为是文件的全部者在运行这个程序。即该程序运行的时候,有效用户ID是该程序的全部者。举个例子:
$ ls -l passwd -r-s--s--x 1 root root 16336 Feb 14 2003 passwd
虽然你以test登录系统,可是当你输入passwd命令来更改密码的时候,因为passwd设置了SUID位,所以虽然进程的实际用户ID是test对应的ID,可是进程的有效用户ID则是passwd文件的全部者root的ID,所以能够修改/etc/passwd文件。
让咱们看另一个例子。
ping命令应用普遍,能够测试网络是否链接正常。ping在运行中是采用了ICMP协议,须要发送ICMP报文。可是只有root用户才能创建ICMP报文,如何解决这个问题呢?一样,也是经过SUID位来解决。
$ ls -l /bin/ping -rwsr-sr-x 1 root root 28628 Jan 25 2003 /bin/ping
咱们能够测试一下,若是去掉ping的SUID位,再用普通用户去运行命令,看会怎么样。
$ chmod u-s /bin/ping $ ls -l ping -rwxr-xr-x 1 root root 28628 Jan 25 2003 ping $ su test $ ping byhh.net ping: icmp open socket: Operation not permitted
SUID虽然很好了解决了一些问题,可是同时也会带来一些安全隐患。由于设置了 SUID 位的程序若是被攻击(经过缓冲区溢出等方面),那么hacker就能够拿到root权限。 所以在安全方面特别要注意那些设置了SUID的程序。
经过如下的命令能够找到系统上全部的设置了suid的文件:
$ find / -perm -04000 -type f -ls
对于这里为何是4000,你们能够看一下前面的st_mode的各bit的意义就明白了。 在这些设置了suid的程序里,若是用不上的,就最好取消该程序的suid位。