RealUID,已保存的UID,有效的UID。这是怎么回事?

时间:2011-12-14 03:53:15

标签: linux privileges setuid

这是一个set-root-uid程序

$ls -l
-rwsr-sr-x 1 root root 7406 2011-12-13 22:37 ./x*

源代码:

int main(void) {
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

seteuid(600);
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

setuid(1000);

    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

setuid(0); // HOW DOES THIS SUCCEED IN SETTING THE EUID BACK TO 0
    printf(
        "         UID           GID  \n"
        "Real      %d  Real      %d  \n"
        "Effective %d  Effective %d  \n",
             getuid (),     getgid (),
             geteuid(),     getegid()
    );

    return 0 ;       
}

输出

         UID           GID  
Real      1000  Real      1000  
Effective 0  Effective 0  
         UID           GID  
Real      1000  Real      1000  
Effective 600  Effective 0  
         UID           GID  
Real      1000  Real      1000  
Effective 1000  Effective 1000  
         UID           GID  
Real      1000  Real      1000  
Effective 0  Effective 1000  

我的问题

手册页指出setuid将改变真实,保存和有效的uid。 因此,在调用setuid(1000)之后,所有三个都更改为1000setuid(0)如何让我将euid更改为0

4 个答案:

答案 0 :(得分:30)

有两种情况,

  
      
  1. 您希望在执行setuid程序时临时删除root权限
  2.   
  3. 您希望在执行setuid程序时永久删除root权限...
  4.   
  • 您可以通过将euid设置为真实用户ID然后将uid更改为您想要的任何内容来暂时执行此操作。稍后当您需要root权限时,您可以setuid为root,并且有效的userid将更改回root 。这是因为保存的用户ID不会更改。
  • 您可以通过直接将uid更改为较低权限的用户ID来永久删除权限。在此之后,无论您无法取回root权限。

案例1:

setuid程序开始执行后

1.seteuid(600);
2.setuid(1000);
3.setuid(0);

对于这种情况,可以再次获得root权限。

              +----+------+------------+
              | uid|euid  |saved-uid   |
              |----|------|------------|
            1.|1000| 0    | 0          |
            2.|1000| 600  | 0          |
            3.|1000| 1000 | 0          |
            4.|1000|  0   | 0          |
              |    |      |            |
              +------------------------+

案例2:

setuid程序开始执行后

1.setuid(1000);
2.setuid(0);



               +----+------+------------+
               | uid|euid  |saved-uid   |
               |----|------|------------|
             1.|1000|0     | 0          |
             2.|1000|1000  | 1000       |
               |    |      |            |
               +------------------------+

在这种情况下,您无法取回root权限。 这可以通过以下命令

进行验证

cat / proc / PROCID / task / PROCID / status |少

Uid:    1000    0       0       0
Gid:    1000    0       0       0

此命令将显示一个Uid和Gid,它将有4个字段(前三个字段是我们关注的字段)。像上面的东西

这三个字段代表uid,euid和saved-user-id。您可以在setuid程序中引入暂停(来自用户的输入),并检查cat /proc/PROCID/task/PROCID/status | less命令的每个步骤。在每个步骤中,您可以检查保存的uid如上所述进行更改。

如果您的euid是root并且您更改了uid,则会永久删除权限。如果有效用户ID不是root,则永远不会触及已保存的用户ID,您可以重新获得root权限随时随地都可以参加您的计划。

答案 1 :(得分:8)

  

<强>描述    setuid()设置调用进程的有效用户ID。如果调用者的有效UID是    root,真实UID和保存的set-user-ID也已设置。

     

在Linux下,setuid()的实现类似于具有_POSIX_SAVED_IDS功能的POSIX版本。这个    允许set-user-ID(root除外)程序删除其所有用户权限,执行一些非特权工作,然后以安全的方式重新启动原始有效用户ID。

     

如果用户是root用户或程序是set-user-ID-root,则必须特别小心。 setuid()函数检查调用者的有效用户ID,如果是超级用户,则检查所有与进程相关的用户    ID设置为uid。发生这种情况后,程序无法重新获得root权限。

     

因此,一个set-user-ID-root程序希望暂时删除root权限,假定一个身份   没有特权的用户,然后重新获得root权限后不能使用setuid()。你可以完成   这与seteuid(2)。

(来自Linux程序员手册,2014-09-21,第setuid.2页)

答案 2 :(得分:3)

0!这些功能很难正确使用。

  

手册页指出setuid将改变真实,保存和有效的uid。因此在调用setuid(1000)之后,所有三个都变为1000。

当且仅当你是euid 0时就是这种情况。但是,当你拨打setuid(0)时,你是euid 1000而已保存 uid 0(检查{{1} }, 例如)。这就是你能够重获特权的原因。

答案 3 :(得分:1)

代码:

#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>

void print_uid(char *str, int ret)
{
    uid_t ruid;
    uid_t euid;
    uid_t suid;
    getresuid(&ruid, &euid, &suid);

    printf("%s ret:%d\n"
           "Real:%4d  Effective:%4d  Saved:%4d\n",
           str, ret, ruid, euid, suid);
}

int main(void)
{
    int ret = 0;
    print_uid("init", ret);            /* Real:1000  Effective:   0  Saved:   0 */

    ret = seteuid(600);
    print_uid("seteuid(600)", ret);    /* Real:1000  Effective: 600  Saved:   0 */

    ret = setuid(1000);
    print_uid("setuid(1000)", ret);    /* Real:1000  Effective:1000  Saved:   0 */

    ret = setuid(0);
    print_uid("setuid(0)", ret);       /* Real:1000  Effective:   0  Saved:   0 */

    ret = setuid(1000);
    print_uid("setuid(1000)", ret);    /* Real:1000  Effective:1000  Saved:1000 */

    ret = setuid(0);
    print_uid("setuid(0)", ret);       /* Real:1000  Effective:1000  Saved:1000 */

    return 0 ;       
}

sudo chown root setuid_feature
sudo chmod + s setuid_feature

在Linux中,一个进程有三个uid:REAL uid,EffECTIVE uid,SAVED uid。
继续1.当euid为root时,可以将setuid或seteuid设置为任何uid,但是有副作用,当使用setuid(不是seteuid)时,可以将所有三个设置为相同的uid,而不是ROOT,并且则该进程无法获得ROOT特权。
继续2.当euid不是root时,可以将setuid或seteuid设置为ruid或suid,并且仅更改euid。

                       |      seteuid             |          setuid  
Cond 1. (euid == root) | set euid to any uid      | set all three uids to any uid  
Cond 2. (euid != root) | set euid to ruid or suid | set euid to ruid or suid  

因此,代码中有5个setuid或seteuid进程,让我对其进行分类:
1. seteuid(600):条件1,将euid设置为600
2. setuid(1000):条件2,将euid设置为1000
3. setuid(0):条件2,将euid设置为0(suid)
4. setuid(1000):条件1,将所有三个uid设置为1000
5. setuid(0):条件2,所有三个uid都不等于0,因此不能设置为0,失败的原因是ret = -1