#Linux的边边角角# 之 "EPERM"错误和setuid魔法

    在上一篇文章(http://my.oschina.net/u/2310891/blog/621672)的结尾处抛出了一个问题,即在正常情况下能够使用普通用户身份执行地ping命令为何在使用了strace跟踪后会报出"EPERM(Operation not permitted)"的错误?

    错误出在这一句:

socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = -1 EPERM (Operation not permitted)

    这是由于创建raw socket时需要root权限造成的,有由socket syscall调用的inet_create函数的实现为证:

err = -EPERM;
if (sock->type == SOCK_RAW && !kern &&
    !ns_capable(net->user_ns, CAP_NET_RAW))
        goto out_rcu_unlock;

    这就有点奇怪了,在执行ping程序时并没有使用root权限,为何能够正常运行,而在使用strace跟踪后又会报错呢?

    沉思两秒后,我们先来看看ping程序文件的属性:

$which ping
/bin/ping

$ls -l /bin/ping
-rwsr-xr-x 1 root root 35712 Nov  8  2011 /bin/ping

    发现一些不一样了吧,有一个不太常见的标志“s”混进了权限位中,google一下rws,很快你就会明白其中的奥秘了,简而言之就是如果我使用root权限为某个程序文件加入了uid权限,那么之后即使通过普通用户的身份执行该程序,也一样能够获得root用户的权限。

    这就是为什么能够直接执行ping程序而并不会出现EPERM错误的原因了。

    但是strace时出错的原因还没有找到。

    我们知道,strace和shell的基本实现都是fork+execv的模式,那么为什么会造成这种差异呢,下面一步步来验证:

    1. 编写一个小程序tcp_client,其主要内容是创建一个raw socket,然后执行它:

$ ls -l
-rwxrwxr-x 1 yyy yyy 13207 Feb 25 11:10 tcp_client

$ ./tcp_client
raw socket create failed, errno: 1, Operation not permitted

    由于程序的所有者和执行者都是yyy,因此在创建原始套接字的时候不出意外的失败了。


    2. 施展setuid魔法的时候到了,请仔细看下面的步骤:

$ sudo cp tcp_client tcp_client_chmod
$ ls -l
-rwxr-xr-x 1 root root 13207 Feb 25 15:12 tcp_client_chmod

$ chmod u+s tcp_client_chmod
chmod: changing permissions of `tcp_client_chmod': Operation not permitted
$ sudo !!
sudo chmod u+s tcp_client_chmod

$ ls -l
-rwsr-xr-x 1 root root 13207 Feb 25 15:12 tcp_client_chmod

$ ./tcp_client_chmod
raw socket create success!
Usage: ./tcp_client serverip serverport

    噔噔噔噔,这下使用普通用户权限也能够执行需要root权限的程序啦。

    为何在cp的时候要使用sudo呢?

    这是因为我们原来的程序文件所有者是yyy用户,而程序的执行需要root权限,因此我们要先将文件所有者变为root用户,然后再应用setuid,才会有奇效。


    3. 接下来我们写一个小程序myshell,让它通过fork+execv的模式来执行tcp_client_chmod:

$ ./myshell ./tcp_client_chomd
parent 18375 wait for 18376
child 18376 do execv!
raw socket create success!
Usage: ./tcp_client serverip serverport

    事实证明,即使我们使用普通用户的身份来执行myshell,且在myshell中没有做任何setuid相关的操作,依然能够正确执行需要root权限的程序,也就是说通过execv调用是没有问题的。

   

    这下又迷惑了:为什么strace不行呢?

    玄机就藏在man strace中:

SETUID INSTALLATION
       If strace is installed setuid to root then the invoking user will be able to attach to and trace processes owned by any user.  In addition setuid and setgid programs  will  be  executed
       and  traced  with  the  correct  effective privileges.  Since only users trusted with full root privileges should be allowed to do these things, it only makes sense to install strace as
       setuid to root when the users who can execute it are restricted to those users who have this trust.  For example, it makes sense to install a special version of strace with mode  `rwsr-
       xr--', user root and group trace, where members of the trace group are trusted users.  If you do use this feature, please remember to install a non-setuid version of strace for ordinary
       lusers to use.


BUGS
       Programs that use the setuid bit do not have effective user ID privileges while being traced.

    啊哈,原来是一个Bug呀!


    另外看一下我们系统中安装的strace程序,没有按照"SETUID INSTALLATION"中说明的安装为setuid形式,因此默认情况下也就无法跟踪其他用户所拥有的进程:

$ which strace
/usr/bin/strace

$ ls -l /usr/bin/strace 
-rwxr-xr-x 1 root root 314192 May 27  2011 /usr/bin/strace





你可能感兴趣的:(linux,strace,setuid,rwS)