Ubuntu - может ли пользователь без полномочий root запускать процесс в chroot-тюрьме?

Можно ли пользователю без полномочий root запускать процесс chroot в Ubuntu?

6 ответов

Решение

В Linux системный вызов chroot(2) может быть выполнен только привилегированным процессом. Способность, в которой нуждается процесс, является CAP_SYS_CHROOT.

Причина, по которой вы не можете использовать chroot как пользователя, довольно проста. Предположим, у вас есть программа setuid, такая как sudo, которая проверяет / etc / sudoers, если вам разрешено что-то делать. Теперь поместите его в chroot chroot с вашим собственным / etc / sudoers. Внезапно вы получаете мгновенное повышение привилегий.

Можно спроектировать программу для самореализации и запуска ее как процесса setuid, но это обычно считается плохим дизайном. Дополнительная безопасность chroot не мотивирует проблемы безопасности с setuid.

@imz -IvanZakharyaschev комментирует ответ pehrs, что это может быть возможно с введением пространств имен, но это не было проверено и опубликовано как ответ. Да, это действительно позволяет пользователю без полномочий root использовать chroot.

Учитывая статически связаны dashи статически связаны busyboxи бег bash оболочка работает без полномочий root:

$ mkdir root
$ cp /path/to/dash root
$ cp /path/to/busybox root
$ unshare -r bash -c 'chroot root /dash -c "/busybox ls -al /"'
total 2700
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 .
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 ..
drwxr-xr-x    1 0        0          1905240 Dec  2 19:15 busybox
drwxr-xr-x    1 0        0           847704 Dec  2 19:15 dash

Идентификатор пользователя root в этом пространстве имен сопоставляется с идентификатором пользователя без полномочий root вне этого пространства имен, и наоборот, поэтому система показывает файлы, принадлежащие текущему пользователю, как принадлежащие идентификатору пользователя 0. Обычный ls -al rootбез unshare, показывает их как принадлежащих текущему пользователю.


Примечание: хорошо известно, что процессы, которые могут использовать chrootспособны вырваться из chroot, поскольку unshare -r даст chroot разрешения для обычного пользователя, это было бы угрозой безопасности, если бы это было разрешено внутри chroot среда. В самом деле, это не разрешено, и терпит неудачу с:

unshare: unshare failed: операция не разрешена

которая соответствует документации unshare(2) (извиняюсь за странный жирный шрифт, но вот как это выглядит):

EPERM (начиная с Linux 3.9)

CLONE_NEWUSER был указан в флажках, а вызывающий абонент находится в среде chroot (т. Е. Корневой каталог вызывающего не совпадает с корневым каталогом пространства имен монтирования, в котором он находится).

В наши дни вы хотите смотреть на LXC (Linux Containers) вместо chroot/BSD jail. Это где-то между chroot и виртуальной машиной, что дает вам большой контроль безопасности и общую настраиваемость. Я считаю, что все, что вам нужно, чтобы запустить его как пользователь, - это быть членом группы, которая владеет необходимыми файлами / устройствами, но могут также быть задействованы возможности / системные разрешения. В любом случае, это должно быть очень выполнимо, поскольку LXC появился совсем недавно, еще долго после того, как SELinux и т. Д. Был добавлен в ядро ​​Linux.

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

Комбинация fakeroot / fakechroot дает симуляцию chroot для простых нужд, таких как создание tar-архивов, где файлы, по-видимому, принадлежат root. Справочная страница Fakechroot находится по адресу http://linux.die.net/man/1/fakechroot.

Вы не получаете никаких новых разрешений, но если у вас есть каталог (например, fake-distro) перед вызовом

fakechroot fakeroot chroot ~/fake-distro some-command

теперь он ищет какую-то команду, как будто вы root и владеете всем в fake-distro.

Похоже, что с пространствами имен пользователей фактически возможно выполнить chroot без root. Вот пример программы, которая демонстрирует, что это возможно. Я только начал исследовать, как работают пространства имен linux, и поэтому я не совсем уверен, является ли этот код наилучшей практикой или нет.

Сохранить как user_chroot.cc, Компилировать с g++ -o user_chroot user_chroot.cc, Использование ./user_chroot /path/to/new_rootfs,

// references:
// [1]: http://man7.org/linux/man-pages/man7/user_namespaces.7.html
// [2]: http://man7.org/linux/man-pages/man2/unshare.2.html

#include <sched.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <cerrno>
#include <cstdio>
#include <cstring>

int main(int argc, char** argv) {
    if(argc < 2) {
        printf("Usage: %s <rootfs>\n", argv[0]);
    }

    int uid = getuid();
    int gid = getgid();
    printf("Before unshare, uid=%d, gid=%d\n", uid, gid);

    // First, unshare the user namespace and assume admin capability in the
    // new namespace
    int err = unshare(CLONE_NEWUSER);
    if(err) {
        printf("Failed to unshare user namespace\n");
        return 1;
    }

    // write a uid/gid map
    char file_path_buf[100];
    int pid = getpid();
    printf("My pid: %d\n", pid);

    sprintf(file_path_buf, "/proc/%d/uid_map", pid);
    int fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", uid, uid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/setgroups", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        dprintf(fd, "deny\n");
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/gid_map", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", gid, gid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    // Now chroot into the desired directory
    err = chroot(argv[1]);
    if(err) {
        printf("Failed to chroot\n");
        return 1;
    }

    // Now drop admin in our namespace
    err = setresuid(uid, uid, uid);
    if(err) {
        printf("Failed to set uid\n");
    }

    err = setresgid(gid, gid, gid);
    if(err) {
        printf("Failed to set gid\n");
    }

    // and start a shell
    char argv0[] = "bash";
    char* new_argv[] = {
        argv0,
        NULL
    };

    err = execvp("/bin/bash", new_argv);
    if(err) {
        perror("Failed to start shell");
        return -1;
    }
}

Я проверил это на минимальном rootfs, сгенерированном с помощью multiistrap (выполняется без полномочий root). Некоторые системные файлы, такие как /etc/passwd а также /etc/groups были скопированы с rootfs хоста в гостевые rootfs.

Нет. Если я правильно помню, есть какая-то вещь уровня ядра, которую делает chroot, которая предотвращает это. Я не помню, что это была за вещь. Я исследовал это, когда возился с инструментом Gentoo Catalyst Build (и chroot в gentoo такой же, как chroot в ubuntu). Хотя было бы возможно сделать это без passwd... но такие вещи остаются в сфере потенциальных уязвимостей безопасности и убедиться, что вы знаете, что делаете.

Другие вопросы по тегам