Linux Setuid(SUID)和Setgid(SGID) sticky bit
http://www.php100.com/html/webkaifa/Linux/2010/0812/6392.html
1、setuid和setgid的解说
setuid和setgid位是让普通用户可以以root用户的角色运行只有root帐号才能运行的程序或命令。比如我们用普通用户运行passwd命令来更改自己的口令,实际上最终更改的是/etc/passwd文件,我们知道/etc/passwd文件是用户管理的配置文件,只有root权限的用户才能更改:
[root@localhost ~]# ls -l /etc/passwd
-rw-r--r-- 1 root root 2379 04-21 13:18 /etc/passwd
作为普通用户,如果修改自己的口令通过修改/etc/passwd肯定是不可完成的任务,是不是可以通过一个命令来修改呢?答案是肯定的,作为普通用户可以通过passwd 来修改自己的口令,这归功于passwd命令的权限。我们来看一下:
[root@localhost ~]# ls -l /usr/bin/passwd
-r-s--x--x 1 root root 21944 02-12 16:15 /usr/bin/passwd
因为/usr/bin/passwd 文件已经设置了setuid 权限位(也就是r-s--x--x中的s),所以普通用户能临时变成root,间接的修改/etc/passwd,以修改自己口令的权限。
我们在Linux 系统中的超级权限的控制中有提到过我们知道Linux的用户管理是极为严格的,不同的用户拥有不同的权限,为了完成只有root用户才能完成的工作,我们必须为普通用户提升权 限,最常用的方法就是su或sudo,虽然setuid 和setgid也是让普通用户超越自身拥有的普通权限达到root权限的方法,但我不推荐大家使用,因为它能为系统带来隐患!!
注意:setuid和setgid会面临风险,所以尽可能的少用,了解了解既可~~~
2、setuid和setgid的实例应用
我们想让一个普通用户beinan拥有root用户拥有超级rm删除权限,我们除了用su或sudo 临时切换到 root身份操作以外,还能怎么做呢???
[root@localhost ~]#cd /home 注:进入/home目录
[root@localhost home]# touch beinantest.txt 注:创建一个文件;
[root@localhost home]# ls -l beinantest.txt 注:查看文件属性;
-rw-r--r-- 1 root root 0 04-24 18:03 beinantest.txt 注:文件的属性;
[root@localhost home]# su beinan 注:切换到普通用户 beinan
[beinan@localhost home]$ rm -rf beinantest.txt 注:以普通用户身份来删除beinantest.txt文件;
rm: 无法删除 beinantest.txt: 权限不够
那我们怎么才能让beinan 这个普通用户也拥有root超级的rm 删除功力呢?
[root@localhost ~]# ls -l /bin/rm
-rwxr-xr-x 1 root root 93876 02-11 14:43 /bin/rm
[root@localhost ~]# chmod 4755 /bin/rm 注:设置rm的权限为4755 , 就把setuid 位设置好了
[root@localhost ~]# ls -l /bin/rm
-rwsr-xr-x 1 root root 43980 02-11 14:43 /bin/rm
[root@localhost ~]# cd /home/
[root@localhost home]# su beinan 注:切换到beinan用户身份;
[root@localhost home]$ ls -l beinantest.txt 注:查看文件属性;
-rw-r--r-- 1 root root 0 04-24 18:03 beinantest.txt 注:文件的属性;
[beinan@localhost home]$ rm -rf beinantest.txt 注:删除beinantest.txt文件;
我们只是设置了rm的setuid位,让普通用户在rm指令上有超级root的删除超级权力
通过这个例子,我们应该能明白setuid和setgid位的应用了,如同前面所说,让普通用户超越本身的能力,让普通用户能执行只有root才能 执行的命令在这一点,我们要和su和sudo 区分开来请参见su和sudo的文档:Linux 系统中的超级权限的控制
3、setuid和setgid的设置方法
第一种方法:八进制方法:
setuid位是的设置用八进制的4000,setgid占用的是八进制的2000 ;比如我们前面所说的 chmod 4755 /bin/rm 就是设置的setuid位;
至于setuid的设置方法,只是在我们通过chmod设置文件或目录权限位的八进制方法的前面多加一个数字,也就是4比如:
[root@localhost ~]# chmod 4755 /bin/rm 注:设置rm的权限为4755 , 就把setuid 位设置好了
作为setgid 位占用的是八进制的2000位,我们下面举个例子;
[root@localhost ~]# cd /home/
[root@localhost home]# mkdir slackdir
[root@localhost home]# ls -ld slackdir/
drwxr-xr-x 2 root root 4096 04-24 18:25 slackdir/
[root@localhost home]# chmod 2755 slackdir/
[root@localhost home]# ls -ld slackdir/
drwxr-sr-x 2 root root 4096 04-24 18:25 slackdir/
我们看到 slackdir这个目录,经过改变权限后的,目录所归属用户组的那三个权限位是 r-s 如果我们见到的是小写的s,表明文件所归属的用户组位有执行权限x因为我们用了2755 ,意思是说文件属主拥有可读可写可执行权限,所归属的用户组拥有可读可执行权限,并且设置了setuid,所以这时本来文件所归属的用户组拥有r-x,现 在加了setgid位,就把其中的x换成了s如果文件所归属的用户组没有执行权限,这个权限应该是S同理setuid位的中的大写的S和小写的s,也 是这个原理见下面的例子;
[root@localhost home]# chmod 2740 slackdir/
[root@localhost home]# ls -ld slackdir/
drwxr-S--- 2 root root 4096 04-24 18:25 slackdir/
这个例子是因为目录slackdir所归属的组没有执行权限,这时本来在执行权限位上显示-,由于有了setuid,所以显示为S
如果我们为一个文件的权限拥有 属主可读可写可执行所归的组拥有可读可执行,其它用户可读可执行,并且同时设置setuid和setgid位,我们应该怎么运行命令呢?
[root@localhost ~]# touch gooddoc.txt
[root@localhost ~]# ls -l gooddoc.txt
-rw-r--r-- 1 root root 0 04-24 18:47 gooddoc.txt
[root@localhost ~]# chmod 6755 gooddoc.txt
[root@localhost ~]# ls -l gooddoc.txt
-rwsr-sr-x 1 root root 0 04-24 18:47 gooddoc.txt
所以,同时设置setuid和setgid,就是把setuid和setgid两个八进位的值相加 (4000 2000=6000),然后加上文件或目录的权限位的三位数值(上面的例子是755),然后通过chmod 运行就行了所以上面例子中用了6755
第二种方法:通过助记语法;
还是延用chmod的助记语法,通过u+s 或u-s 来增减setuid位,同理,我们可以通过g+s 或g-s 来setgid位;
[root@localhost ~]# touch mydoc.txt 注:创建一个文件;
[root@localhost ~]# ls -l mydoc.txt
-rw-r--r-- 1 root root 0 04-24 19:00 mydoc.txt
[root@localhost ~]# chmod u+s mydoc.txt
[root@localhost ~]# ls -l mydoc.txt
-rwSr--r-- 1 root root 0 04-24 19:00 mydoc.txt
我们也可以用file命令来查看setuid和setgid位,当然也能用file来查看文件的类型;
比如:
[root@localhost ~]# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0xc101d30ff4513f2dbad17fcc483dcda4a38e1df0, stripped
http://blog.csdn.net/wowricky/article/details/6894538
setuid 和 setgid (全称分别是:set user ID upon execution 和 set group ID upon execution)是Unix的访问权限标志位,它允许用户以可执行文件owner或group的权限来运行这个可执行文件。它们经常适用于:为了运行特定的任务,可以允许用户暂时的提高权限。用处:暂时的权限提升。
什么情况下需要setuid 和 setgid呢?当task需要的权限高于用户的权限时,比如修改用户的登录密码。有些任务需要更高的权限可能不会立刻表现出来,比如ping,它需要发送和监听某个网络接口的控制包。
1. setuid作用于可执行文件
当一个二进制可执行文件被设置了setuid属性之后,在所创建的进程内部,有权限执行此文件的用户将会获得这个可执行文件的owner的权限(通常是root)。在进程内部,用户获取root权限之后,这个用户将可以做一下常规用户被限制做的事情,当然有些事情是禁止的:比如使用ptrace 、LD_LIBRARY_PATH, 或者给自己发送信号(但是从终端发送的信号是可以的)。由于潜在竞争条件,如果setuid 作用于shell 脚本,很多操作系统将会忽略掉setuid.
虽然setuid在很多场合是很有用的,但是如果一个可执行程序设计的不够好并被设置了setuid将会带来潜在的风险。人们能够利用有漏洞的程序获取永久的权限提升,或者让用户在无意之间运行一个特洛伊木马。
setgid能够改变group的权限,正如setuid改变user权限一样。
setuid作用于可执行文件解释了为什么系统调用chroot对于非root用户是不可用的。
可以通过chmod 来设置setuid 和 setguid的标志位(最高位),
4: for setuid
2: for setguid
1: 这个是粘滞位 //可以参考:http://blog.csdn.net/hzgdiyer/article/details/6788275
"chmod 6711 file" 将会设置setuid 和setguid, bits(6) 即位最高位。
另外还多系统也支持 “chmod ug+s"命令来设置.
下面的演示代码用来获取并显示出进程的real 和 effective 的用户(user)和组(group)的ID:
1.显示printid.c的代码,这段代码就是打印real/effective user/group ID
2.编译程序printid
3.运行程序printid,打印出了real/effective user/group ID
4.修改printid的owner为root
5.给文件printid添加setuid和setgid标志位
6.取消文件printid其它用户(other)的读r和执行x权限
7.显示文件printid属性
8.重新运行printid,
我们发现printid权限:
owner:root, rws
group:staff, r-s
other: ---
虽然other没有任何权限,但以用户bobie(对于问价printerid,bobie不是owner,也不是group,属于other)运行printid,依然可以运行,显然是添加了setuid的原因。
通过打印信息可以看到effective id 是0,正好是root的id,可以参考/etc/passwd(里面有每个用户/组对应的id)
//备注:如果这个程序是在volumn上运行且mounte时添加了'nosuid'选项,这个程序将会失败,没有打印信息;
//volumn: 可以再磁盘上创建卷(volumn),物理卷(PV)=》逻辑卷(LV)=>卷组(VG),最后将这卷组mounte到指定路径
[bobie]$ cat printid.c
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(void) {
printf(
" UID GID \n"
"Real %d Real %d \n"
"Effective %d Effective %d \n",
getuid (), getgid (),
geteuid(), getegid()
);
return getegid() ; /* always good to return something */
}
[bobie]$ cc printid.c -o printid
[bobie]$ ./printid
UID GID
Real 1008 Real 1008
Effective 1008 Effective 1008
[bobie]$ sudo chown root printid # to change the owner you need to sudo
Password:
[bobie]$ sudo chmod ug+s printid # SetUID and SetGID flags
[bobie]$ sudo chmod o-rx printid # Don't let Others read or execute it
[bobie]$ ls -l
-rwsr-s--- 1 root staff 6944 2011-10-06 10:22 printid
[bobie]$ ./printid
UID GID
Real 1008 Real 1008
Effective 0 Effective 20
2.setuid/setgid作用于路径
setuid和setgid作用于路径时,有完全不同的含义。
给路径设置setgid(chmod g+s),会导致路径下新建的文件和子文件夹继承它的group id, 而不创建文件或文件夹的用户的primary group id.【只有group id 受影响,owner id 不受影响】。另外,新创建的子文件夹还将继承setgid位。注意:给路径设置setgid,仅仅影响新建的文件和文件夹的group id,已经存在的文件和文件夹不受影响。
给已经存在的子文件夹设置setgid,必须手动来做,用如下命令:
[root@foo]# find /path/to/directory -type d -exec chmod g+s {} \;
给路径设置setuid,将会被Unix 和 Linux系统忽略。
3.安全
被设置setuid/setgid的程序必须小心的设计防止缓存区溢出攻击。缓存区溢出攻击成功的后果是:能够使攻击者利用进程的权限执行任意的代码。如果一个有漏洞的程序被设置了setuid,权限提升以root运行,攻击成功就会使攻击者获得root权限,这太可怕了。
4.历史
setuid 是 Dennis Ritchie发明的,他所在的公司AT&T, 于1972年申请专利,1979年专利获批,专利号:US 4135240 "Protection of data file contents".
http://waringid.blog.51cto.com/65148/95407
字符 | 含义 |
a | 修改所有用户的特权 |
g | 修改组用户的特权 |
o | 修改其它用户的特权 |
u | 修改所有者的权限 |
字符 | 含义 |
- | 删除当前的权限 |
= | 替换当前的权限 |
+ | 增加当前的权限 |
字符 | 含义 |
r | 读访问 |
w | 写访问 |
x | 执行访问 |
s | SUID或是SGID |
t | 粘附位 |
八进制数 | 权限 |
4000 | SUID |
2000 | SGID |
1000 | 粘附位 |
0400 | 所有者可读 |
0200 | 所有者可写 |
0100 | 所有者可执行 |
0040 | 组成员可读 |
0020 | 组成员可写 |
0010 | 组成员可执行 |
0004 | 其它用户可读 |
0002 | 其它用户可写 |
001 | 其它用户可执行 |
umask | 用户访问 | 组访问 | 其它 |
0000 | 所有 | 所有 | 所有 |
0002 | 所有 | 所有 | 读,执行 |
0007 | 所有 | 所有 | 无 |
0022 | 所有 | 读,执行 | 读,执行 |
0027 | 所有 | 读,执行 | 无 |
0077 | 所有 | 无 | 无 |
如果在目录上设置了这个位,那么大多数版本的unix不允许删除或重新命名该目录中的文件,除非你是该目录的属主,该文件的属主或超级用户.在这个目录上拥有写入权限是不够的.这相约定是让像/tmp之类的目录变得多少有些隐私性和安全性的一种尝试.
Solaris和HP-UX在处理粘附位目录的时候并不那么严格.如果对该目录有写入权限,即使不是属主,也能删除其中的文件.这实际上有许多意义,虽然对实际应用几乎没有什么影响。
Linux中的粘滞位
Sticky 位是一个访问权限标志位,可以用来标示文件和路径。
历史:
粘滞位是在1974年Unix的第5版中引入的,用来设置可执行文件。当可执行文件设置粘滞位之后,它能够指示操作系统在程序退出后,保留程序的代码段到swap空间。当程序再次执行时,内核只需将程序从swap搬到内存即可,这能够加速程序的执行。所以,频繁使用的程序比如编辑器能够更快的打开。目前,这种应用只是适用于HP-UX, NetBSD和UnixWare,Solaris在2005年放弃了这种应用,linux没有版本支持过这种行为。
当今使用:
当今,粘滞位最常用是应用于路径。当路径被设置粘滞位后,路径下的文件只有文件的owner, 或者root 才能够重命名、删除文件。如果没有粘滞位,任何用户,不管是不是owner, 只要有路径的写/执行权限就可以重命名、删除文件。典型的应用就是/tmp路径,粘滞位可以阻止一般用户删除/重命名其他用户的文件。这种特性首次引入是在1986年4.3BSD, 今天在现在的Unix系统中都可以找到这个特性。另外,Solaris定义了独有的行为:当粘滞位设置到非执行文件时,当访问这种文件时,内核将不会缓存。这常用于设置swap文件,用来阻止访问这些文件时冲刷掉系统缓存中更重要的数据。
Sticky bit在不同系统中的异同
HP-UX:当程序的最后一个用户退出时,阻止系统丢弃程序段swap-space image. 当下一个用户执行这个程序时,系统只需要swap in,而不需要重从磁盘新读入文件到内存,节约程序启动时间。
[...] prevents the system from abandoningthe swap-space image of the program-text portion of the file when its last userterminates. Then, when the next user of the file executes it, the text need notbe read from the file system but can simply be swapped in, thus saving time.
Linux: 当粘滞位设置到文件时,内核将会忽略。当设置路径时,路径中的文件只能够被root或者文件的owner重命名或者unlinked。
[...] the Linux kernel ignores the stickybit on files. [...] When the sticky bit is set on a directory, files in thatdirectory may only be unlinked or renamed by root or their owner.
举例:
Sticky bit 设置:
chmod 命令,可以用八进制模式1000或者它的符号t.
比如:添加粘滞位到路径/usr/local/tmp,
1. chmod +t /usr/local/tmp
2. chmod 1777 /usr/local/tmp
在Unix 文件系统 符号中,sticky bit t 是在最后一位。比如:在Solaris 8, /tmp路径默认有粘滞位,如下:
$ ls -ld /tmp
drwxrwxrwt 4 root sys 485 Nov 10 06:01 /tmp
如果粘滞位设置的路径或者文件没有可执行(x)位,它的符号用T(大写的t)
# ls -l test
-rw-r--r-- 1 root other 0 Nov 10 12:57 test
# chmod +t test; ls -l test
-rw-r--r-T 1 root other 0 Nov 10 12:57 test
From http://en.wikipedia.org/wiki/Sticky_bit