【关键字】 chmod u+s filename; chmod u-s filename; setuid; seteuid; getuid; geteuid; sticky bit(chmod o+t filename); real user ID; effective user ID; saved set-user ID;
下午使用chmod u+s 命令时有一些迷惑,死活想不明白,强迫症开始发作,心想非要弄清楚不可,在网上看无数资料,一番折腾,还是一头雾水。恍然间,才发觉这是一个大坑。然而,不管怎样,看了这么多资料,还是有一些初步理解,做个笔记以供进一步学习。
网上有一篇同主题的文章http://www.groad.net/bbs/read.php?tid-3743.html,写得比较好,概念解释地比较透彻,相对而言,他的文章更深入些,感兴趣的可以忽略我的,直接去看那篇文章。
在使用setuid,seteuid,chmod u+s filename,chmod u-s filename等命令前,先弄清楚四个概念,分别是:文件拥有者,real user ID, effective user ID, saved set-user-ID。
文件拥有者:当你输入 ls -l命令,可以查看一个文件的属性,其中有该文件的拥有者。
-rw-rw-rw- 1 xy xy 1760 Jun 5 19:44 luoxuan.c
上面这一栏就是ls -l命令的输出,第三栏就是文件拥有者,在这里是xy。
real user ID:实际上进程的执行者,标志系统中不同的用户,普通用户无法修改其值,某一个用户的real user ID==他的uid,使用命令“id username"来查看某用户uid。
再来区分一下,real user ID与文件所有者的概念,以下面代码作为范例。
#include <stdio.h> #include <stdlib.h> int main(){ int i; printf("The real user ID is: %d\n",getuid()); printf("The effective user ID is: %d\n",geteuid()); i=setuid(100); if(0==i){ printf(".......................\n"); printf("The real user ID is: %d\n",getuid()); printf("The effective user ID is: %d\n",geteuid()); printf(".......................\n"); } else{ perror("failed to setuid"); printf("The real user ID is: %d\n",getuid()); printf("The effective user ID is: %d\n",geteuid()); exit(1); } return 0; }
假设代码以普通用户编译,生成a.out可执行文件,输入“ls -l a.out",可以看见输出为“-rwxr-xr-x 1 xy xy 7567 Jul 8 14:10 a.out”,a.out的所有者是xy。
然后,运行./a.out命令,得到结果1:
The real user ID is: 1003
The effective user ID is: 1003
failed to setuid: Operation not permitted
The real user ID is: 1003
The effective user ID is: 1003
再运行sudo ./a.out命令,得到结果2:
The real user ID is: 0
The effective user ID is: 0
.......................
The real user ID is: 100
The effective user ID is: 100
从输出结果来看,先不理会effective user ID,当以普通用户运行时,real user ID 为1003,无法setuid,也改变不了real user ID 的值;而使用了sudo 后,改变实际执行用户为root权限执行进程,real user ID的值也变为0,0是root的uid值,此时a.out这个文件的所有者仍然是xy(1003),只不过使用了sudo 超级用户权限导致real user ID不一样。
effective user ID: 主要用于检验该进程在执行时所获得的访问文件权限,当进程在访问文件时,检查权限,实际上是检查effective user ID。有时候,real user ID==effective user ID,但很多时候又不一样,具体情况后面再解释。
仍以上面的代码作为例子,此时以普通用户身份对a.out执行命令:chmod u+s a.out,再以"ls -l a.out"查看a.out的文件属性,为"-rwsr-xr-x 1 xy xy 7567 Jul 8 14:10 a.out"。文件属性中多了一个s符号。
再执行sudo ./a.out,得到结果3:
The real user ID is: 0
The effective user ID is: 1003
failed to setuid: Operation not permitted
The real user ID is: 0
The effective user ID is: 1003
对比结果2,尽管real user ID 是0(root uid),却无法setuid,因为我们使用chmod u+s设置了effective user ID为1003(因为以普通用户运行chmod u+s命令,所以effective user ID为1003),effective user id为1003时,即普通用户,是无法使用setuid修改real user ID和effective user ID的值。所以此时,运行a.out程序的real user ID为0,而effective user ID为1003。
saved set-user ID: 当effective user ID修改时,保存effective user ID的值。具体作用,我还不清楚,请看本文第一段的链接,那里有详细介绍。
从上面例子,观察到一个事实,通过getuid()和geteuid()可以获得real user ID和effective user ID的值,却没有函数获得saved set-user-ID的值。
再来区分一下setuid和chmod u+s。
setuid : 修改real user ID和effective user ID。
chmod u+s filename: 将filename的effective user ID 改为当前登录用户的权限,比如上例结果3中,effective user ID为1003,即uid。即使使用sudo chmod u+s,结果也一样,effective user ID仍为1003。
为了更加清晰地说明这个概念,我们再以上面的代码进行另一个试验。假设以sudo cc test.c tuo.a编译上述代码,生成tuo.a二进制文件,使用"ls -l tuo.a"查看tuo.a的属性,得到-rwxr-xr-x 1 root root 7567 Jul 8 14:53 tuo.a,uid是root。
再以普通用户运行./tuo.a,得到结果4:
The real user ID is: 1003
The effective user ID is: 1003
failed to setuid: Operation not permitted
The real user ID is: 1003
The effective user ID is: 1003
尽管这个文件所有者(owner)是root,但实际运行用户是普通用户,所以real user ID和effective user ID都是1003,因此也无法运行setuid。
再以sudo ./tuo.a运行,得到结果5:
The real user ID is: 0
The effective user ID is: 0
.......................
The real user ID is: 100
The effective user ID is: 100
.......................
这里以root权限运行。
再来使用chmod u+s tuo.a,得到结果“chmod: changing permissions of `tuo.a': Operation not permitted”,因为chmod此时是普通用户,无法修改root用户的文件(tuo.a),所以我们换成sudo chmod u+s tuo.a,再"ls -l tuo.a",可以看见“-rwsr-xr-x 1 root root 7567 Jul 8 14:53 tuo.a",注意红色的s字幕,这就是chmod u+s的效力。现在再以普通用户来运行一下tuo.a二进制文件,得到结果6:
The real user ID is: 1003
The effective user ID is: 0
.......................
The real user ID is: 100
The effective user ID is: 100
.......................
此时,real user ID为1003, effective user ID为0,即使是普通用户运行,还是可以setuid,因为effective user ID被chmod u+s 赋予了0(root权限)。
这一类典型的文件有/usr/bin/passwd,使用"ls -l /usr/bin/passwd"文件查看到“-rwsr-xr-x 1 root root 35696 Feb 8 2011 /usr/bin/passwd”,正是这个s标志(也就是effective user ID)可以让普通用户以root权限做一些事情,如登陆时密码匹配。
如果不希望该文件继续拥有u+s权限,可使用chmod u-s filename消除影响。
最后再来说一说sticky bit粘滞位。
sticky bit: 文件写权限的一种扩展,当文件被设置了sticky bit位,同一组的其他用户他可以为该文件添加内容,但不能删除该文件。使用命令chmod o+t filename,或者chmod 八进制方式设置sticky bit位。设置好之后,用ls -l filename,可以看见一个标记“t"。请注意一个地方,即使添加了stickybit,文件所有者也是可以随意删改这个文件的。
相关链接:
http://www.makelinux.net/alp/083
http://en.wikipedia.org/wiki/User_identifier#Effective_user_ID