linuxchroot命令详解
chroot,即 change root directory (更改 root ⽬录)。在 linux 系统中,系统默认的⽬录结构都是以 /,即以根 (root) 开始的。⽽在使⽤ chroot 之后,系统的⽬录结构将以指定的位置作为 / 位置。
基本语法
chroot NEWROOT [COMMAND [ARG]...]
具体⽤法请参考本⽂的 demo。
为什么要使⽤ chroot 命令
增加了系统的安全性,限制了⽤户的权⼒:
在经过 chroot 之后,在新根下将访问不到旧系统的根⽬录结构和⽂件,这样就增强了系统的安全性。⼀般会在⽤户登录前应⽤ chroot,把⽤户的访问能⼒控制在⼀定的范围之内。
建⽴⼀个与原系统隔离的系统⽬录结构,⽅便⽤户的开发:
使⽤ chroot 后,系统读取的是新根下的⽬录和⽂件,这是⼀个与原系统根下⽂件不相关的⽬录结构。在这
个新的环境中,可以⽤来测试软件的静态编译以及⼀些与系统不相关的独⽴开发。
切换系统的根⽬录位置,引导 Linux 系统启动以及急救系统等:
chroot 的作⽤就是切换系统的根位置,⽽这个作⽤最为明显的是在系统初始引导磁盘的处理过程中使⽤,从初始 RAM 磁盘(initrd) 切换系统的根位置并执⾏真正的 init,本⽂的最后⼀个 demo 会详细的介绍这种⽤法。
通过 chroot 运⾏ busybox ⼯具
busybox 包含了丰富的⼯具,我们可以把这些⼯具放置在⼀个⽬录下,然后通过 chroot 构造出⼀个 mini 系统。简单起见我们直接使⽤ docker 的 busybox 镜像打包的⽂件系统。先在当前⽬录下创建⼀个⽬录 rootfs:
$ mkdir rootfs
然后把 busybox 镜像中的⽂件释放到这个⽬录中:
$ (docker export $(docker create busybox) | tar -C rootfs -xvf -)
通过 ls 命令查看 rootfs ⽂件夹下的内容:
$ ls rootfs
万事俱备,让我们开始吧!
执⾏ chroot 后的 ls 命令
$ sudo chroot rootfs /bin/ls
虽然输出结果与刚才执⾏的 ls rootfs 命令形同,但是这次运⾏的命令却是 rootfs/bin/ls。
运⾏ chroot 后的 pwd 命令
$ sudo chroot rootfs /bin/pwd
哈,pwd 命令真把 rootfs ⽬录当根⽬录了!
不带命令执⾏ chroot
$ sudo chroot rootfs
这次出错了,因为不到 /bin/bash。我们知道 busybox 中是不包含 bash 的,但是 chroot 命令为什么会 bash 命令呢?原来,如果不给 chroot 指定执⾏的命令,默认它会执⾏ '${SHELL} -i',⽽我的系统中 ${SHELL} 为 /bin/bash。
既然 busybox 中没有 bash,我们只好指定 /bin/sh 来执⾏ shell 了。
$ sudo chroot rootfs /bin/sh
运⾏ sh 是没有问题的,并且我们打印出了当前进程的 PID。
检查程序是否运⾏在 chroot 环境下
虽然我们做了好⼏个实验,但是肯定会有朋友⼼存疑问,怎么能证明我们运⾏的命令就是在 chroot ⽬录后的路径中呢?
其实,我们可以通过 /proc ⽬录下的⽂件检查进程的中的根⽬录,⽐如我们可以通过下⾯的代码检查上⾯运⾏的 /bin/sh 命令的根⽬录(请在另外⼀个 shell 中执⾏):printf输出格式linux
$ pid=$(pidof -s sh)
$ sudo ls -ld /proc/$pid/root
输出中的内容明确的指出 PID 为 46644 的进程的根⽬录被映射到了 /tmp/rootfs ⽬录。
通过代码理解 chroot 命令
下⾯我们尝试⾃⼰实现⼀个 chroot 程序,代码中涉及到两个函数,分别是 chroot() 函数和 chdir() 函数,其实真正的 chroot 命令也是通过调⽤它们实现的:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
if(argc<2){
printf("Usage: chroot NEWROOT [] \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;
}
把上⾯的代码保存到⽂件 mychroot.c ⽂件中,并执⾏下⾯的命令进⾏编译:
$ gcc -Wall mychroot.c -o mychroot
mychroot 的⽤法和 chroot 基本相同:
$ sudo ./mychroot ./rootfs
特别之处是我们的 mychroot 在没有传递命令的情况下执⾏了 /bin/sh,原因当然是为了⽀持我们的 busybox ⼯具集,笔者在代码中 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",如下图所⽰:
接着按下 ctrl + x 以该设置继续启动,启动过程中操作系统会停下来,这是系统启动过程中的⼀个⾮常早的时间点:
所以系统的根⽬录还挂载在 RAM disk 上(就是内存中的⼀个⽂件系统),我们可以通过 mount 命令检查系统当前挂载的⽂件系统,下⾯是我们⽐较关⼼的两条:
上图中 mount 命令输出的第⼀⾏说明此时的根⽬录在⼀个 RAM disk 中, 即 rootfs。
图中输出的第⼆⾏说明我们的⽂件系统此时被挂载到了 /sysroot ⽬录,并且是只读的模式:
复制代码代码如下:
/dev/mapper/centos-root on /sysroot type xfs (ro,relatime,attr2,inode64,noquota)
⽽在我们正常登陆系统的情况下,系统根⽬录的挂载情况如下:
复制代码代码如下:
/dev/mapper/centos-root on / type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
该时间点的最⼤优势是我们具有 root 权限!所以让我们开始设置新的 root 密码吧。
先通过下⾯的命令把 /sysroot 重新挂载为可读写的模式:
switch_root:/# mount -o remount,rw /sysroot
然后⽤下⾯ chroot 命令把根⽬录切换到我们原来的环境中:
switch_root:/# chroot /sysroot
此时可以理解为:我们以 root 权限登录了原来的系统,修改密码就很容易了!⽤下⾯的命令为 root ⽤户设置新的密码:
sh-4.2# echo "new_root_pw" | passwd --stdin root
接下来还要处理 SELinux 相关的问题。由于当前的环境中 SELinux 并未启动,所以我们对⽂件的修改可能造成⽂件的context 不正确。为了确保开机时重新设定 SELinux context,必須在根⽬录下添加隐藏⽂件 .autorelabel:
sh-4.2# touch /.autorelabel
最后从 chroot 中退出,并重启系统:
sh-4.2# exit
switch_root:/# reboot
重新进⼊登陆界⾯时就可以使⽤刚才设置的密码以 root 登陆了!
总结
chroot 是⼀个很有意思的命令,我们可以⽤它来简单的实现⽂件系统的隔离。但在⼀个容器技术繁荣的时代,⽤ chroot 来进⾏资源的隔离实在是 low 了点。所以 chroot 的主要⽤途还是集中在系统救援、维护等⼀些特殊的场景中。
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。