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

基本句型

chrootNEWROOT[COMMAND[ARG]...]

具体用法请参考本文的demo。

为何要使用chroot

降低了系统的安全性,限制了用户的权利:

在经过chroot以后,在新根下将访问不到旧系统的根目录结构和文件,这样就提高了系统的安全性。通常会在用户登陆前应用chrootredhat linux,把用户的访问能力控制在一定的范围之内。

构建一个与原系统隔离的系统目录结构,便捷用户的开发:

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

切换系统的根目录位置,引导Linux系统启动以及急救系统等:

chroot的作用就是切换系统的根位置,而这个作用最为显著的是在系统初始引导c盘的处理过程中使用,从初始RAMc盘(initrd)切换系统的根位置并执行真正的init,本文的最后一个demo会详尽的介绍这些用法。

通过chroot运行busybox工具

busybox包含了丰富的工具,我们可以把这种工具放置在一个目录下,之后通过chroot构造出一个mini系统。简单起见我们直接使用docker的busybox镜像打包的文件系统。先在当前目录下创建一个目录rootfs:$mkdirrootfs

之后把busybox镜像中的文件释放到这个目录中:$(dockerexport$(dockercreatebusybox)|tar-Crootfs-xvf-)

通过ls查看rootfs文件夹下的内容:$lsrootfs

linux chroot_linux chroot_linux chroot

万事俱备,让我们开始吧!

执行chroot后的ls$sudochrootrootfs/bin/ls

尽管输出结果与刚刚执行的lsrootfs命令形同,然而此次运行的命令却是rootfs/bin/ls。

运行chroot后的pwd命令$sudochrootrootfs/bin/pwd

哈,pwd命令真把rootfs目录当根目录了!

不带命令执行chroot$sudochrootrootfs

此次出错了,由于找不到/bin/bash。我们晓得busybox中是不包含bash的,而且chroot命令为何会找bash命令呢?原先,假若不给chroot指定执行的命令,默认它会执行'${}-i',而我的系统中${SHELL}为/bin/bash。

既然busybox中没有bash,我们只得指定/bin/sh来执行shell了。$sudochrootrootfs/bin/sh

运行sh是没有问题的,但是我们复印出了当前进程的PID。

检测程序是否运行在chroot环境下

linux chroot_linux chroot_linux chroot

其实我们做了好几个实验,并且肯定会有同学心存疑惑,如何能证明我们运行的命令就是在chroot目录后的路径中呢?

虽然linux chroot,我们可以通过/proc目录下的文件检测进程的中的根目录,例如我们可以通过下边的代码检测里面运行的/bin/sh命令的根目录(请在另外一个shell中执行):$pid=$(pidof-ssh)

$sudols-ld/proc/$pid/root

输出中的内容明晰的强调PID为46644的进程的根目录被映射到了/tmp/rootfs目录。

通过代码理解chroot命令

下边我们尝试自己实现一个chroot程序,代码中涉及到两个函数,分别是chroot()函数和chdir()函数,虽然真正的chroot命令也是通过调用它们实现的:

#include#include#include

intmain(intargc,char*argv[])

{if(argc

printf("Usage:chrootNEWROOT[COMMAND...]n");

return1;

}if(chroot(argv[1])){

perror("chroot");

linux chroot_linux chroot_linux chroot

return1;

if(chdir("/")){

perror("chdir");

return1;

if(argc==2){//hardcode/bin/shformybusyboxtools.

argv[0]=(char*)"/bin/sh";

argv[1]=(char*)"-i";

argv[2]=NULL;

}else{

argv+=2;

execvp(argv[0],argv);

printf("chroot:cannotruncommand`%s`n",*argv);

return0;

把里面的代码保存到文件mychroot.c文件中,并执行下边的命令进行编译:$gcc-Wallmychroot.c-omychroot

linux chroot_linux chroot_linux chroot

mychroot的用法和chroot基本相同:$sudo./mychroot./rootfs

非常之处是我们的mychroot在没有传递命令的情况下执行了/bin/sh,缘由其实是为了支持我们的busybox工具集linux apache 虚拟主机,笔者在代码中hardcode了默认的shell:argv[0]=(char*)"/bin/sh";

从代码中我们也可以见到,实现chroot命令的核心逻辑虽然并不复杂。

实例:通过chroot重新设置root密码

忘掉了root密码该如何办?接出来的demo将演示怎么通过chroot命令重新设置centos7中被忘掉了的root密码。

systemd的管理机制中,rescure模式和emeryency模式是难以直接取得root权限的,须要使用root密码能够步入rescure和emeryency环境。所以我们须要通过其他方法来设置root密码。我们可以为内核的启动指定"rd.break"参数,进而让系统在启动的初期停出来,此时我们可以通过使用root权限并结合chroot命令完成设置root密码的操作。下边我们一上去看具体的操作过程。

在系统启动过程中步入开机菜单时按下字母键e进程开机菜单的编辑模式:

这就是系统的开机菜单,按下e后步入编辑界面:

找到以"linux16/vmlinuz-"开头的行。假如默认没有看见该行,须要按向上键把它滚动下来。

之后定位到该行结尾处,输入一个空格和字符串"rd.break",如右图所示:

linux chroot_linux chroot_linux chroot

接着按下ctrl+x以该设置继续启动,启动过程中操作系统会停出来linux chroot,这是系统启动过程中的一个特别早的时间点:

所以系统的根目录还挂载在RAMdisk上(就是显存中的一个文件系统),我们可以通过mount命令检测系统当前挂载的文件系统,下边是我们比较关心的两条:

上图中mount命令输出的第一行说明此时的根目录在一个RAMdisk中,即rootfs。

图中输出的第二行说明我们的文件系统此时被挂载到了/sysroot目录,但是是只读的模式:/dev/mapper/centos-rooton/sysroottypexfs(ro,relatime,attr2,inode64,noquota)

而在我们正常登录系统的情况下,系统根目录的挂载情况如下:/dev/mapper/centos-rooton/typexfs(rw,relatime,seclabel,attr2,inode64,noquota)

该时间点的最大优势是我们具有root权限!所以让我们开始设置新的root密码吧。

先通过下边的命令把/sysroot重新挂载为可读写的模式:switch_root:/#mount-oremount,rw/sysroot

之后用下边chroot命令把根目录切换到我们原先的环境中:switch_root:/#chroot/sysroot

此时可以理解为:我们以root权限登入了原先的系统,更改密码就很容易了!用下边的命令为root用户设置新的密码:sh-4.2#echo"new_root_pw"|passwd--stdinroot

接出来还要处理SELinux相关的问题。因为当前的环境中SELinux并未启动,所以我们对文件的更改可能导致文件的context不正确。为了确保开机时重新设定SELinuxcontext,必須在根目录下添加隐藏文件.autorelabel:sh-4.2#touch/.autorelabel

最后从chroot中退出,并重启系统:sh-4.2#exit

switch_root:/#reboot

重新步入登录界面时就可以使用刚刚设置的密码以root登录了!

总结

chroot是一个很有意思的命令,我们可以用它来简单的实现文件系统的隔离。但在一个容器技术繁荣的时代,用chroot来进行资源的隔离实在是low了点。所以chroot的主要用途还是集中在系统搜救、维护等一些特殊的场景中。

本文原创地址://lrxjmw.cn/lxtmrdgmljgh.html编辑:刘遄,审核员:暂无