| xchpst(8) | System Manager's Manual | xchpst(8) |
xchpst — eXtended
CHange Process STate
xchpst |
--help |
xchpst |
--version |
xchpst |
--exit[=retcode] |
xchpst |
[OPTIONS] [--]
command ... |
The xchpst utility changes process state
according to the supplied options and then calls
exec()
on a named executable with the positional arguments.
xchpst is a backwards-compatible extension
to the chpst(8) tool which is supplied with runit.
xchpst enables runit service scripts to take
advantage of hardening capabilities available with recent Linux kernels such
as namespaces and capabilities. xchpst can set up
shadow subtrees within the filesystem hierarchy to isolate long-running
services from parts of the system to which they ought to need no access,
e.g. with private /tmp areas and read-only
/usr.
The extra options provided by xchpst are
as follows:
--help--file
file--exit[=retcode]--mount-ns--net-ns--uts-ns--pid-ns--fork-join
because a new process is needed to act as PID 1 and in order to be able to
mount a new procfs for the namespace.--fork-joinxchpst
process. This option is necessary to take advantage of PID namespaces. The
exit status is that of the child process.--user-ns--adopt-net
path--new-root--private-run--new-root is also specified, the old
shared /run directory will still be accessible if the stacked mount is
removed.--private-tmp--new-root is also specified, the old
shared /tmp directory will still be accessible if the stacked mount is
removed.--protect-home--new-root is also specified, the old
shared host directories will still be accessible if the stacked mounts are
removed.--ro-sys--new-root option is designed to prevent this.
Alternatively, use --cap-bs-drop to remove the
‘CAP_SYS_ADMIN’ capability,
preventing the bind mount from being unmounted.--ro-home--ro-sys.--ro-etc--ro-sys.--caps-bs-keep
capability[,capability...]--caps-bs-drop
capability[,capability...]--caps-keep
capability[,capability...]--caps-drop
capability[,capability...]--no-new-privs--cpu-scheduler
other|batch|idle--io-scheduler
rt|best-effort|idle[:priority]--cpus
start[-end[:stride]][,...]--umask
mode--app
name--run-dir--state-dir--log-dir--cache-dir--login--oom
adjustment-s
bytes-a
bytes--limit-memlock
bytes--limit-msgqueue
bytes--limit-nice
niceness--limit-rtptio
prio--limit-rttime
ms--limit-sigpending
number--limit-locks
number--hardlimit-@xchpst invocation into a command line for
chpst if xchpst is not
present on the system.The options compatible with classic chpst
are as follows:
-u
user[:group]...-U
user[:group]-u but the environment variables
UID and GID are set
instead of changing the user. Supplementary groups are ignored.-b
argv0-e
dir-/
dir-C
dir-n
inc-l
fileexec().-L
file-m
bytes-d
bytes-o
files-p
procs-f
bytes-c
bytes-t
seconds-v-Vxchpst version number.-P-0-1-2The resource limit options above take a parameter in one of the following forms:
chpst and
softlimit, unless
--hardlimit has previously been specified, in
which case both soft and hard limits are defined, in the style of
prlimit.An unlimited limit may be selected by any value of
‘-1’,
‘unlimited’ or
‘infinity’.
When invoked as chpst,
envdir, envuidgid,
pgrphack, setlock,
setuidgid, or softlimit, the
xchpst executable emulates the corresponding tools
from the “runit” or “daemontools” packages
respectively. As an additional feature, all these tools when so invoked,
accept the -v option to increase verbosity.
An options file specifies additional options to apply, one option
per line. Each line begins with an option name. Options that take an
argument have horizontal white space and the option value following the
option name. Comments begin with a ‘#’
character and may only be preceded by whitespace, otherwise they will be
interpreted as part of an option name or value.
Example options file:
# Comment line private-tmp app my app run-dir pid-ns
--exit is specified
is 0. This can be used for a quick test that
xchpst is available on the system in shell scripts
and that the given options are supported.--exit option takes an optional argument with
a return code to use.If there is no error and the intended application is
exec()'d, the exit status will be that of the
application, not xchpst.
The table below divides the process change options between those that abort on failure to effect the requested change (with error code 111) and those that continue execution. Nonsense configuration values always fail with error code 100.
| Option group | Abort on error | Continue on error |
| chpst | u e / C n L l m d s a o p f c r t | U b 0 1 2 |
| rlimit | limit-memlock limit-msgqueue limit-nice limit-rtprio limit-rttime limit-sigpending limit-locks | |
| namespaces | fork-join new-root mount-ns net-ns user-ns pid-ns uts-ns net-adopt | |
| capabilities 1 | cap-bs-keep cap-bs-drop caps-keep caps-drop | |
| filesystem | private-run private-tmp protect-home ro-sys ro-home ro-etc run-dir state-dir cache-dir log-dir | |
| other | cpus cpu-scheduler io-scheduler no-new-privs umask oom login |
The table below shows how some systemd service directives map onto
xchpst options. See
systemd.exec(5) This is not an exhaustive list.
| systemd | xchpst | Differences |
| ProtectSystem=yes | ro-sys | |
| ProtectSystem=full | ro-sys ro-etc | |
| ProtectHome=read-only | ro-home | |
| ProtectHome=tmpfs | protect-home | |
| PrivateTmp=yes | private-tmp | |
| CapabilityBoundingSet= | cap-bs-keep | |
| CapabilityBoundingSet=~ | cap-bs-drop | |
| AmbientCapabilities= | caps-keep | |
| AmbientCapabilities=~ | caps-drop | |
| NoNewPrivileges=yes | no-new-privs | |
| CPUAffinity= | cpus | use taskset 1 format |
| CPUSchedulingPolicy= | cpu-scheduler | |
| -literal -compact IOSchedulingClass= IOSchedulingPriority= | io-scheduler | |
| UMask= | umask | |
| RuntimeDirectory= | run-dir | Leaf name governed by target command or app option |
| StateDirectory= | state-dir | Leaf name governed by target command or app option |
| CacheDirectory= | cache-dir | Leaf name governed by target command or app option |
| LogsDirectory= | log-dir | Leaf name governed by target command or app option |
| OOMScoreAdjust= | oom | |
| -literal -compact User= Group= | u | Check syntax. In particular, numeric ids begin with a colon. |
| User= with ExecStart=+ or ExecStart=! | U | In these modes, systemd does not drop the user, expecting the application to do that, but instead uses the specified username for other options. In this case the environment variable setting by is not useful but other options like run-dir will use the right user. |
The table below shows how xchpst resource
limit options correspond to those of other tools.
| xchpst | chpst | softlimit | prlimit | ulimit | systemd |
| d | d | d | d | d | LimitDATA= |
| o | o | o | n | n | LimitNOFILE= |
| p | p | p | u | u | LimitNPROC= |
| f | f | f | f | f | LimitFSIZE= |
| c | c | c | c | c | LimitCORE= |
| t | t | t | t | t | LimitCPU= |
| r | r | m | m | LimitRSS= | |
| s | s | s | s | LimitSTACK= | |
| a | a | v | v | LimitAS= | |
| m | m | m | d s l v | d s l v | -literal -compact LimitDATA= LimitSTACK= LimitAS= LimitMEMLOCK= |
| limit-memlock | l | l | l | LimitMEMLOCK= | |
| limit-msgqueue | q | q | LimitMSGQUEUE= | ||
| limit-nice | e | e | LimitNICE= | ||
| limit-rtprio | r | r | LimitRTPRIO= | ||
| limit-rttime | y | R | LimitRTTIME= | ||
| limit-sigpending | i | i | LimitSIGPENDING= | ||
| limit-locks | x | x | LimitLOCKS= |
The following options from the bash
ulimit command are not available: b
k p P T.
The --cpu-scheduler option should accept
more scheduling policies and should accept additional parameters to qualify
those policies. Currently unknown policy names are treated as the default
Linux scheduling policy.
When the kernel supports capabilities but not specific
capabilities that have been requested to be dropped or kept,
xchpst should continue rather than aborting.
Testing the emulation of ‘envdir’:
xchpst -b envdir --
xchpstLaunch with read-only filesystem if xchpst
is available, else use chpst:
xchpst --exit && exec xchpst
--ro-sys -l /var/lock/ntpsec-ntpdate ntpd; exec chpst -l
/var/log/ntpsec-ntpdate ntpdDrop a capability from the bounding set:
xchpst --cap-bs-drop CAP_SYS_ADMIN --
acmedDrop user while retaining some capabilities:
xchpst -u :500:500 --caps-keep
CAP_DAC_OVERRIDE fakeroot /usr/sbin/gpm -D -m /dev/input/mice -t
exps2To see what is going on, including options enabled implicitly due
to other options, add the ‘--verbose’
option.
Use ‘--login’ without a
command name to explore the hardened environment from a shell.
You can enter the created namespaces (but not other aspects of hardening), including any synthesised root filesystem, by identifying the process id of the hardened application and running:
nsenter -a -t PIDchpst(8), runit(8), unshare(1), capsh(1), taskset(1), chrt(1), choom(1), proc_pid_oom_score_adj(5), prlimit(1), prlimit(2), namespaces(7), capabilities(7)
Andrew Bower <andrew@bower.uk>
| March 21, 2025 | Debian |