Change Your Root: Chroot Basics
Table of contents
Start tutorial
Reset Progress<br>Are you sure you want to reset your progress for this tutorial? This action cannot be undone.<br>Cancel<br>Reset
close
Tutorial on Linux, Containers<br>Discussion Discord<br>#chroot#isolation#filesystem#rootfs
This tutorial was created by a community author. Community content is reviewed by the iximiuz Labs team on a best effort basis.
Tutorial on Linux, Containers Published: Aug 9, 2026
close<br>Change Your Root: Chroot Basics
by Başar Subaşı
Understand how the chroot system call changes the root directory for a process, learn how dynamic linkers resolve dependencies inside a jail, and see what an isolated process perceives as its filesystem root.
When you work with containers in Docker, Podman, or Kubernetes, one of the most visible isolation features is that each container has its own private filesystem. The container cannot see the host's /etc, /var, or /home directories unless you explicitly mount them.<br>Important<br>Note: chroot is not used in modern container runtimes<br>Modern container runtimes (such as containerd, or CRI-O) do not use chroot. Instead, they rely on Mount Namespaces (CLONE_NEWNS) along with pivot_root to isolate and swap process root filesystems securely without leaving access to the underlying host root.<br>To learn how modern container filesystems are constructed using mount namespaces and layered images, Ivan's Container Filesystem from Scratch tutorial is a gem.
Long before Linux containers, namespaces, or cgroups existed, Unix introduced a foundational mechanism for filesystem isolation in 1979: chroot (change root).<br>In this tutorial, you will explore how chroot works under the hood, how the Linux kernel manages root directory pointers for processes, and how to create an isolated root environment.<br>Step 1: What is chroot?<br>Every process in Linux is represented in kernel space by a task_struct. Inside this structure, the kernel maintains a pointer to filesystem context (struct fs_struct), which includes two crucial directory pointers:<br>Current Working Directory (pwd): The starting point for relative paths (e.g. foo/bar.txt).<br>Root Directory (root): The starting point for absolute paths (e.g. /etc/passwd).<br>When a process starts, it inherits its root directory pointer from its parent process (typically the system root /).<br>The chroot(const char *path) system call instructs the kernel to change the calling process's root directory pointer to a new location. From that moment on, whenever the process or any of its child processes resolves an absolute path starting with /, the kernel translates / to the new directory.
Step 2: (Try to) Change Your Root<br>Let's test what happens when you create an empty directory and attempt to chroot into it.<br>Create an empty directory:<br>mkdir -p /tmp/newroot<br>Copy to clipboard<br>Now try running a shell inside /tmp/newroot:<br>sudo chroot /tmp/newroot /bin/sh<br>Copy to clipboard<br>You will receive an error:<br>chroot: failed to run command '/bin/sh': No such file or directory<br>Copy to clipboard<br>Why did this fail when /bin/sh clearly exists on your Ubuntu system?<br>Because the path /bin/sh is evaluated after the root directory is changed to /tmp/newroot. The kernel looked for /tmp/newroot/bin/sh, which does not exist.<br>Step 3: Setting Up a Root Filesystem<br>To run programs inside /tmp/newroot, the directory must contain a valid root filesystem with its own binaries and shared libraries.<br>Instead of manually copying individual files and libraries, you can export a lightweight container root filesystem (such as Alpine Linux) in a single command using crane:<br>mkdir -p /tmp/newroot<br>crane export alpine:latest - | tar -xf - -C /tmp/newroot<br>Copy to clipboard<br>This unpacks a complete rootfs into /tmp/newroot, containing its own /bin, /lib, /etc, and standard utilities.<br>Step 4: Stepping Inside the chroot<br>Now enter the isolated root environment:<br>sudo chroot /tmp/newroot /bin/sh<br>Copy to clipboard<br>Notice what happens:<br>Check your current directory: pwd<br>Copy to clipboard
The output is /.<br>List root directory contents: ls /<br>Copy to clipboard
You only see the directories inside /tmp/newroot. The host's /home, /var, and /etc are completely invisible to this process.<br>Check the OS release: cat /etc/os-release<br>Copy to clipboard
Even though the host OS is Ubuntu, the chrooted shell reports Alpine Linux because it reads /etc/os-release from the new root!<br>Try navigating above root: cd ..<br>pwd<br>Copy to clipboard
The output remains /. The kernel prevents directory traversal past the process's assigned root.<br>Type exit to return to your host shell:<br>exit<br>Copy to clipboard<br>Step 5: Why chroot is Not a Container<br>While chroot provides filesystem confinement, it does not provide complete process isolation:<br>Shared Kernel Subsystems: Processes inside a chroot jail still share the same PID table, network stack, IPC mechanisms, and user table with the host.<br>Escape Vulnerabilities: A process running as root (UID 0) inside a traditional chroot jail...