ivot_root() 문서에서는 네임스페이스를 마운트하는 기능을 예측합니까?

ivot_root() 문서에서는 네임스페이스를 마운트하는 기능을 예측합니까?

ivot_root()는 호출 프로세스의 루트 파일 시스템을 put_old 디렉터리로 이동하고 new_root를 호출 프로세스의 새 루트 파일 시스템으로 만듭니다.

ivot_root()의 일반적인 사용은 시스템 시작 중에 시스템이 임시 루트 파일 시스템(예: initrd)을 마운트한 다음 실제 루트 파일 시스템을 마운트하고 결국 후자를 모든 관련 프로세스 또는 스레드의 현재 루트로 만드는 것입니다.

ivot_root()는 이전 루트 디렉터리를 사용하는 프로세스나 스레드의 현재 루트 디렉터리와 현재 작업 디렉터리를 변경할 수도 있고 변경하지 않을 수도 있습니다. ivot_root() 호출자는 루트 디렉터리 또는 현재 작업 디렉터리가 이전 루트 디렉터리에 있는 프로세스가 두 경우 모두 올바르게 실행되는지 확인해야 합니다. 이를 보장하는 간단한 방법은ivot_root()를 호출하기 전에 루트 디렉터리와 현재 작업 디렉터리를 new_root로 변경하는 것입니다.

위의 단락은 향후에ivot_root() 구현이 변경될 수 있으므로 의도적으로 모호하게 작성되었습니다. 이 글을 쓰는 시점에서,ivot_root()는 각 프로세스나 스레드의 루트 디렉터리와 현재 작업 디렉터리를 new_root로 변경합니다(이전 루트 디렉터리를 가리키는 경우). 이는 커널 스레드가 어떤 방식으로든 파일 시스템에 액세스하지 않더라도 이전 루트 디렉터리가 루트 디렉터리와 현재 작업 디렉터리로 바쁘게 유지되는 것을 방지하는 데 필요합니다. 미래에는 커널 스레드가 파일 시스템에 대한 모든 액세스를 명시적으로 포기하는 메커니즘이 있을 수 있으므로 이러한 다소 방해적인 메커니즘은ivot_root()에서 제거될 수 있습니다.

...

실수

ivot_root()는 시스템에 있는 다른 모든 프로세스의 루트 디렉터리와 현재 작업 디렉터리를 변경할 필요가 없습니다.

ivot_root()의 좀 더 모호한 사용은 빠르게 광기로 이어질 수 있습니다.

-- man pivot_root, Linux 매뉴얼 페이지 4.15

나는ivot_root()가 호출될 때 여러 프로세스가 실행되는 상황에서 작업하고 있습니다.

맨페이지에서는 두 가지 가능한ivot_root() 구현이 다중 프로세스 상황을 처리하는 방법에 대해 명확하지 않은 것 같습니다. S(ystemd)와 P(lymouth)라는 두 개의 프로세스가 있다고 가정합니다. 현재 P와 S는 루트와 작업 디렉터리를 new_root로 변경하고 S는ivot_root()를 호출합니다. 현재 구현에 따르면 이는 정상적으로 작동합니다.

S와 P가 Pivot_root() 전에 chroot()를 사용하여 "그들의 루트를 변경"한다고 가정합니다. 그러나 man chroot우리가 들었던 것처럼, 당신이 root()라면 chroot() 감옥을 떠날 수 있습니다 mkdir foo; chroot foo; cd ..; chroot .. 분명히 프로세스에는 두 가지 관련 뿌리가 있습니다.

  1. 현재 chroot
  2. 마운트 네임스페이스의 루트

Pivot_root()를 실행한 후 S는 마운트된 네임스페이스의 루트가 현재 chroot와 동일한지 확인해야 합니다. 나중에 이스케이프할 수 있는 더 깊은 루트 파일 시스템이 있는 경우 해당 루트 파일 시스템은 사용 중이므로 마운트 해제할 수 없습니다. 나는 이전 루트 파일 시스템을 마운트 해제하도록 허용하는 것이ivot_root()의 주요 목적이라고 생각합니다.

현재 P는 S와 동일한 마운트 네임스페이스에 있기 때문에 동일한 것을 관찰합니다.

Pivot_root()의 대체 구현이 호출 프로세스를 새롭고 변경된 설치 네임스페이스에 넣는 것처럼 들립니다. 이것이 유효한 읽기인가?

(나는 이 대체 구현이 /sbin/pivot_root거의 의미가 없다는 것을 알았습니다).

나는 원래의ivot_root()가 실제로 마운트되는 네임스페이스보다 앞서 있다고 생각합니다. Pivot_root()의 대체 구현에 대한 이 계획이 마운트된 네임스페이스의 일부 기능에 대한 필요성을 예견하는지, 아니면 이 요구 사항을 무시하는지 알고 있습니까?

(마운트 네임스페이스는 "커널 스레드가 파일 시스템에 대한 모든 액세스를 명시적으로 포기하는 메커니즘"과 매우 유사하게 들립니다. 따라서 커널 스레드는 빈 tmpfs에서ivot_root()와 동등한 작업을 수행할 수 있습니다.)

답변1

Pivot_root()의 대체 구현이 호출 프로세스를 새롭고 변경된 설치 네임스페이스에 넣는 것처럼 들립니다. 이것이 유효한 읽기인가?

