![Comportamento estranho de pivot_root(".", ".") no namespace de montagem](https://rvso.com/image/168809/Comportamento%20estranho%20de%20pivot_root(%22.%22%2C%20%22.%22)%20no%20namespace%20de%20montagem.png)
Estou tentando entender os containers e me deparei com um truque aparentemente encontrado pelos desenvolvedores do LXC, vejaeste runc PR: você pode chamar pivot_root(".", ".")
o que evita a necessidade de um diretório para colocar a raiz antiga. No entanto, isso faz com que o namespace mount se comporte de maneira estranha:
unshare --user --map-root-user --mount bash -c "
mount --bind containerfs bindmountpoint
cd bindmountpoint
pivot_root . .
# this is fine:
ls -l /
# this is not fine:
ls -l /..
"
O pai de .
, acessado via ./..
ou /..
ou /proc/<any>/cwd/..
aponta para a raiz do namespace de montagem raiz (ainda não tentei aninhar)! Ele não aponta para o pai de containerfs
nor bindmountpoint
, mas realmente para a raiz do namespace de montagem raiz/externa.
Da mesma forma, quando tento nsenter --user --preserve-credentials --mount --target=<pid>
, esse novo processo tem seu CWD colocado na raiz do namespace de montagem raiz.
Nada disso acontece quando eu pivot_root(".", "oldroot")
. O comportamento também desaparece ao desmontar a raiz antiga, seja por meio de um descritor de arquivo umount -l /
ou umount -l /proc/1/cwd
.
Também tentei essa sequência de syscalls de um programa C customizado, pois a documentação do pivot_root
só dá garantias sobre o processo atual (então faço tudo no mesmo processo). O comportamento é o mesmo das etapas de vários processos usando ferramentas CLI mostradas acima.
Testado em um kernel 5.3.
O que está acontecendo quando eu corro pivot_root(".", ".")
?
Responder1
pivot_root(new_root, put_old)
move o diretório raiz antigo do processo de chamada (que deve ser a raiz de uma montagem) para put_old
e coloca new_root
em seu lugar. Em seguida, ele define o diretório atual e a raiz de cada processo que foi definido no diretório raiz antigo como new_root
.
Então, depois que pivot_root(".", ".")
o novo diretório raiz tiver o diretório raiz antigo montado sobre ele.
Sempre que ..
for resolvido para o diretório que possui outro diretório montado, ele na verdade será resolvido para o diretório montado na parte superior. Isso corresponde ao comportamento histórico do Unix e do Linux, onde ..
, exceto no diretório raiz de um sistema de arquivos, não teve nenhum tratamento especial na travessia do caminho e foi implementado por uma entrada de diretório armazenada no disco.
Este não é um escape de namespace de montagem.
Responder2
Parece um bug genuíno...
Verifique o kernel mais recente da sua distribuição e relate-o com detalhes completos (anexe seu programa de teste!).