真实UID,保存的UID,有效的UID。这是怎么回事?



这是一个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)之后,这三个都变成了1000。那setuid(0)呢我把euid改成0

有两种情况,

  1. 你想在执行setuid程序时暂时放弃root权限
  2. 你想在执行setuid程序时永久删除root权限…
  • 您可以通过将uid设置为实际用户id,然后将uid更改为您想要的任何内容来临时做到这一点。以后当您需要恢复root权限时,您可以将id设置为root,并且有效的用户id将更改回root。这是因为保存的用户id没有更改。
  • 您可以通过直接将uid更改为权限较低的用户id来永久删除特权。在此之后,无论如何您都无法恢复root权限。

Case 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       |
               |    |      |            |
               +------------------------+

在这种情况下,您无法获得根权限。这可以通过以下命令

进行验证

cat/proc/procid/task/procid/status | less

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是否如前所述发生了更改。

如果您的uid是root并且您更改了uid,那么特权将被永久删除。如果有效用户id不是root,那么保存的用户id永远不会被触及,您可以随时在程序中重新获得root权限。

setuid()设置调用进程的有效用户ID。如果调用方的有效UID是同时设置真实UID和保存的set-user- id。

在Linux下,setuid()的实现与POSIX版本一样,具有_POSIX_SAVED_IDS特性。这允许set-user-ID(除了root)程序放弃它所有的用户权限,做一些没有特权的工作,然后以一种安全的方式重新使用原来的有效用户ID。

如果用户是root或者程序是set-user-ID-root,必须特别小心。setuid()函数检查调用者的有效用户ID,如果它是超级用户,则检查所有与进程相关的用户ID被设置为uid。在此之后,程序不可能重新获得root权限。

因此,如果一个set-user-ID-root程序希望暂时放弃root权限,那么它就假定是一个用户的身份无特权用户,然后重新获得根权限,不能使用setuid()。你可以完成

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

0 !这些函数很难正确使用。

手册页说明setuid将更改真实的、保存的和有效的uid。所以在调用setuid(1000)之后,这三个变量都变为1000。

当且仅当您的id为0时才会出现这种情况。但是,在调用setuid(0)时,您的uid为1000,保存的uid为 0(例如,检查getresuid(2))。

代码:

#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:%dn"
           "Real:%4d  Effective:%4d  Saved:%4dn",
           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)时,可以将三者设置为非root的相同uid,然后进程无法重新获得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):设置id为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

最新更新