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作用于路径时,有完全不同的含义。
给路径设置set
gid(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 {} \;
给路径设置set
uid,将会被Unix 和 Linux系统
忽略。
3.安全
被设置setuid/setgid的程序必须小心的设计防止缓存区溢出攻击。缓存区溢出攻击成功的后果是:能够使攻击者利用进程的权限执行任意的代码。如果一个有漏洞的程序被设置了setuid,权限提升以root运行,攻击成功就会使攻击者获得root权限,这太可怕了。
4.历史
setuid 是 Dennis Ritchie发明的,他所在的公司AT&T, 于1972年申请专利,1979年专利获批,专利号:US 4135240 "Protection of data file contents".