Como executar o chroot com namespaces do Linux?

8

Depois de ler sobre namespaces do Linux, fiquei com a impressão de que eles são, entre muitos outros recursos, uma alternativa ao chroot. Por exemplo, em este artigo :

Other uses [of namespaces] include [...] chroot()-style isolation of a process to a portion of the single directory hierarchy.

No entanto, quando clona o namespace mount, por exemplo com o seguinte comando, ainda vejo toda a árvore raiz original.

unshare --mount -- /bin/bash

Entendo que agora posso executar montagens adicionais no novo namespace que não são compartilhadas com o namespace original e, portanto, isso fornece isolamento, mas ainda é a mesma raiz, por exemplo, /etc ainda é o mesmo para os dois namespaces. Ainda preciso de chroot para alterar a raiz ou existe uma alternativa?

Eu esperava que esta pergunta fornecesse uma resposta, mas a resposta é apenas usa chroot novamente.

EDIT # 1

Houve um comentário agora excluído que mencionou pivot_root . Como isso faz parte de linux/fs/namespace.c , na verdade é parte da implementação dos namespaces. Isso sugere que alterar o diretório raiz apenas com unshare e mount não é possível, mas os namespaces fornecem uma versão própria - mais inteligente - de chroot . Ainda não entendo a idéia principal dessa abordagem que a torna fundamentalmente diferente de chroot , mesmo depois de ler o código-fonte (no sentido de, por exemplo, segurança ou melhor isolamento).

EDIT # 2

Esta não é uma cópia de esta questão . Depois de executar todos os comandos da resposta eu tenho separado /tmp/tmp.vyM9IwnKuY (ou similar), mas o diretório raiz ainda é o mesmo!

    
por koalo 16.07.2018 / 21:43

1 resposta

8

A inserção de um namespace de montagem antes da configuração de um chroot permite que você evite sobrecarregar o namespace do host com montagens adicionais, por exemplo, para /proc . Você pode usar chroot dentro de um namespace de montagem como um hack simples e agradável.

Acho que há vantagens em entender pivot_root , mas tem uma curva de aprendizado. Na minha opinião, a documentação não explica exatamente tudo ... Pelo menos há um exemplo de uso em man 8 pivot_root (para o comando shell). man 2 pivot_root (para a chamada do sistema) pode ser mais claro se fizer o mesmo e incluir um exemplo de programa em C.

Como usar o pivot_root

Imediatamente após entrar no namespace de montagem, você também precisa de mount --make-rslave / ou similar. Caso contrário, todas as alterações de montagem serão propagadas para as montagens no namespace original, incluindo o pivot_root . Você não quer isso:).

Se você usou o comando unshare --mount , observe que é documentado aplicar mount --make-rprivate por padrão. AFAICS este é um padrão ruim e você não quer isso no código de produção. Por exemplo. neste ponto, isso impediria que eject trabalhasse em um DVD ou USB montado no namespace do host. O DVD ou USB permaneceria montado dentro da árvore de montagem privada, e o kernel não permitiria que você ejetasse o DVD.

Depois de fazer isso, você pode montar, por exemplo, o diretório /proc que você estará usando. Da mesma forma que você faria para chroot .

Ao contrário de quando você usa chroot , pivot_root requer que seu novo sistema de arquivos raiz seja um ponto de montagem. Se ainda não é um, você pode satisfazer isso simplesmente aplicando uma montagem de ligação: mount --bind new_root new_root .

Use pivot_root - e, em seguida, umount do sistema de arquivos raiz antigo, com a opção -l / MNT_DETACH . ( Você não usa t precisa de umount -R , o que pode levar mais tempo. ).

Tecnicamente, usar pivot_root geralmente também envolve o uso de chroot ; não é "ou-ou".

Como por man 2 pivot_root , ele é definido apenas como a troca da raiz do namespace de montagem. Não está definido para alterar para qual diretório físico a raiz do processo está apontando. Ou o diretório de trabalho atual ( /proc/self/cwd ). Acontece que faz isso, mas isso é um truque para lidar com encadeamentos do kernel. A manpage diz que isso pode mudar no futuro.

Geralmente você quer essa sequência:

chdir(new_root);            // cd new_root
pivot_root(".", put_old);   // pivot_root . put_old
chroot(".");                // exec chroot .

A ordenação do chroot parece ser ainda outro detalhe sutil . Embora o ponto de pivot_root seja reorganizar o namespace de montagem, o código do kernel parece encontrar o sistema de arquivos raiz para mover, observando a raiz por processo, que é o que define chroot .

Por que usar o pivot_root

Em princípio, faz sentido usar pivot_root para segurança e isolamento. Eu gosto de pensar sobre a teoria da segurança baseada em recursos . Você passa uma lista dos recursos específicos necessários e o processo não pode acessar outros recursos. Neste caso, estamos falando sobre os sistemas de arquivos passados para um namespace de montagem. Essa idéia se aplica geralmente ao recurso "namespaces" do Linux, embora provavelmente eu não esteja expressando isso muito bem.

chroot apenas define a raiz do processo, mas o processo ainda se refere ao namespace de montagem completo. Se um processo retiver o privilégio de executar chroot , ele poderá percorrer o espaço de nomes do sistema de arquivos. Como detalhado em man 2 chroot , "o superusuário pode escapar de um 'chroot jail' por ...".

Outra maneira instigante de desfazer chroot é nsenter --mount=/proc/self/ns/mnt . Este talvez seja um argumento mais strong para o princípio. nsenter / setns() necessariamente recarrega a raiz do processo, da raiz do namespace de montagem . Embora o fato de que isso funciona quando os dois se referem a diferentes diretórios físicos, pode ser considerado um bug do kernel. (Nota técnica: pode haver vários sistemas de arquivos montados uns em cima dos outros na raiz; setns() usa o superior, mais recentemente montado).

Isso ilustra uma vantagem de combinar um namespace de montagem com um "namespace PID". Estar dentro de um espaço de nomes PID impediria que você entrasse no namespace de montagem de um processo não delimitado. Isso também impede que você insira a raiz de um processo não confinado ( /proc/$PID/root ). E, claro, um namespace PID também impede que você mate qualquer processo que esteja fora dele: -).

    
por 17.07.2018 / 16:25