Подтвердить что ты не робот

RealUID, сохраненный 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 ;       
}

OUTPUT

         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?

4b9b3361

Ответ 1

Есть два случая:

  • Вы хотите временно отказаться от прав root при выполнении программы setuid.
  • Вы хотите навсегда отказаться от привилегий root при выполнении программы setuid...
  • Вы можете временно сделать это, установив euid на реальный идентификатор пользователя, а затем изменив uid на все, что захотите. И позже, когда вам понадобится root-привилегия, вы можете установить root, а эффективный идентификатор пользователя изменится на root, Это связано с тем, что сохраненный идентификатор пользователя не изменяется.
  • Вы можете временно удалить привилегию, сразу изменив uid на менее привилегированный идентификатор пользователя. После этого, независимо от того, что вы не можете вернуть 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/статус | меньше

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

Эта команда отобразит Uid и Gid, и у нее будет 4 поля (первые три поля - это те, которые мы занимаем). Что-то вроде выше

Три поля представляют uid, euid и save-user-id. Вы можете ввести паузу (ввод от пользователя) в вашей программе setuid и проверить для каждого шага команду cat /proc/PROCID/task/PROCID/status | less. На каждом шаге вы можете проверить, что сохраненный uid стал изменен, как указано.

Если вы euid - это root, и вы изменяете uid, привилегии будут удаляться навсегда. Если эффективный идентификатор пользователя не является root, тогда сохраненный идентификатор пользователя никогда не затрагивается, и вы можете вернуть корневую привилегию обратно в любое время в вашей программе.

Ответ 2

ОПИСАНИЕ setuid() устанавливает эффективный идентификатор пользователя вызывающего процесса. Если эффективный UID вызывающего абонента  root, действительный UID и сохраненный идентификатор set-user-ID.

В Linux, setuid() реализуется как версия POSIX с функцией _POSIX_SAVED_IDS. Эта  позволяет программе set-user-ID (кроме root) отказаться от всех своих пользовательских привилегий, выполнить некоторую работу без привилегий и затем безопасно восстановить исходный эффективный идентификатор пользователя.

Если пользователь root или программа установлена, то пользовательский ID-корень должен быть особо соблюден. Функция setuid() проверяет эффективный идентификатор пользователя вызывающего абонента, и если он является суперпользователем, все пользователи, связанные с процессом  ID установлены на uid. После этого программа не сможет восстановить привилегии root.

Таким образом, программа set-user-ID-root, желающая временно отказаться от привилегий root, принимает личность непривилегированный пользователь, а затем восстановить привилегии root впоследствии не могут использовать setuid(). Вы можете выполнить это с помощью seteuid (2).

(из Руководства программистов Linux, 2014-09-21, стр. setuid.2)

Ответ 3

О! Эти функции трудно использовать правильно.

На странице пользователя указано, что setuid изменит реальный, сохраненный и эффективный uid. Итак, после вызова setuid (1000) все три изменяются на 1000.

Это так, если и только если вы являетесь euid 0. В то время, когда вы вызываете setuid(0), вы, тем не менее, являетесь euid 1000 и сохранили uid 0 (например, отметьте getresuid(2)). Вот почему вы можете восстановить привилегии.

Ответ 4

Код:

#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, 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): Cond 1, установите euid на 600
2. setuid (1000): Cond 2, установите euid на 1000
3. setuid (0): Cond 2, установите euid в 0 (suid)
4. setuid (1000): Cond 1, установите все три идентификатора на 1000
5. setuid (0): Cond 2, все три идентификатора не равны 0, поэтому не могут быть установлены в 0, сбой с ret = -1