linux chroot 理解--转

目录

定义

​基本语法

chroot 作用

chroot 使用

chroot 命令的内部实现


定义

chroot,即 change root directory (更改 root 目录)。在 linux 系统中,系统默认的目录结构都是以 /,即以根 (root) 开始的。而在使用 chroot 之后,系统的目录结构将以指定的位置作为 / 位置。


基本语法

# man chroot

CHROOT(1)                                                                                                             

NAME
       chroot - run command or interactive shell with special root directory

SYNOPSIS
       chroot [OPTION] NEWROOT [COMMAND [ARG]...]
       chroot OPTION

DESCRIPTION
       Run COMMAND with root directory set to NEWROOT.

       --userspec=USER:GROUP
              specify user and group (ID or name) to use

       --groups=G_LIST
              specify supplementary groups as g1,g2,..,gN

       --help display this help and exit

       --version
              output version information and exit

       If no command is given, run '${SHELL} -i' (default: '/bin/sh -i').

COMMAND 表示 NEWROOT作为新的 root 后,已何种 shell 来和环境进行交互。默认不指定该参数,则用的是 "$SHELL" 环境变量中指定的 shell 来进行交互。


chroot 作用

在经过 chroot 之后,系统读取到的目录和文件将不在是旧系统根下的而是新根下(即被指定的新的位置)的目录结构和文件;

增加了系统的安全性,限制了用户的权力:
在经过 chroot 之后,在新根下将访问不到旧系统的根目录结构和文件,这样就增强了系统的安全性。一般会在用户登录前应用 chroot,把用户的访问能力控制在一定的范围之内。

建立一个与原系统隔离的系统目录结构,方便用户的开发:
使用 chroot 后,系统读取的是新根下的目录和文件,这是一个与原系统根下文件不相关的目录结构。在这个新的环境中,可以用来测试软件的静态编译以及一些与系统不相关的独立开发。

切换系统的根目录位置,引导 Linux 系统启动以及急救系统等:
chroot 的作用就是切换系统的根位置,而这个作用最为明显的是在系统初始引导磁盘的处理过程中使用,从初始 RAM 磁盘 (initrd) 切换系统的根位置并执行真正的 init,本文的最后一个 demo 会详细的介绍这种用法。

chroot 使用

需求

我想要做的是,把根目录设置为 /home/test 目录

test 目录结构

# pwd
/home/test

# ll
total 0
-rw-r--r-- 1 root root 0 Nov 15 14:46 aa.out
-rw-r--r-- 1 root root 0 Nov 15 14:46 bb.out
-rw-r--r-- 1 root root 0 Nov 15 14:46 cc.out

# chroot /home/test
chroot: failed to run command ‘/bin/bash’: No such file or directory

如果不给 chroot 指定执行的命令,默认它会执行 '${SHELL} -i',而我的系统中 ${SHELL} 为 /bin/bash。如下所示:


一开始会报错,是因为切换根目录无法找到默认 shell – bash,所以我们只需要按照原样拷贝 /bin/bash 到 test/bin 下。

# mkdir bin
# cp /bin/bash /home/test/bin
# tree /home/test/
./
├── aa.out
├── bb.out
├── bin
│   └── bash
└── cc.out

# chroot /home/test
仍然报错,是因为我们没有解决 bash 的依赖问题,用 ldd 检查依赖

# ldd bin/bash 
        linux-vdso.so.1 =>  (0x00007ffd8b3d7000)
        libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007fc5eecc3000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fc5eeabf000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc5ee6f1000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc5eeeed000)
# cp -rf /lib64/ /home/test
# ll /home/test
total 72
-rw-r--r--  1 root root     0 Nov 15 14:46 aa.out
-rw-r--r--  1 root root     0 Nov 15 14:46 bb.out
drwxr-xr-x  2 root root  4096 Nov 15 14:49 bin
-rw-r--r--  1 root root     0 Nov 15 14:46 cc.out
dr-xr-xr-x 79 root root 65536 Nov 15 14:50 lib64

# chroot /home/test
bash-4.2# echo $$
23330

bash-4.2# ls -al
bash: ls: command not found

这个是因为在 当前的 根目录(/) 实际是 /home/test , bin(/home/test/bin)下没有 ls 命令;

将 /bin/ls 拷贝到 /home/test/bin ,然后再执行 chroot /home/test ,如下所示:

# cp /bin/ls /home/test/bin
# cp /bin/pwd /home/test/bin
# chroot /home/test/
bash-4.2# pwd
/    # 新的目录变成了根目录;
bash-4.2# ls -al  # 新根目录下的文件 和 /home/test 一样;
total 80
drwxr-xr-x  4 0 0  4096 Nov 15 06:50 .
drwxr-xr-x  4 0 0  4096 Nov 15 06:50 ..
-rw-r--r--  1 0 0     0 Nov 15 06:46 aa.out
-rw-r--r--  1 0 0     0 Nov 15 06:46 bb.out
drwxr-xr-x  2 0 0  4096 Nov 15 07:07 bin
-rw-r--r--  1 0 0     0 Nov 15 06:46 cc.out
dr-xr-xr-x 79 0 0 65536 Nov 15 06:50 lib64
bash-4.2#
bash-4.2# echo $$
45681

另外开一个窗口,查看 当前 bash 进程的 root 目录,如下所示, root 为 /home/test; 


# ps -ef |grep 45681
root     45681 36510  0 15:15 pts/1    00:00:00 /bin/bash -i
root     45725 14975  0 15:15 pts/0    00:00:00 grep --color=auto 45681

