정의: chroot – Linux의 시스템 호출 및 유틸리티

13368 단어 systemcallskernellinux
chroot()는 1979년 버전 7 Unix에 added이었으며 파일 시스템 격리에 사용되었습니다.

사실, 이것은 전체 현재 컨테이너화 아이디어의 전신이며, 지금은 namespaces cgroups가 사용되고 이전 chroot는 예를 들어 호스트에서 격리되고 테스트 목적으로 사용될 수 있는 환경을 만드는 데 사용되었습니다.

또한 ch와 root는 change와 root(파일 시스템의)의 "약어"입니다.

Linux 파일 시스템 트리



Linux의 디렉토리 트리는 일반적으로 다음과 같습니다(Filesystem Hierarchy Standard 참조).



$ tree -d -L 1 /
/
├── bin -> usr/bin
├── boot
├── data
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib64 -> usr/lib
├── lost+found
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/bin
├── srv
├── sys
├── tmp
├── usr
└── var
chroot() 다음 그림과 함께 시연할 수 있는 중첩된 파일 시스템 트리를 만들 수 있습니다.



아래에서 일부 C 코드 예제와 chroot() 유틸리티 및 운영 체제에서의 사용법에 대해 자세히 살펴보겠습니다.

chroot – Linux 시스템 호출



따라서 chroot는 루트를 변경하여 파일 시스템에 대한 액세스를 제한하기 위한 것입니다.

즉. 다음과 같은 디렉토리 구조 대신:

$ tree -d -L 1 /
/
├── bin -> usr/bin
├── boot
├── data
...
├── tmp
├── usr
└── var

프로세스는 chroot() 에 전달된 매개변수에 의해 최상위 수준에서 제한되는 항목만 볼 수 있습니다.

예를 들어 사용할 다음 디렉토리를 만들어 보겠습니다.

$ mkdir -p /tmp/chroot/{1,2,3,4}

그리고 다음 코드를 C로 작성해 봅시다.

#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
int main(void) {

    // check path before chroot()
    char t_cwd[PATH_MAX];
    getcwd(t_cwd, sizeof(t_cwd));
    printf("Current dir before chroot(): %s\n", t_cwd);

    // do chroot()
    chdir("/tmp/chroot/");
    if (chroot("/tmp/chroot/") != 0) {
        perror("chroot /tmp/chroot/");
        return 1;
    }

    // check path path after chroot()
    char a_cwd[PATH_MAX];
    getcwd(a_cwd, sizeof(a_cwd));
    printf("Current dir after chroot(): %s\n", a_cwd);
    // point dr struct to the "root"
    struct dirent *de;
    DIR *dr = opendir("/");  

    // run readdir() and list "root"'s content
    while ((de = readdir(dr)) != NULL)  
        printf("%s\n", de->d_name);  

    // try to open /etc/passwd from a "host" filesystem
    FILE *f;
    f = fopen("/etc/passwd", "r");
    if (f == NULL) {
        perror("/etc/passwd");
        return 1;
    } else {
        char buf[100];
        while (fgets(buf, sizeof(buf), f)) {
             printf("%s", buf);
        }
    }
    return 0;
}

