Ubuntu - o usuário não raiz pode executar o processo na prisão chroot?

18

É possível para um usuário não root executar um processo chroot no Ubuntu?

Hawkeye
fonte
Este antigo tópico do FreeBSD cobre a mesma pergunta: lists.freebsd.org/pipermail/freebsd-security/2003-April/… Resposta curta: Não, você não pode executar um processo como raiz dentro de uma prisão chroot não raiz.
David Harrison
as cadeias chroot são específicas para o bsd. um chroot no linux não é uma prisão. Por último, verifiquei que não era possível fazer chroot como usuário.
Xenoterracide
11
As cadeias do @xenoterracide são específicas do BSD, mas o chroot é comumente conhecido como "chroot jail" na comunidade Linux. Está bastante confuso.
Pehrs
2
O que você está tentando fazer e por quê? Existem ferramentas como fakechroot e schroot que fornecem uma alternativa viável, dependendo de seus requisitos.
Zoredache
Também houve mais discussões relacionadas em Como "encarcerar" um processo sem ser raiz? com abordagens mais funcionais ou tentativas para resolver esta tarefa listada.
imz - Ivan Zakharyaschev

Respostas:

12

No Linux, a chamada do sistema chroot (2) pode ser feita apenas por um processo privilegiado. A capacidade que o processo precisa é CAP_SYS_CHROOT.

O motivo pelo qual você não pode chroot como usuário é bastante simples. Suponha que você tenha um programa setuid, como o sudo, que verifique / etc / sudoers se tiver permissão para fazer alguma coisa. Agora coloque-o em um chroot chroot com seus próprios / etc / sudoers. De repente, você tem uma escalada instantânea de privilégios.

É possível projetar um programa para fazer chroot e executá-lo como um processo setuid, mas isso geralmente é considerado um design ruim. A segurança extra do chroot não motiva os problemas de segurança com o setuid.

pehrs
fonte
3
Com as novas possibilidades de espaços para nome no linux, talvez seja possível criar (descompartilhar) um novo espaço para nome "usuário", onde haveria um usuário raiz "incorporado" e executá chroot-lo.
IMZ - Ivan Zakharyaschev
11
@ imz - IvanZakharyaschev Você está absolutamente correto, e espero que você não se importe que eu tenha tido a liberdade de escrever isso como uma resposta facilmente testável.
hvd
@hvd Ótimo! Deve ser muito útil, pois demonstra como usar os novos recursos desconhecidos do Linux com comandos concretos.
imz - Ivan Zakharyaschev 3/04/14
6

@ imz - IvanZakharyaschev comenta a resposta dos pehrs de que pode ser possível com a introdução de namespaces, mas isso não foi testado e publicado como resposta. Sim, isso realmente possibilita que um usuário não root use chroot.

Dado um shell estaticamente vinculado dashe estaticamente vinculado busyboxe um bashshell em execução como não raiz:

$ 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

O ID de usuário root em que namespace é mapeado para o não-ID de usuário root fora desse espaço de nomes, e vice-versa, razão pela qual os arquivos mostra o sistema de propriedade do usuário atual como propriedade da ID de usuário 0. Um regular ls -al root, sem unshare, faz mostre-os como pertencentes ao usuário atual.


Nota: é sabido que os processos capazes de usar chrootsão capazes de romper a chroot. Como unshare -rconcederia chrootpermissões a um usuário comum, seria um risco de segurança se isso fosse permitido dentro de um chrootambiente. Na verdade, não é permitido e falha com:

unshare: unshare falhou: operação não permitida

que corresponde à documentação não compartilhada (2) :

EPERM (desde Linux 3.9)

CLONE_NEWUSER foi especificado em sinalizadores e o chamador está em um ambiente chroot (ou seja, o diretório raiz do chamador não corresponde ao diretório raiz do espaço para nome da montagem em que reside).

hvd
fonte
A execução de pivot_root em um namespace de montagem tem um efeito semelhante ao chroot, mas evita o conflito com os namespaces do usuário.
Timothy Baldwin
11
Pode-se escapar de um espaço para nome chroot ou montar descendo para / proc se for um processo externo com o mesmo UID no mesmo ou no PID filho ou em espaços de nomes de usuário.
Timothy Baldwin
2