아니요, 그다지 명확하지는 않지만 더 일관되고 정확한 읽기가 있다고 생각합니다.

ivot_root()의 기본 부분(두 구현 모두 동일해야 함)은 다음과 같습니다.

ivot_root()는 호출 프로세스의 루트 파일 시스템을 put_old 디렉터리로 이동하고 new_root를 호출 프로세스의 새 루트 파일 시스템으로 만듭니다.

ivot_root()의 핵심 부분은 호출 프로세스에만 국한되지 않습니다. 이 참조에 설명된 작업은 호출 프로세스의 탑재 네임스페이스에 적용됩니다. 이는 동일한 마운트 네임스페이스에 있는 모든 프로세스의 보기에 영향을 미칩니다.

작업 디렉토리가 이전 루트 파일 시스템인 두 번째 프로세스(또는 커널 스레드)에 대한 기본 변경의 영향을 고려하십시오. 현재 디렉터리는 여전히 이전 루트 파일 시스템입니다. 이렇게 하면 /put_old마운트 지점이 계속 사용되므로 이전 루트 파일 시스템을 마운트 해제할 수 없습니다.

두 번째 프로세스를 제어하는 ​​경우 맨페이지에 따라 Pivot_root()를 호출하기 전에 해당 프로세스의 작업 디렉터리를 new_root로 설정하여 이 문제를 해결할 수 있습니다. ivot_root()가 호출된 후에도 현재 디렉터리는 여전히 새 루트 파일 시스템이 됩니다.

따라서 프로세스 S(ystemd)는 S가 ivot_root()를 호출하기 전에 작업 디렉터리를 변경하기 위해 프로세스 P(lymouth)에 신호를 보내도록 구성되었습니다. 괜찮아요. 그러나 커널 스레드도 있으며 . 현재 ivot_root() 구현은 커널 스레드의 작업 디렉터리와 ivot_root()의 기본 부분 이전에 /다른 프로세스를 설정하는 것과 같습니다 .new_root

그 외에도 현재의ivot_root() 구현은 이전 작업 디렉터리가 .인 경우에만 프로세스의 작업 디렉터리를 변경합니다 /. 따라서 실제로 차이점을 쉽게 확인할 수 있습니다.

$ unshare -rm
# cd /tmp    # work in a subdir instead of '/', and pivot_root() will not change it
# /bin/pwd
/tmp
# mount --bind /new-root /new-root
# pivot_root /new-root /new-root/mnt
# /bin/pwd
/mnt/tmp    # see below: if pivot_root had not updated our current chroot, this would still show /tmp

그리고

$ unshare -rm
# cd /
# /bin/pwd
/
# ls -lid .
2 dr-xr-xr-x. 19 nfsnobody nfsnobody 4096 Jun 13 01:17 .
# ls -lid /newroot
6424395 dr-xr-xr-x. 20 nfsnobody nfsnobody 4096 May 10 12:53 /new-root
# mount --bind /new-root /new-root
# pivot_root /new-root /new-root/mnt
# /bin/pwd
/
# ls -lid .
6424395 dr-xr-xr-x. 20 nobody nobody 4096 May 10 12:53 .
# ls -lid /
6424395 dr-xr-xr-x. 20 nobody nobody 4096 May 10 12:53 /
# ls -lid /mnt
2 dr-xr-xr-x. 19 nobody nobody 4096 Jun 13 01:17 /mnt

이제 작업 디렉토리에 무슨 일이 일어나는지 이해했으므로 chroot()에 무슨 일이 일어나는지 더 쉽게 이해할 수 있습니다. ivot_root()를 호출하는 프로세스의 현재 chroot는 현재 작업 디렉터리와 마찬가지로 원래 루트 파일 시스템에 대한 참조일 수 있습니다.

chdir()+pivot_root()를 실행했지만 chroot()를 잊어버린 경우 현재 디렉터리는 다음과 같습니다.외부현재 chroot. 현재 디렉토리가 현재 chroot 외부에 있으면 상황이 매우 복잡해질 수 있습니다. 아마도 이 상태에서는 프로그램을 실행하고 싶지 않을 것입니다.

# cd /
# python
>>> import os
>>> os.chroot("/newroot")
>>> os.system("/bin/pwd")
(unreachable)/
0
>>> os.getcwd()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 2] No such file or directory
>>> os.system("ls -l ./proc/self/cwd")
lrwxrwxrwx. 1 root root 0 Jun 17 13:46 ./proc/self/cwd -> /
0
>>> os.system("ls -lid ./proc/self/cwd/")
2 dr-xr-xr-x. 19 root root 4096 Jun 13 01:17 ./proc/self/cwd/
0
>>> os.system("ls -lid /")
6424395 dr-xr-xr-x. 20 root root 4096 May 10 12:53 /
0

이 경우 POSIX는 pwdgetcwd() 또는 getcwd()의 결과를 지정하지 않습니다 :). POSIX는 getcwd()에서 "해당 파일 또는 디렉터리 없음"(ENOENT) 오류가 발생할 수 있음을 경고하지 않습니다. Linux 맨페이지에는 rm작업 디렉터리가 연결되지 않은 경우(예: 를 사용하여) 이 오류가 발생할 수 있다고 명시되어 있습니다. 나는 그것이 좋은 비유라고 생각한다.

관련 정보