O primeiro processo em um novo namespace de usuário do Linux precisa chamar setuid ()?

5

Estou aprendendo sobre namespaces de usuários Linux e estou observando um comportamento estranho que não está completamente claro para mim.

Eu criei um intervalo de UIDs em namespaces de usuário iniciais para os quais eu posso mapear UIDs no namespace de usuário filho por meio do comando newuidmap . Estas são minhas configurações:

$ grep '^woky:' /etc/subuid
woky:200000:10000
$ id -u
1000

Depois, tentei criar um novo namespace de usuário e mapear seu intervalo de UID [0-10000) to [200000-210000) no namespace de usuário pai:

  • Primeiro terminal:

    $ PS1='% ' unshare -U bash
    % echo $$
    1337
    % id
    uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
    
  • Segundo terminal:

    $ ps -p 1337 -o uid
      UID
     1000
    $ newuidmap 1337 0 200000 10000
    $ ps -p 1337 -o uid
      UID
     1000
    
  • Primeiro terminal:

    % id
    uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
    

Assim, os UIDs dentro e fora do novo namespace de usuário não foram alterados, mesmo que o newuidmap tenha sido concluído com êxito.

Então achei o seguinte artigo link que abriu um pouco meus olhos. Eu tentei o cenário anterior, mas com o seguinte script test-unshare.py , que tirei do artigo e modifiquei um pouco, em vez do comando unshare :

#!/usr/bin/python3
import os
from cffi import FFI
CLONE_NEWUSER = 0x10000000
ffi = FFI()
ffi.cdef('int unshare(int flags);')
libc = ffi.dlopen(None)

libc.unshare(CLONE_NEWUSER)
print("user id = %d, process id = %d" % (os.getuid(), os.getpid()))
input("Press Enter to continue...")
# The uid must be set to 0 to avoid loosing capabilities when creating the shell.
os.setuid(0)
os.execlp('/bin/bash', 'bash')
  • Primeiro terminal:

    $ python3 ./test-unshare.py
    user id = 65534, process id = 1337
    Press Enter to continue...
    
  • Segundo terminal:

    $ ps -p 1337 -o uid
      UID
     1000
    $ newuidmap 1337 0 200000 10000
    $ ps -p 1337 -o uid
      UID
     1000
    
  • Primeiro terminal:

    <Enter>
    bash: /home/woky/.bashrc: Permission denied
    bash-4.4# id
    uid=0(root) gid=65534(nobody) groups=65534(nobody)
    
  • Segundo terminal:

    $ ps -p 1337 -o uid
      UID
    200000
    

Agora parece que eu esperava desde o começo. Agora, minha teoria sobre por que os UIDs no primeiro exemplo não foram alterados é a seguinte:

O unshare chamado execve(2) para executar /bin/bash sem chamar primeiro setuid(2) . Agora o shell perdeu todos os seus recursos (como mencionado em user_namespaces(7) ) e não pode alterar seu UID de 65534. No segundo caso, o processo mudou seu UID para 0, porque ele tinha recursos para isso e o Linux o mapeou para 200000 fora do novo namespace de usuário (de acordo com /proc/1337/uid_map , que newuidmap escreveu). O que significa que o primeiro processo em um novo namespace de usuário deve chamar setuid (START_UID) ou, caso contrário, ele ficará preso em 65534 após execve(2) .

Está correto?

O artigo diz sobre o meu primeiro exemplo (que é equivalente ao código Python em seu primeiro exemplo):

If you just try this out, you'll probably find that it doesn't really quite work, this is because the uid map has the be set before the shell is executed.

Mas não posso concluir isso a partir das informações contidas nas páginas man, nem as páginas man afirmam explicitamente que setuid(2) precisa ser chamado no primeiro processo em um novo namespace de usuário.

No entanto, neste cenário, o processo no novo namespace de usuário não precisou chamar setuid(2) e, ainda assim, seu UID foi alterado:

  • Primeiro terminal:

    $ PS1='% ' unshare -U bash
    % echo $$
    1337
    % id
    uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
    
  • Segundo terminal:

    $ ps -p 1337 -o uid
      UID
     1000
    $ echo '500000 1000 1' >/proc/1337/uid_map
    $ ps -p 1337 -o uid
      UID
     1000
    
  • Primeiro terminal:

    % id
    uid=500000 gid=65534(nobody) groups=65534(nobody)
    

Por favor, explique todas as situações em profundidade.

Minha jornada começou quando tentei entender para que serve o arquivo /etc/subuid . É usado pelo Docker e pelo LXC, mas apenas alguns documentos explicam isso. Desculpe pela verbosidade. Demorei muito tempo para compreendê-lo e ainda não o entendi totalmente, então estou colecionando aqui tudo que sei.

BONUS: Explique /etc/subuid , sua relação com namespaces de usuários, por que é necessário para Docker e LXC, e por que é uma interface genérica nas distribuições Linux. A página do manual é breve e os artigos na Internet documentam principalmente como fazer algo no trabalho do LXC / Docker. (A explicação real está em newuidmap(1) ).

    
por woky 15.06.2018 / 22:46

1 resposta

1

Veja o link

Veja essa resposta, você pode ver um UID como ninguém, já que eles não estão mapeados.

Situação 1 : "(65534) ninguém dentro, 1000 (woky) fora" como valor init, depois que o newuidmap ainda não obtém um mapa (somente [outside200000, outside210000) são mapeados, mas precisam do outside1000 para serem mapeados, fora do intervalo). Então nada mudou.

Situação 2: "(65534) ninguém dentro, 1000 (woky) fora" como valor init, depois que o newuidmap ainda não obtém um mapa (somente [outside200000, outside210000) são mapeados, mas precisam do outside1000 para serem mapeados, fora do intervalo). Mas você setuid (inside0) logo após pegar o mapa (note que você nunca pode setuid antes de escrever para uid_map), que está no mapa, então o UID mudou do valor de overflow para o valor mapeado normal (outside200000, inside0).

Situação 3: "(65534) ninguém dentro, 1000 (woky) fora" como valor init, depois que o newuidmap pega um mapa (outside1000 é mapeado), então o UID mudou de valor de overflow para valor mapeado normal (outside1000, inside500000).

    
por 21.07.2018 / 11:22