Удаление корневых привилегий - PullRequest
54 голосов
/ 29 июля 2010

У меня есть демон, который запускается от имени пользователя root (поэтому он может связываться с низкими портами).После инициализации мне бы очень хотелось, чтобы из соображений безопасности он удалил привилегии root.

Может ли кто-нибудь указать мне на известный правильный фрагмент кода на C, который это сделает?

Я прочитал справочные страницы, я посмотрел на различные реализации этого в разных приложениях, и все они разные, и некоторые из них действительно сложны.Это код, связанный с безопасностью, и я действительно не хочу изобретать те же ошибки, которые совершают другие люди.То, что я ищу, - это лучшая практика, известная хорошая переносимая библиотечная функция, которую я могу использовать, зная, что она все сделает правильно.Существует ли такая вещь?

Для справки: я начинаю как root;Мне нужно изменить, чтобы работать под другим UID и GID;Мне нужно правильно настроить дополнительные группы;После этого мне не нужно возвращаться к привилегиям root.

Ответы [ 3 ]

46 голосов
/ 29 июля 2010

Чтобы отбросить все привилегии (пользователя и группы), вам нужно удалить группу перед пользователем.Учитывая, что userid и groupid содержат идентификаторы пользователя и группы, в которую вы хотите перетаскивать данные, и если предположить, что эффективные идентификаторы также являются корневыми, это достигается путем вызова setuid () и setgid () :

if (getuid() == 0) {
    /* process is running as root, drop privileges */
    if (setgid(groupid) != 0)
        fatal("setgid: Unable to drop group privileges: %s", strerror(errno));
    if (setuid(userid) != 0)
        fatal("setuid: Unable to drop user privileges: %S", strerror(errno));
}

Если вы параноик, вы можете попытаться вернуть свои привилегии root, что должно дать сбой.Если это не сработает, вы спаситесь:

 if (setuid(0) != -1)
     fatal("ERROR: Managed to regain root privileges?");

Кроме того, если вы все еще параноик, вы можете захотеть seteuid () и setegid () тоже, но в этом нет необходимости, поскольку setuid () и setgid () уже устанавливают все идентификаторы, если процесс принадлежит пользователю root.

Список дополнительных групп является проблемой, поскольку POSIX нетфункция для установки дополнительных групп (есть getgroups () , но нет setgroups ()).Существует расширение BSD и Linux setgroups () , которое вы можете использовать, если это вас касается.

Вам также следует chdir("/") или в любом другом каталоге,так что процесс не остается в корневом каталоге.

Поскольку ваш вопрос касается Unix в целом, это очень общий подход.Обратите внимание, что в Linux это больше не является предпочтительным подходом.В текущих версиях Linux вы должны установить возможность CAP_NET_BIND_SERVICE на исполняемом файле и запускать его как обычный пользователь.Корневой доступ не требуется.

16 голосов
/ 18 марта 2015

Вы ищете эту статью:

POS36-C. Соблюдайте правильный порядок отзыва при отказе от привилегий

Не уверен, как лучше поместить туда некоторую информацию, не дублируя содержимое этой страницы ...

2 голосов
/ 20 июня 2017

Это было то, что я мог сделать лучше всего:

#define _GNU_SOURCE  // for secure_getenv()


int drop_root_privileges(void) {  // returns 0 on success and -1 on failure
    gid_t gid;
    uid_t uid;

    // no need to "drop" the privileges that you don't have in the first place!
    if (getuid() != 0) {
        return 0;
    }

    // when your program is invoked with sudo, getuid() will return 0 and you
    // won't be able to drop your privileges
    if ((uid = getuid()) == 0) {
        const char *sudo_uid = secure_getenv("SUDO_UID");
        if (sudo_uid == NULL) {
            printf("environment variable `SUDO_UID` not found\n");
            return -1;
        }
        errno = 0;
        uid = (uid_t) strtoll(sudo_uid, NULL, 10);
        if (errno != 0) {
            perror("under-/over-flow in converting `SUDO_UID` to integer");
            return -1;
        }
    }

    // again, in case your program is invoked using sudo
    if ((gid = getgid()) == 0) {
        const char *sudo_gid = secure_getenv("SUDO_GID");
        if (sudo_gid == NULL) {
            printf("environment variable `SUDO_GID` not found\n");
            return -1;
        }
        errno = 0;
        gid = (gid_t) strtoll(sudo_gid, NULL, 10);
        if (errno != 0) {
            perror("under-/over-flow in converting `SUDO_GID` to integer");
            return -1;
        }
    }

    if (setgid(gid) != 0) {
        perror("setgid");
        return -1;
    }
    if (setuid(uid) != 0) {
        perror("setgid");
        return -1;    
    }

    // change your directory to somewhere else, just in case if you are in a
    // root-owned one (e.g. /root)
    if (chdir("/") != 0) {
        perror("chdir");
        return -1;
    }

    // check if we successfully dropped the root privileges
    if (setuid(0) == 0 || seteuid(0) == 0) {
        printf("could not drop root privileges!\n");
        return -1;
    }

    return 0;
}
...