새로운 Linux 사용자 네임스페이스의 첫 번째 프로세스는 setuid()를 호출해야 합니까?

새로운 Linux 사용자 네임스페이스의 첫 번째 프로세스는 setuid()를 호출해야 합니까?

저는 Linux 사용자 네임스페이스에 대해 배우고 있는데 완전히 명확하지 않은 이상한 동작을 관찰했습니다.

초기 사용자 네임스페이스에 일련의 UID를 만들었고 newuidmap명령을 통해 하위 사용자 네임스페이스의 UID를 이러한 UID에 매핑할 수 있었습니다. 내 설정은 다음과 같습니다.

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

그런 다음 새 사용자 네임스페이스를 만들고 해당 UID 범위를 상위 사용자 네임스페이스 [0-10000)에 매핑해 보았습니다 .[200000-210000)

  • 첫 번째 터미널:

    $ PS1='% ' unshare -U bash
    % echo $$
    1337
    % id
    uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
    
  • 터미널 2:

    $ ps -p 1337 -o uid
      UID
     1000
    $ newuidmap 1337 0 200000 10000
    $ ps -p 1337 -o uid
      UID
     1000
    
  • 첫 번째 터미널:

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

따라서 성공적으로 완료되더라도 newuidmap새 사용자의 네임스페이스 내부와 외부의 UID는 변경되지 않습니다.

그러다가 아래와 같은 글을 발견했습니다 http://www.itinken.com/blog/2016/Sep/exploring-unprivileged-containers/이것이 내 눈을 열었습니다. 이전 시나리오를 시도했지만 test-unshare.py명령 대신 다음 스크립트(기사에서 가져와 약간 수정함)를 사용했습니다 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')
  • 첫 번째 터미널:

    $ python3 ./test-unshare.py
    user id = 65534, process id = 1337
    Press Enter to continue...
    
  • 터미널 2:

    $ ps -p 1337 -o uid
      UID
     1000
    $ newuidmap 1337 0 200000 10000
    $ ps -p 1337 -o uid
      UID
     1000
    
  • 첫 번째 터미널:

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

    $ ps -p 1337 -o uid
      UID
    200000
    

이제 처음에 예상했던 것과 똑같아 보입니다. 이제 첫 번째 예에서 UID가 변경되지 않은 이유에 대한 내 이론은 다음과 같습니다.

unshare호출된 실행을 먼저 호출할 execve(2)필요는 없습니다 . 이제 쉘은 언급한 대로 모든 기능을 상실했으며 UID를 65534에서 변경할 수 없습니다. 두 번째 경우에는 프로세스가 UID를 0으로 변경하고 Linux는 이를 새로운 200000 이상으로 매핑합니다. 사용자 네임스페이스( 작성된 대로 )./bin/bashsetuid(2)user_namespaces(7)/proc/1337/uid_mapnewuidmap이는 새 사용자 네임스페이스의 첫 번째 프로세스가 setuid(START_UID)를 호출해야 함을 의미합니다.그렇지 않으면 65534 이후에 멈추게 됩니다 execve(2).

맞아?

이 기사에서는 첫 번째 예제(첫 번째 예제의 Python 코드와 동일)를 소개하고 다음과 같이 읽습니다.

시도해 보면 쉘이 실행되기 전에 uid 매핑이 설정되기 때문에 실제로는 잘 작동하지 않는다는 것을 알 수 있습니다.

그러나 매뉴얼 페이지의 정보에서는 이러한 결론을 도출할 수 없으며 매뉴얼 페이지에는 setuid(2)새 사용자 네임스페이스의 첫 번째 프로세스에서 호출되어야 한다고 명시적으로 명시되어 있지 않습니다.

그러나 이 경우 새 사용자 네임스페이스의 프로세스를 호출할 필요는 없지만 setuid(2)해당 UID가 변경되었습니다.

  • 첫 번째 터미널:

    $ PS1='% ' unshare -U bash
    % echo $$
    1337
    % id
    uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
    
  • 터미널 2:

    $ ps -p 1337 -o uid
      UID
     1000
    $ echo '500000 1000 1' >/proc/1337/uid_map
    $ ps -p 1337 -o uid
      UID
     1000
    
  • 첫 번째 터미널:

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

모든 상황을 자세히 설명해주세요.

/etc/subuid나의 여정은 이 파일의 목적을 이해하려고 노력하면서 시작되었습니다. Docker와 LXC가 이를 사용하지만 이를 설명하는 문서는 거의 없습니다. 너무 길게 얘기해서 죄송합니다. 이해하는데 오랜 시간이 걸렸지만, 아직도 완전히 이해가 되지 않아서 제가 알고 있는 내용을 여기에 모아봤습니다.

보너스: /etc/subuid사용자 네임스페이스와 어떻게 관련되는지, Docker와 LXC에서 이를 요구하는 이유, Linux 배포판에서 공통 인터페이스인 이유를 설명하세요. 매뉴얼 페이지는 간단하며 인터넷에 있는 기사는 대부분 LXC/Docker에서 무언가를 실행하는 방법을 문서화합니다. (실제 설명은 에 있습니다 newuidmap(1).)

답변1

보고 있다https://unix.stackexchange.com/a/110245/301641

이 답변을 보면 일부 UID가 매핑되지 않아 사용할 수 없음을 알 수 있습니다.

사례 1: "(65534)nobody inside, 1000(woky)outside"가 초기 값으로 사용됩니다. newuidmap 이후에도 맵이 얻어지지 않습니다([outside200000, Outside210000)만 매핑되지만 Outside1000은 매핑되어야 합니다. 범위를 벗어났습니다.) 그래서 아무것도 변하지 않았습니다.

사례 2: "(65534)nobody inside, 1000(woky)outside"가 초기 값으로 사용됩니다. newuidmap 이후에도 맵이 얻어지지 않습니다([outside200000, Outside210000)만 매핑되지만 Outside1000은 매핑되어야 합니다. 범위를 벗어났습니다.) 하지만 맵을 가져온 후에 setuid(inside0)를 설정하면(참고: uid_map에 쓰기 전에는 setuid를 설정할 수 없음) 맵에 있으므로 UID는 오버플로 값에서 일반 매핑 값(outside200000, inside0)으로 변경됩니다.

사례 3: newuidmap이 매핑된 후(outside1000이 매핑됨) 초기 값으로 "(65534)noy inside, 1000(woky) Outside"이므로 UID는 오버플로 값에서 일반 매핑 값(outside1000, inside500000)으로 변경됩니다.

관련 정보