Hoje em dia, você quer ver o LXC (Linux Containers) em vez da prisão chroot / BSD. Está entre um chroot e uma máquina virtual, oferecendo muito controle de segurança e configurabilidade geral. Acredito que tudo o que você precisa para executá-lo como usuário é ser um membro do grupo que possui os arquivos / dispositivos necessários, mas também pode haver recursos / permissões do sistema envolvidas. De qualquer forma, deve ser muito factível, já que o LXC é bastante recente, muito tempo depois que o SELinux etc. foi adicionado ao kernel do Linux.

Além disso, lembre-se de que você pode escrever scripts como root, mas conceder aos usuários permissão segura para executá-los (sem uma senha, se desejar, mas verifique se o script está seguro) usando o sudo.

Lee B
fonte
1

A combinação de fakeroot / fakechroot fornece um simulacro de chroot para necessidades simples, como a produção de arquivos tar onde os arquivos parecem pertencer à raiz. A página de manual do Fakechroot é http://linux.die.net/man/1/fakechroot .

Você não recebe nenhuma nova permissão, mas se possui um diretório (por exemplo, fake-distro) antes de chamar

fakechroot fakeroot chroot ~/fake-distro some-command

Agora, procure por algum comando como se você fosse root e possuísse tudo dentro da fake-distro.

sylvainulg
fonte
É uma boa idéia, mas parece manipular os links simbólicos de maneira imprevisível. Meu ~/fake-distrousos busybox, que links simbólicos ls, mve outros utilitários comuns a /bin/busybox. Se eu ligar explicitamente /bin/busybox mv ..., as coisas funcionam, mas se eu ligar, /bin/mv ...eu atendo sh: /bin/mv: not found. A configuração export FAKECHROOT_EXCLUDE_PATH=/antes de executar o fakechroot corrige esse sintoma, mas depois quebra em outros links simbólicos (por exemplo /usr/bin/vim -> /usr/bin/vim.vim).
Ponkadoodle
talvez FAKECHROOT_EXCLUDE_PATH = /: / usr ajudaria, então?
sylvainulg
1

Parece que, com espaços de nome de usuário, é possível chroot sem raiz. Aqui está um exemplo de programa que demonstra que é possível. Eu apenas comecei a explorar como os namespaces do linux funcionam e, portanto, não tenho certeza se esse código é uma prática recomendada ou não.

Salvar como user_chroot.cc. Compile com g++ -o user_chroot user_chroot.cc. O uso é ./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;
    }
}

Eu testei isso em um rootfs mínimo gerado com multistrap (executado como não raiz). Alguns arquivos do sistema gostam /etc/passwde /etc/groupsforam copiados dos rootfs do host para os rootfs convidados.

cheshirekow
fonte
Falha em Failed to unshare user namespacemim no linux 4.12.10 (Arch Linux).
Ponkadoodle 08/09
@wallacoloo talvez modifique printf () para perror () e veja qual foi o erro real. consulte man7.org/linux/man-pages/man2/unshare.2.html para saber quais códigos de erro podem resultar de uma unsharechamada malsucedida . Você também pode tentar esta versão python que poderia ter melhor de mensagens de erro: github.com/cheshirekow/uchroot
cheshirekow
11
Na verdade @wallacoloo Parece que desativa arco namespaces de usuários unpriviledged nele de construção do kernel: lists.archlinux.org/pipermail/arch-general/2017-February/...
cheshirekow
0

Não. Se bem me lembro, existe algo no nível do kernel que o chroot faz que impede. Não me lembro o que era aquilo. Eu o investiguei ao mexer com a ferramenta Catalyst Build do Gentoo (e um chroot no gentoo é o mesmo que um chroot no ubuntu). Embora seja possível fazer isso sem uma senha ... mas essas coisas são deixadas para o domínio de possíveis vulnerabilidades de segurança e para garantir que você saiba o que está fazendo.

xenoterracida
fonte