# cd /proc/45681
root@xxxx:/proc/45681
# ll
total 0
dr-xr-xr-x 2 root root 0 Nov 15 15:16 attr
-rw-r--r-- 1 root root 0 Nov 15 15:16 autogroup
-r-------- 1 root root 0 Nov 15 15:16 auxv
-r--r--r-- 1 root root 0 Nov 15 15:16 cgroup
--w------- 1 root root 0 Nov 15 15:16 clear_refs
-r--r--r-- 1 root root 0 Nov 15 15:15 cmdline
-rw-r--r-- 1 root root 0 Nov 15 15:16 comm
-rw-r--r-- 1 root root 0 Nov 15 15:16 coredump_filter
-r--r--r-- 1 root root 0 Nov 15 15:16 cpuset
lrwxrwxrwx 1 root root 0 Nov 15 15:16 cwd -> /home/test
-r-------- 1 root root 0 Nov 15 15:16 environ
lrwxrwxrwx 1 root root 0 Nov 15 15:16 exe -> /home/test/bin/bash
dr-x------ 2 root root 0 Nov 15 15:15 fd
dr-x------ 2 root root 0 Nov 15 15:16 fdinfo
-rw-r--r-- 1 root root 0 Nov 15 15:16 gid_map
-r-------- 1 root root 0 Nov 15 15:16 io
-r--r--r-- 1 root root 0 Nov 15 15:16 limits
-rw-r--r-- 1 root root 0 Nov 15 15:16 loginuid
dr-x------ 2 root root 0 Nov 15 15:16 map_files
-r--r--r-- 1 root root 0 Nov 15 15:16 maps
-rw------- 1 root root 0 Nov 15 15:16 mem
-r--r--r-- 1 root root 0 Nov 15 15:16 mountinfo
-r--r--r-- 1 root root 0 Nov 15 15:16 mounts
-r-------- 1 root root 0 Nov 15 15:16 mountstats
dr-xr-xr-x 6 root root 0 Nov 15 15:16 net
dr-x--x--x 2 root root 0 Nov 15 15:16 ns
-r--r--r-- 1 root root 0 Nov 15 15:16 numa_maps
-rw-r--r-- 1 root root 0 Nov 15 15:16 oom_adj
-r--r--r-- 1 root root 0 Nov 15 15:16 oom_score
-rw-r--r-- 1 root root 0 Nov 15 15:16 oom_score_adj
-r--r--r-- 1 root root 0 Nov 15 15:16 pagemap
-r-------- 1 root root 0 Nov 15 15:16 patch_state
-r--r--r-- 1 root root 0 Nov 15 15:16 personality
-rw-r--r-- 1 root root 0 Nov 15 15:16 projid_map
lrwxrwxrwx 1 root root 0 Nov 15 15:16 root -> /home/test
-rw-r--r-- 1 root root 0 Nov 15 15:16 sched
-r--r--r-- 1 root root 0 Nov 15 15:16 schedstat
-r--r--r-- 1 root root 0 Nov 15 15:16 sessionid
-rw-r--r-- 1 root root 0 Nov 15 15:16 setgroups
-r--r--r-- 1 root root 0 Nov 15 15:16 smaps
-r--r--r-- 1 root root 0 Nov 15 15:16 stack
-r--r--r-- 1 root root 0 Nov 15 15:15 stat
-r--r--r-- 1 root root 0 Nov 15 15:16 statm
-r--r--r-- 1 root root 0 Nov 15 15:15 status
-r--r--r-- 1 root root 0 Nov 15 15:16 syscall
dr-xr-xr-x 3 root root 0 Nov 15 15:16 task
-r--r--r-- 1 root root 0 Nov 15 15:16 timers
-rw-r--r-- 1 root root 0 Nov 15 15:16 uid_map
-r--r--r-- 1 root root 0 Nov 15 15:16 wchan

chroot 命令的内部实现

# man 2 chroot
CHROOT(2)
NAME
       chroot - change root directory

SYNOPSIS
       #include <unistd.h>

       int chroot(const char *path);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       chroot():
           Since glibc 2.2.2:
               _BSD_SOURCE ||
                   (_XOPEN_SOURCE >= 500 ||
                       _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) &&
                   !(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
           Before glibc 2.2.2: none

DESCRIPTION
       chroot() changes the root directory of the calling process to that specified in path.  This directory will be used for pathnames beginning with /.  The root directory is inherited by all children of the calling process.

       Only a privileged process (Linux: one with the CAP_SYS_CHROOT capability) may call chroot().

       This call changes an ingredient in the pathname resolution process and does nothing else.

       This call does not change the current working directory, so that after the call '.' can be outside the tree rooted at '/'.  In particular, the superuser can escape from a "chroot jail" by doing:

           mkdir foo; chroot foo; cd ..

       This call does not close open file descriptors, and such file descriptors may allow access to files outside the chroot tree.

RETURN VALUE
       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

chroot 涉及的2个函数

#include <unistd.h>
int chroot(const char *path);
int chdir(const char *path);
chroot() 将切换参数 path 所指位置为根目录 (/),chdir() 用来将当前的工作目录改变成以参数path 所指的目录。

查看 chroot 涉及的系统调用

实现 chroot 命令

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int main(int argc, char *argv[])
{
    if(argc<2){
        printf("Usage: chroot NEWROOT [COMMAND...] \n");
        return 1;
    }

    if(chroot(argv[1])) {
        perror("chroot");
        return 1;
    }
 
    if(chdir("/")) {
        perror("chdir");
        return 1;
    }
 
    if(argc == 2) {
        // hardcode /bin/sh for my busybox tools.
        argv[0] = (char *)"/bin/sh";
 
        argv[1] = (char *) "-i";
        argv[2] = NULL;
    } else {
        argv += 2;
    }
 
    execvp (argv[0], argv);
    printf("chroot: cannot run command `%s`\n", *argv);
 
    return 0;
}

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值