여기서는 다음과 같습니다.
  • 호출하기 전에 현재 경로를 확인하십시오chroot().
  • 전화 chroot()
  • 현재 경로를 다시 확인하십시오
  • .
  • "루트"콘텐츠 가져오기
  • "실제"파일 시스템에 있는 chroot() 파일을 열려고 합니다
  • .

    구축:

    $ gcc chroot_example.c -o chroot_example
    

    그리고 실행하여 확인합니다(/etc/passwd는 루트에서만 사용할 수 있으므로):

    $ sudo ./chroot_example
    Current dir before chroot(): /home/setevoy/Scripts/C
    Current dir after chroot(): /
    .
    ..
    4
    3
    2
    1
    /etc/passwd: No such file or directory
    
    sudo 자체는 커널의 chroot() 파일에 정의되어 있습니다.

    SYSCALL_DEFINE1(chroot, const char __user *, filename)
    {
      return ksys_chroot(filename);
    }
    

    그리고 chroot() 을 반환합니다.

    int ksys_chroot(const char __user *filename)
    {
      struct path path;
      int error;
      unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
    retry:
      error = user_path_at(AT_FDCWD, filename, lookup_flags, &path);
      if (error)
        goto out;
      error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
      if (error)
        goto dput_and_out;
      error = -EPERM;
      if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
        goto dput_and_out;
      error = security_path_chroot(&path);
      if (error)
        goto dput_and_out;
      set_fs_root(current->fs, &path);
      error = 0;
    dput_and_out:
      path_put(&path);
      if (retry_estale(error, lookup_flags)) {
        lookup_flags |= LOOKUP_REVAL;
        goto retry;
      }
    out:
      return error;
    }
    

    차례로 프로세스에 대해 open.c 을 호출합니다.

    void set_fs_root(struct fs_struct *fs, const struct path *path)
    {
      struct path old_root;
      path_get(path);
      spin_lock(&fs->lock);
      write_seqcount_begin(&fs->seq);
      old_root = fs->root;
      fs->root = *path;
      write_seqcount_end(&fs->seq);
      spin_unlock(&fs->lock);
      if (old_root.dentry)
        path_put(&old_root);
    }
    

    좋은 syscalls 설명 here>>here>>>을 찾을 수 있습니다.


    ksys_chroot() – Linux 유틸리티



    Linux에서 격리된 공간을 만들려면 set_fs_root() 유틸리티를 사용할 수 있습니다.

    $ which chroot
    /usr/bin/chroot
    $ file /usr/bin/chroot
    /usr/bin/chroot: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f3861107940247a67dbbf6343fa5ff1c1c70305c, stripped
    

    격리된 파일 시스템을 사용하여 "감옥"(FreeBSD chroot 은 UNIX chroot의 고급 후속 제품)에 대한 카탈로그를 생성해 보겠습니다.

    $ cd /tmp/
    $ mkdir changed_root
    

    실제로 chroot 유틸리티는 동일한 jail 시스템 호출을 호출합니다. chroot 으로 확인하겠습니다.

    $ sudo strace -e trace=chroot chroot changed_root/
    chroot("changed_root/")                 = 0
    chroot: failed to run command ‘/bin/bash’: No such file or directory
    +++ exited with 127 +++
    

    '/bin/bash': 이 새로운 환경에는 chroot() 디렉토리와 strace 실행 파일이 없다는 사실로 인해 이러한 파일 또는 디렉토리 오류가 발생하지 않습니다.

    마찬가지로 다른 프로그램을 호출하려고 하면 이러한 오류가 반환됩니다.

    [setevoy@setevoy-arch-work /tmp]  $ which ls
    /usr/bin/ls
    [setevoy@setevoy-arch-work /tmp]  $ sudo chroot changed_root /usr/bin/ls
    chroot: failed to run command ‘/usr/bin/ls’: No such file or directory
    

    수정해 보겠습니다. /binbash 디렉토리를 만들고 이 "컨테이너"내부의 "호스트"에서 파일을 복사/bin합니다.

    [setevoy@setevoy-arch-work /tmp]  $ mkdir changed_root/bin
    [setevoy@setevoy-arch-work /tmp]  $ cp /bin/bash changed_root/bin
    [setevoy@setevoy-arch-work /tmp]  $ file changed_root/bin/bash
    changed_root/bin/bash: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=357034d1736cd97d2c8f8347045250dbd0de998e, stripped
    

    다시 시도하십시오:

    [setevoy@setevoy-arch-work /tmp]  $ sudo chroot changed_root /bin/bash
    chroot: failed to run command ‘/bin/bash’: No such file or directory
    

    괜찮아.

    그러나 지금은 필요한 라이브러리가 없기 때문에 발생합니다. /tmp/changed_root 이것에 대해 말할 수 없습니다.
    bash의 종속성을 chroot 으로 확인합니다.

    [setevoy@setevoy-arch-work /tmp]  $ ldd /bin/bash
    linux-vdso.so.1 (0x00007ffe37f16000)
    libreadline.so.8 => /usr/lib/libreadline.so.8 (0x00007f39b13d2000)
    libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f39b13cd000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007f39b1209000)
    libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f39b119a000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f39b153f000)
    

    새 작업 디렉터리에 두 개의 카탈로그(bashldd)를 더 만듭니다.

    [setevoy@setevoy-arch-work /tmp]  $ mkdir changed_root/usr/lib changed_root/lib64
    

    그리고 libs 파일을 복사합니다.

    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/lib/libreadline.so.8 changed_root/usr/lib/
    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/lib/libdl.so.2 changed_root/usr/lib/
    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/lib/libc.so.6 changed_root/usr/lib/
    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/lib/libncursesw.so.6 changed_root/usr/lib/
    [setevoy@setevoy-arch-work /tmp]  $ cp /lib64/ld-linux-x86-64.so.2 changed_root/lib64
    
    /lib를 다시 실행합니다.

    [setevoy@setevoy-arch-work /tmp]  $ sudo chroot changed_root/
    bash-5.0#
    

    이제 여기에서 실행 중인 /lib64 및 모든 내장 함수가 있습니다.

    bash-5.0# pwd
    /
    

    그러나 분명히 – 다른 외부 유틸리티는 여기에서 작동하지 않습니다.

    bash-5.0# ls -l
    bash: ls: command not found
    

    그리고 이것은 chroot에 대해 수행한 것과 동일한 방식으로 수정할 수 있습니다.

    [setevoy@setevoy-arch-work /tmp]  $ which ls
    /usr/bin/ls
    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/bin/ls changed_root/bin/
    [setevoy@setevoy-arch-work /tmp]  $ ldd /usr/bin/ls
    linux-vdso.so.1 (0x00007ffdebbf5000)
    libcap.so.2 => /usr/lib/libcap.so.2 (0x00007fa5b147d000)
    libc.so.6 => /usr/lib/libc.so.6 (0x00007fa5b12b9000)
    /lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fa5b14d8000)
    [setevoy@setevoy-arch-work /tmp]  $ cp /usr/lib/libcap.so.2 changed_root/usr/lib/
    

    다른 라이브러리는 이미 복사되었으므로 다시 실행해 보겠습니다bash.

    bash-5.0# /bin/ls -l /
    total 0
    drwxr-xr-x 2 1000 1000  80 Mar 22 11:45 bin
    drwxr-xr-x 2 1000 1000 120 Mar 22 11:37 lib
    drwxr-xr-x 2 1000 1000  60 Mar 22 11:38 lib64
    drwxr-xr-x 3 1000 1000  60 Mar 22 11:39 usr
    

    또한보십시오


  • Containerization Mechanisms: Namespaces
  • Linux Virtualization – Chroot Jail
  • chroot, cgroups and namespaces — An overview
  • The somewhat surprising history of chroot()
  • chroot(2) – Linux man page
  • Anatomy of a system call, part 1

  • 유사한 게시물



  • 2019-03-03 (0)

  • 2018-03-10 What is: Linux namespaces, примеры PID и Network namespaces (0)

  • 2017년 3월 18일 Linux: LVM – уменьшить home, увеличить root (1)

  • 2018-10-20 Linux: увеличение размера раздела без LVM с сохранением данных на ext4 (0)
  • 좋은 웹페이지 즐겨찾기