[GNU Manual] [No POSIX requirement] [Linux man] [FreeBSD man]
Summary
chroot - run a command with a different root directory
Lines of code: 431
Principal syscall: chroot() (Linux)
Support syscalls: execvp(), chdir()
Options: 5 (0 short, 5 long)
GNU implementation is possibly the earliest utility -- chroot syscall appeared in Version 7 UNIX (1979)
Added to Shellutils in March 1996 [First version]
Number of revisions: 110 [Code Evolution]
There is no current POSIX interface for chroot, which complicates utility execution across platforms. Here is the legacy POSIX interface
Helpers:is_root()
- Tests if an input path is the same as '/'gid_set()
- Tests ifgid
has a nontrivial valuegid_unset()
- Tests ifgid
is -1parse_additional_groups()
- Parses comma separated groups in to a gid arrayset_groups()
- Simulates setgroups() syscall with success/fail conditionsuid_set()
- Tests ifuid
has a nontrivial valueuid_unset()
- Tests ifuid
is -1
die()
- Exit with mandatory non-zero error and message to stderrerror()
- Outputs error message to standard error with possible process terminationignore_value()
- Prevents warning from GCCwarn_unused_result
attributeparse_user_spec()
- Breaks a user:group in to components
Setup
The bulk of chroot executes within main(). The function begins by initializing nine locals:
c
- The current command line option letter we're parsinggid
- The group ID parsed fromuserspec
groups
- Group list input from the--groups
optionn_gids
- The number of gid entriesout_gids
- The resulting gids parsed fromgroups
skip_chdir
- Flag to skip changing working directoryuid
- user ID parsed fromuserspec
username
- The user name pulled from the user fileuserspec
- The user:group input from the--userspec
option
Parsing
Parsing collects options and a target path which considers the following questions:
- Should the new process use a specific group?
- Should the new process run under different credentials?
- Should the working directory change?
Parsing failures
These failure cases are explicitly checked:
- No new path to change root
- Trying to skip changing directory if the newroot isn't root
User specified parsing failures result in a short error message followed by the usage instructions. Access related parsing errors die with an error message.
Execution
chroot
execution follows a fairly linear process:
- Set input users and groups as specified
- Perform
chroot()
to the new location - Change working directory to the new root
- Update all users and groups to the new settings (with supplemental groups)
- Execute the desired command in the new root environment (default to new shell)
Since execvp()
doesn't return any further execution in chroot implies a failure
Failure cases:
- Can't change root (
chroot()
fails) - Can't change working directory (
chdir()
fails) - Unknown group provided
- Can't change group ID
- Can't change user ID
execvp
failed for any reason
Failures output an error message to STDERR and return without displaying usage help