É possível executar um novo comando sem acesso à rede como não root usando unshare -r -n
, por exemplo:
$ unshare -r -n ls
a.txt b.txt
Um comando que requer acesso à rede falhará previsivelmente.
$ unshare -r -n curl unix.stackexchange.com
curl: (6) Could not resolve host: unix.stackexchange.com
Eu estou querendo saber se é possível remover o acesso à rede para o processo atual, potencialmente gravando em um arquivo mágico /sys
ou algo semelhante.
Eu gostaria de poder fazer algo como
$ /bin/sh -c 'echo 1 > /sys/unsharethis; curl unix.stackexchange.com'
Um trecho de strace
-ing unshare -r -n ls
mostra a unshare
chamada do sistema
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4759040, ...}) = 0
mmap(NULL, 4759040, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f7ec6968000
close(3) = 0
unshare(CLONE_NEWUSER|CLONE_NEWNET) = 0
open("/proc/self/setgroups", O_WRONLY) = 3
write(3, "deny", 4) = 4
O que me sugere que descompartilhar o acesso à rede do processo atual é de fato a única maneira de conseguir descompartilhar (ou seja, não pode ser passado como um argumento spawn
ou algo equivalente). Também sugere que descompartilhar de um script de shell não funcionaria a menos que o shell tivesse sido especificamente estendido para expor um wrapper em torno do unshare
.
Isso pode ser feito, mais ou menos, com o
gdb
depurador, e se o processo em execução pode ser anexado (programas que alteram seu estado de despejo, ou são setgid etc. não podem ser anexados, a menos que sejam da raiz).Alguns arquivos opcionais podem ajudar a usar gdb como símbolos de depuração para libc6, e alguns arquivos de inclusão relacionados ao Linux para obter os valores reais de alguns símbolos mais tarde (por exemplo, no Debian: (possivelmente) e pacotes)
libc6-dbg
, mas na verdade uma vez que a "receita " for feito, eles provavelmente não serão mais necessários.libc6-dev
linux-libc-dev
Primeiro o que mais está fazendo? Sem isso, o novo usuário permanece e não pode nem escrever como seu usuário inicial:
unshare()
unshare -r
nobody
Isso será usado mais tarde.
Em outro terminal:
[...]
Agora vamos chamar a primeira função:
Ok, pode haver um método para que o gdb o conheça, mas não sou um guru:
No processo alterado, pode-se verificar que a
eth0
interface desapareceu:Não há como voltar atrás: o novo namespace de usuário não pode voltar ao namespace inicial. Se o processo estiver sendo executado com privilégios suficientes (por exemplo, root sem recursos perdidos nem SELinux), então seria possível (usando apenas
unshare(CLONE_NEWNET)
/setns(savedopenedfd)
).É claro que é possível criá-lo em um arquivo e alterar qualquer processo em execução permitido ou fazer com que o shell se altere a partir de um subprocesso gdb. Conteúdo de
removenetwork.gdb
, válido aqui apenas para alterar um processo compid:gid
==1000:1000
:ATUALIZAÇÃO: adicionado o tipo de retorno (aproximado) para as syscalls abaixo, isso deve evitar que algumas versões do gdb reclamem em ambientes não-dev:
Exemplo:
UPDATE : se o root não for necessário, como aparece para esta pergunta, não há necessidade de mapear para o root. Simplesmente substitua as ocorrências de
write($XX, "0 1000 1", 8)
porwrite($XX, "1000 1000 1", 11)
(para o casouid:gid
==1000:1000
). Grupos suplementares ainda são inevitavelmente perdidos, mas o uid/gid não muda (é mapeado para si mesmo).