├── pkg ├── rpm │ ├── BUILD │ ├── RPMS │ ├── SRPMS │ └── SPECS │ │ └── enroot.spec ├── deb │ ├── source │ │ ├── format │ │ └── lintian-overrides │ ├── lintian-overrides │ ├── PACKAGE+caps.postinst │ ├── PACKAGE+caps.prerm │ ├── rules │ ├── control │ ├── changelog │ └── copyright ├── release │ ├── run-build.sh │ ├── docker-run-build.sh │ ├── deb-build.sh │ ├── rpm-build.sh │ ├── docker-release-build.sh │ ├── Dockerfile.ubuntu │ └── Dockerfile.almalinux ├── rpmbuild ├── runbuild └── debbuild ├── conf ├── environ │ └── 10-terminal.env ├── apparmor.profile ├── enroot.conf.d │ └── README ├── mounts │ ├── 20-config.fstab │ ├── 10-system.fstab │ └── extra │ │ └── 30-lxcfs.fstab ├── hooks │ ├── 10-aptfix.sh │ ├── 10-localtime.sh │ ├── 10-home.sh │ ├── 10-cgroups.sh │ ├── extra │ │ ├── 50-mig-config.sh │ │ ├── 50-slurm-pytorch.sh │ │ ├── 50-sharp.sh │ │ └── 50-slurm-pmi.sh │ ├── 10-devices.sh │ ├── 98-nvidia.sh │ ├── 10-shadow.sh │ └── 99-mellanox.sh ├── bash_completion └── enroot.conf.in ├── .lgtm.yml ├── .gitignore ├── doc ├── cmd │ ├── version.md │ ├── remove.md │ ├── exec.md │ ├── list.md │ ├── create.md │ ├── export.md │ ├── batch.md │ ├── bundle.md │ ├── import.md │ └── start.md ├── image-format.md ├── usage.md ├── requirements.md ├── standard-hooks.md ├── configuration.md └── installation.md ├── SECURITY.md ├── .gitmodules ├── deps ├── musl.patch ├── libbsd │ ├── include │ │ └── bsd │ │ │ ├── inttypes.h │ │ │ ├── unistd.h │ │ │ ├── libutil.h │ │ │ ├── stdlib.h │ │ │ └── sys │ │ │ └── cdefs.h │ └── src │ │ ├── strtonum.c │ │ ├── strtoi.c │ │ ├── strtou.c │ │ ├── fparseln.c │ │ └── closefrom.c └── Makefile ├── CONTRIBUTING.md ├── README.md ├── bin ├── compat.h ├── enroot-mksquashovlfs.c ├── common.h ├── enroot-aufs2ovlfs.c └── enroot-nsenter.c ├── Makefile ├── src └── common.sh └── LICENSE /pkg/rpm/BUILD: -------------------------------------------------------------------------------- 1 | ../.. -------------------------------------------------------------------------------- /pkg/rpm/RPMS: -------------------------------------------------------------------------------- 1 | ../../dist -------------------------------------------------------------------------------- /pkg/rpm/SRPMS: -------------------------------------------------------------------------------- 1 | ../../dist -------------------------------------------------------------------------------- /pkg/deb/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /conf/environ/10-terminal.env: -------------------------------------------------------------------------------- 1 | TERM=${TERM} 2 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | path_classifiers: 2 | library: 3 | - deps/**/*.c 4 | -------------------------------------------------------------------------------- /pkg/deb/source/lintian-overrides: -------------------------------------------------------------------------------- 1 | useless-autoreconf-build-depends 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deps/dist 2 | dist/ 3 | conf/enroot.conf 4 | enroot 5 | bin/* 6 | !bin/*.* 7 | -------------------------------------------------------------------------------- /pkg/deb/lintian-overrides: -------------------------------------------------------------------------------- 1 | binary-without-manpage 2 | new-package-should-close-itp-bug 3 | -------------------------------------------------------------------------------- /conf/apparmor.profile: -------------------------------------------------------------------------------- 1 | abi , 2 | include 3 | 4 | /usr/bin/enroot-nsenter flags=(unconfined) { 5 | allow userns create, 6 | include if exists 7 | } 8 | -------------------------------------------------------------------------------- /doc/cmd/version.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | `Usage: enroot version` 4 | 5 | # Description 6 | 7 | Print the release version of Enroot. 8 | 9 | # Example 10 | 11 | ```sh 12 | $ enroot version 13 | 4.0.1 14 | ``` 15 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | When reporting a security issue, do not create an issue or file a pull request. 6 | Instead, disclose the issue responsibly by sending an email to `psirtnvidia.com`. 7 | -------------------------------------------------------------------------------- /pkg/release/run-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | OUTPUT_DIR="${1:-/output/}" 4 | mkdir -p "${OUTPUT_DIR}" 5 | 6 | set -x 7 | 8 | make deb PACKAGE=enroot-hardened 9 | apt-get install -y ./dist/enroot*.deb 10 | 11 | ./pkg/runbuild 12 | 13 | cp -v dist/*.run "${OUTPUT_DIR}/" 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/makeself"] 2 | path = deps/makeself 3 | url = https://github.com/megastep/makeself.git 4 | [submodule "deps/musl"] 5 | path = deps/musl 6 | url = git://git.musl-libc.org/musl 7 | [submodule "deps/linux-headers"] 8 | path = deps/linux-headers 9 | url = https://github.com/sabotage-linux/kernel-headers.git 10 | -------------------------------------------------------------------------------- /conf/enroot.conf.d/README: -------------------------------------------------------------------------------- 1 | # Drop-ins for enroot.conf 2 | # 3 | # All files in this directory named *.conf are read in shell expansion order 4 | # (ie, asciicographical, possibly influenced by LC_COLLATE) 5 | # 6 | # Any file to be processed must adhere to the same format as enroot.conf. 7 | # See there for details. 8 | # 9 | # If necessary, a numbering scheme (10-default.conf, 20-local.conf, 30-....conf) 10 | # might be beneficial. 11 | # 12 | # EOF 13 | -------------------------------------------------------------------------------- /conf/mounts/20-config.fstab: -------------------------------------------------------------------------------- 1 | /etc/hosts /etc/hosts none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 2 | /etc/hostname /etc/hostname none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 3 | /etc/resolv.conf /etc/resolv.conf none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 4 | /etc/machine-id /etc/machine-id none x-create=file,bind,ro,nosuid,nodev,noexec,private,nofail,silent 0 -1 5 | -------------------------------------------------------------------------------- /pkg/deb/PACKAGE+caps.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # postinst script for #PACKAGE# 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | case "$1" in 9 | configure|abort-upgrade|abort-remove|abort-deconfigure) 10 | setcap cap_sys_admin+pe "$(command -v enroot-mksquashovlfs)" 11 | setcap cap_sys_admin,cap_mknod+pe "$(command -v enroot-aufs2ovlfs)" 12 | ;; 13 | 14 | *) 15 | echo "postinst called with unknown argument \`$1'" >&2 16 | exit 1 17 | ;; 18 | esac 19 | 20 | #DEBHELPER# 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /pkg/deb/PACKAGE+caps.prerm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # prerm script for #PACKAGE# 3 | # 4 | # see: dh_installdeb(1) 5 | 6 | set -e 7 | 8 | case "$1" in 9 | remove|upgrade|deconfigure) 10 | setcap cap_sys_admin-pe "$(command -v enroot-mksquashovlfs)" 11 | setcap cap_sys_admin,cap_mknod-pe "$(command -v enroot-aufs2ovlfs)" 12 | ;; 13 | 14 | failed-upgrade) 15 | ;; 16 | 17 | *) 18 | echo "prerm called with unknown argument \`$1'" >&2 19 | exit 1 20 | ;; 21 | esac 22 | 23 | #DEBHELPER# 24 | 25 | exit 0 26 | -------------------------------------------------------------------------------- /conf/mounts/10-system.fstab: -------------------------------------------------------------------------------- 1 | /proc /proc none x-create=dir,rbind,rw,nosuid,nodev,noexec,rslave 0 -1 2 | /sys /sys none x-create=dir,rbind,ro,nosuid,nodev,noexec,rslave 0 -1 3 | /dev /dev none x-create=dir,rbind,rw,nosuid,noexec,rslave 0 -1 4 | tmpfs /tmp tmpfs x-create=dir,rw,nosuid,nodev,mode=755,slave 0 -1 5 | tmpfs /var/run tmpfs x-create=dir,rw,nosuid,nodev,mode=755,slave 0 -1 6 | tmpfs /var/lock tmpfs x-create=dir,rw,nosuid,nodev,mode=755,slave 0 -1 7 | /dev/shm /dev/shm none x-create=dir,bind,rw,nosuid,nodev,noexec,rslave 0 -1 8 | -------------------------------------------------------------------------------- /doc/cmd/remove.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot remove [options] [--] NAME... 4 | 5 | Delete one or multiple container root filesystems. 6 | 7 | Options: 8 | -f, --force Do not prompt for confirmation 9 | ``` 10 | 11 | # Description 12 | 13 | Remove one or multiple containers, deleting their root filesystem from disk. 14 | 15 | # Configuration 16 | 17 | | Setting | Default | Description | 18 | | ------ | ------ | ------ | 19 | | `ENROOT_FORCE_OVERRIDE` | `no` | Remove container root filesystems without prompting for confirmation (same as `--force`) | 20 | 21 | # Example 22 | 23 | ```sh 24 | # Force remove all the containers from the system 25 | $ enroot remove --force $(enroot list) 26 | ``` 27 | -------------------------------------------------------------------------------- /doc/cmd/exec.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot exec [options] [--] PID COMMAND [ARG...] 4 | 5 | Execute a command inside an existing container. 6 | 7 | Options: 8 | -e, --env KEY[=VAL] Export an environment variable inside the container 9 | ``` 10 | 11 | # Description 12 | 13 | Execute a command inside an existing container referred to by a proccess identifier. 14 | The process identifier of a container can be obtained using the [list](list.md) command. 15 | 16 | # Example 17 | 18 | ```bash 19 | # Start an alpine container, print its process identifier and sleep forever. 20 | $ enroot start alpine sh -c 'echo $$; sleep infinity' 21 | 12019 22 | 23 | # Execute bash inside the running container. 24 | $ enroot exec 12019 bash 25 | -------------------------------------------------------------------------------- /pkg/rpmbuild: -------------------------------------------------------------------------------- 1 | #! /usr/bin/enroot batch 2 | #ENROOT_REMAP_ROOT=y 3 | #ENROOT_ROOTFS_WRITABLE=y 4 | #ENROOT_ROOTFS=${ENROOT_ROOTFS:-centos.sqsh} 5 | 6 | mounts() { 7 | echo "$(dirname $0)/.. /usr/local/src/enroot" 8 | } 9 | 10 | environ() { 11 | echo "LC_ALL=C" 12 | } 13 | 14 | rc() { 15 | dnf install -y epel-release 16 | 17 | dnf install -y \ 18 | libtool \ 19 | gcc \ 20 | make \ 21 | rpm-build \ 22 | rpmlint \ 23 | libmd-devel 24 | 25 | cd /usr/local/src/enroot 26 | 27 | if [ "$1" = "--hardened" ]; then 28 | make rpm PACKAGE=enroot-hardened 29 | else 30 | CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make rpm 31 | fi 32 | } 33 | -------------------------------------------------------------------------------- /pkg/release/docker-run-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | readonly project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" 4 | readonly output_dir="${project_dir}/dist" 5 | readonly arch=${ARCH:-$(uname -m)} 6 | 7 | echo "Building enroot-check.run to: ${output_dir}" 8 | echo "Architecture: ${arch}" 9 | 10 | set -x 11 | 12 | mkdir -p "${output_dir}" 13 | 14 | docker build --platform "linux/${arch}" \ 15 | -f "${project_dir}/pkg/release/Dockerfile.ubuntu" \ 16 | -t "enroot-build-ubuntu:${arch}" "${project_dir}" 17 | 18 | docker run --rm \ 19 | --platform "linux/${arch}" \ 20 | --cap-add SYS_ADMIN --security-opt apparmor=unconfined \ 21 | -v "${output_dir}:/output" \ 22 | "enroot-build-ubuntu:${arch}" run-build.sh 23 | -------------------------------------------------------------------------------- /pkg/runbuild: -------------------------------------------------------------------------------- 1 | #! /bin/bash -eu 2 | 3 | readonly workdir=$(readlink -f $(dirname $0)) 4 | readonly version=$(enroot version) 5 | readonly arch=${ARCH:-$(uname -m)} 6 | readonly tmpdir=$(mktemp -d) 7 | 8 | trap 'rm -rf "${tmpdir}"' EXIT 9 | cd ${tmpdir} 10 | 11 | export ENROOT_DATA_PATH="${PWD}" 12 | export ENROOT_CACHE_PATH="${PWD}" 13 | export ENROOT_SQUASH_OPTIONS="-comp gzip" 14 | 15 | enroot import --arch "${arch}" -o busybox.sqsh docker://busybox:musl 16 | enroot create busybox.sqsh 17 | 18 | cat > ${ENROOT_DATA_PATH}/busybox/etc/rc << EOF 19 | printf "Bundle ran successfully!\n" 20 | EOF 21 | 22 | enroot export -o enroot-check_${version}_${arch}.sqsh busybox 23 | enroot bundle -c -d "enroot-check v${version}" enroot-check_${version}_${arch}.sqsh 24 | 25 | mkdir -p ${workdir}/../dist && mv *.run $_ 26 | -------------------------------------------------------------------------------- /doc/cmd/list.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot list [options] 4 | 5 | List all the container root filesystems on the system. 6 | 7 | Options: 8 | -f, --fancy Display more information in tabular format 9 | ``` 10 | 11 | # Description 12 | 13 | List all the containers on the system and additional information like their size on disk and the processes started. 14 | 15 | # Example 16 | 17 | ```sh 18 | $ enroot list --fancy 19 | NAME SIZE PID STATE STARTED TIME MNTNS USERNS COMMAND 20 | alpine 5.9M 21 | busybox 1.3M 22 | centos 235M 24353 S+ 05:39:23 06:54 4026533442 4026533441 -sh 23 | 24522 S+ 05:39:31 06:46 4026533439 4026533438 -sh 24 | ubuntu 70M 24733 S+ 05:39:48 06:29 4026533445 4026533444 sleep infinity 25 | ``` 26 | -------------------------------------------------------------------------------- /pkg/release/deb-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | OUTPUT_DIR="${1:-/output/}" 4 | mkdir -p "${OUTPUT_DIR}" 5 | 6 | set -x 7 | 8 | # enroot package 9 | CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make deb 10 | cp -v dist/enroot*.deb "${OUTPUT_DIR}/" 11 | 12 | # hardened enroot package 13 | make deb PACKAGE=enroot-hardened 14 | cp -v dist/enroot*.deb "${OUTPUT_DIR}/" 15 | 16 | # Cross-compile only from x86_64 17 | if [ "$(uname -m)" = "x86_64" ]; then 18 | # aarch64 enroot package 19 | ARCH=aarch64 CC=aarch64-linux-gnu-gcc-13 CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make deb 20 | cp -v dist/enroot*.deb "${OUTPUT_DIR}/" 21 | 22 | # aarch64 hardened enroot package 23 | ARCH=aarch64 CC=aarch64-linux-gnu-gcc-13 make deb PACKAGE=enroot-hardened 24 | cp -v dist/enroot*.deb "${OUTPUT_DIR}/" 25 | fi 26 | -------------------------------------------------------------------------------- /pkg/release/rpm-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | OUTPUT_DIR="${1:-/output/}" 4 | mkdir -p "${OUTPUT_DIR}" 5 | 6 | set -x 7 | 8 | # enroot package 9 | CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make rpm 10 | cp -v dist/$(uname -m)/enroot*.rpm "${OUTPUT_DIR}/" 11 | 12 | # hardened enroot package 13 | make rpm PACKAGE=enroot-hardened 14 | cp -v dist/$(uname -m)/enroot*.rpm "${OUTPUT_DIR}/" 15 | 16 | # Cross-compile only from x86_64 17 | if [ "$(uname -m)" = "x86_64" ]; then 18 | # aarch64 enroot package 19 | ARCH=aarch64 CC=aarch64-none-linux-gnu-gcc CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make rpm 20 | cp -v dist/aarch64/enroot*.rpm "${OUTPUT_DIR}/" 21 | 22 | # aarch64 hardened enroot package 23 | ARCH=aarch64 CC=aarch64-none-linux-gnu-gcc make rpm PACKAGE=enroot-hardened 24 | cp -v dist/aarch64/enroot*.rpm "${OUTPUT_DIR}/" 25 | fi 26 | -------------------------------------------------------------------------------- /conf/mounts/extra/30-lxcfs.fstab: -------------------------------------------------------------------------------- 1 | /var/lib/lxcfs/proc/cpuinfo /proc/cpuinfo none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 2 | /var/lib/lxcfs/proc/diskstats /proc/diskstats none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 3 | /var/lib/lxcfs/proc/meminfo /proc/meminfo none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 4 | /var/lib/lxcfs/proc/stat /proc/stat none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 5 | /var/lib/lxcfs/proc/swaps /proc/swaps none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 6 | /var/lib/lxcfs/sys/devices/system/cpu/online /sys/devices/system/cpu/online none x-create=file,bind,ro,nosuid,nodev,noexec,private 0 -1 7 | -------------------------------------------------------------------------------- /conf/hooks/10-aptfix.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | if [ ! -f "${ENROOT_ROOTFS}/etc/debian_version" ]; then 20 | exit 0 21 | fi 22 | 23 | if [ -n "${ENROOT_REMAP_ROOT-}" ]; then 24 | mkdir -p "${ENROOT_ROOTFS}/etc/apt/apt.conf.d" 25 | printf 'APT::Sandbox::User "root";\n' > "${ENROOT_ROOTFS}/etc/apt/apt.conf.d/enroot" 26 | fi 27 | -------------------------------------------------------------------------------- /pkg/release/docker-release-build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -eu 2 | 3 | readonly project_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" 4 | readonly output_dir="${project_dir}/dist" 5 | readonly arch=${ARCH:-$(uname -m)} 6 | 7 | echo "Building deb/rpm packages to: ${output_dir}" 8 | echo "Architecture: ${arch}" 9 | 10 | mkdir -p "${output_dir}" 11 | 12 | set -x 13 | 14 | docker build --platform "linux/${arch}" \ 15 | -f "${project_dir}/pkg/release/Dockerfile.ubuntu" \ 16 | -t "enroot-build-ubuntu:${arch}" "${project_dir}" 17 | 18 | docker run --rm \ 19 | --platform "linux/${arch}" \ 20 | -v "${output_dir}:/output" \ 21 | "enroot-build-ubuntu:${arch}" 22 | 23 | docker build \ 24 | --platform "linux/${arch}" \ 25 | -f "${project_dir}/pkg/release/Dockerfile.almalinux" \ 26 | -t "enroot-build-almalinux:${arch}" "${project_dir}" 27 | 28 | docker run --rm \ 29 | --platform "linux/${arch}" \ 30 | -v "${output_dir}:/output" \ 31 | "enroot-build-almalinux:${arch}" 32 | -------------------------------------------------------------------------------- /doc/cmd/create.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ``` 4 | Usage: enroot create [options] [--] IMAGE 5 | 6 | Create a container root filesystem from a container image. 7 | 8 | Options: 9 | -n, --name Name of the container (defaults to "IMAGE") 10 | -f, --force Overwrite an existing root filesystem 11 | ``` 12 | 13 | # Description 14 | 15 | Take a container image and unpack its root filesystem under `$ENROOT_DATA_PATH/`. 16 | The resulting root filesystem can be started with the [start](start.md) command or removed with the [remove](remove.md) command. 17 | 18 | # Configuration 19 | 20 | | Setting | Default | Description | 21 | | ------ | ------ | ------ | 22 | | `ENROOT_MAX_PROCESSORS` | `$(nproc)` | Maximum number of processors to use for parallel tasks (0 means unlimited) | 23 | | `ENROOT_FORCE_OVERRIDE` | `no` | Overwrite the root filesystem if it already exists (same as `--force`) | 24 | 25 | # Example 26 | 27 | ```sh 28 | # Import Ubuntu 18.04 from DockerHub and create a container out of it 29 | $ enroot import docker://ubuntu:18.04 30 | $ enroot create --name ubuntu ubuntu+18.04.sqsh 31 | ``` 32 | -------------------------------------------------------------------------------- /conf/hooks/10-localtime.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | if [ ! -L /etc/localtime ] ; then 20 | exit 0 21 | fi 22 | 23 | source "${ENROOT_LIBRARY_PATH}/common.sh" 24 | 25 | cp --no-dereference --preserve=links /etc/localtime "${ENROOT_ROOTFS}/etc/localtime" 26 | target="$(common::realpath /etc/localtime)" 27 | if [ ! -e "${ENROOT_ROOTFS}${target}" ] ; then 28 | mkdir --parents "${ENROOT_ROOTFS}$(dirname "${target}")" 29 | cp "${target}" "${ENROOT_ROOTFS}${target}" 30 | fi 31 | -------------------------------------------------------------------------------- /deps/musl.patch: -------------------------------------------------------------------------------- 1 | From 070bce8f7e508a951d3b65da227b2fca3a65f37b Mon Sep 17 00:00:00 2001 2 | From: Ferdinand Bachmann 3 | Date: Tue, 28 May 2019 21:53:25 +0200 4 | Subject: [PATCH] fix musl-gcc.specs.sh to correctly handle -static-pie 5 | 6 | --- 7 | tools/musl-gcc.specs.sh | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/tools/musl-gcc.specs.sh b/tools/musl-gcc.specs.sh 11 | index 30492574..7206cb25 100644 12 | --- a/tools/musl-gcc.specs.sh 13 | +++ b/tools/musl-gcc.specs.sh 14 | @@ -17,13 +17,13 @@ cat <> "${ENROOT_MOUNTS}" 33 | printf "HOME=/root\n" >> "${ENROOT_ENVIRON}" 34 | else 35 | printf "%s %s none x-create=dir,bind,rw,nosuid\n" "${HOME}" "${HOME}" >> "${ENROOT_MOUNTS}" 36 | printf "HOME=%s\n" "${HOME}" >> "${ENROOT_ENVIRON}" 37 | fi 38 | -------------------------------------------------------------------------------- /pkg/release/Dockerfile.ubuntu: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 AS base 2 | 3 | # Install build dependencies 4 | RUN apt-get update && apt-get install -y \ 5 | build-essential \ 6 | autotools-dev \ 7 | dh-apparmor \ 8 | devscripts \ 9 | debhelper \ 10 | dh-make \ 11 | git \ 12 | pkg-config \ 13 | libmd-dev \ 14 | curl \ 15 | ca-certificates \ 16 | rename && \ 17 | rm -rf /var/lib/apt/lists/* 18 | 19 | # Install runtime dependencies (to create enroot-check) 20 | RUN apt-get update && apt-get install -y \ 21 | jq \ 22 | parallel \ 23 | squashfs-tools \ 24 | bsdmainutils \ 25 | libcap2-bin && \ 26 | rm -rf /var/lib/apt/lists/* 27 | 28 | 29 | FROM base AS build-amd64 30 | 31 | # Install cross-compilation toolchain for aarch64 32 | RUN apt-get update && apt-get install -y \ 33 | gcc-aarch64-linux-gnu \ 34 | binutils-aarch64-linux-gnu \ 35 | linux-libc-dev-arm64-cross \ 36 | libc6-dev-arm64-cross && \ 37 | rm -rf /var/lib/apt/lists/* 38 | 39 | 40 | FROM base AS build-arm64 41 | 42 | 43 | FROM build-${TARGETARCH} 44 | WORKDIR /usr/local/src/enroot 45 | COPY . . 46 | RUN git clean -fxd 47 | 48 | COPY pkg/release/deb-build.sh pkg/release/run-build.sh /usr/local/bin/ 49 | 50 | CMD ["/usr/local/bin/deb-build.sh", "/output"] 51 | -------------------------------------------------------------------------------- /conf/hooks/10-cgroups.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | shopt -s lastpipe 19 | 20 | while IFS=':' read -r x ctrl path; do 21 | if [ -n "${ctrl}" ]; then 22 | grep -m1 "\- cgroup cgroup [^ ]*${ctrl}" 23 | else 24 | grep -m1 "\- cgroup2 cgroup" 25 | fi < /proc/self/mountinfo | { IFS=' ' read -r x x x root mount x || :; } 26 | 27 | if [ -n "${root}" ] && [ -n "${mount}" ]; then 28 | subtree="${mount}/${path#${root}}${SLURM_STEP_ID:+/..}" 29 | printf "%s %s none x-create=dir,rbind,nosuid,noexec,nodev,ro\n" "${subtree}" "${mount}" >> "${ENROOT_MOUNTS}" 30 | fi 31 | done < /proc/self/cgroup 32 | 33 | printf "none /sys/fs/cgroup none rbind,remount,nosuid,noexec,nodev,ro,rslave,nofail,silent\n" >> "${ENROOT_MOUNTS}" 34 | -------------------------------------------------------------------------------- /pkg/release/Dockerfile.almalinux: -------------------------------------------------------------------------------- 1 | FROM almalinux:8 AS base 2 | 3 | # Install build dependencies 4 | RUN dnf install -y epel-release && \ 5 | dnf update -y && \ 6 | dnf install -y \ 7 | rpm-build \ 8 | rpmlint \ 9 | rpmdevtools \ 10 | git \ 11 | make \ 12 | gcc \ 13 | libtool \ 14 | libmd-devel \ 15 | curl \ 16 | ca-certificates && \ 17 | dnf clean all 18 | 19 | 20 | FROM base AS build-amd64 21 | 22 | # Install cross-compilation toolchain for aarch64 23 | RUN cd /tmp && \ 24 | curl --proto '=https' -fSsL "https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz" -O && \ 25 | echo 'ddeaff1ea60d4135acba271b0143d9f5add02b68ab9e9be39672d1965c12e82f arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz' | sha256sum -c --strict - && \ 26 | mkdir /opt/arm-gnu-toolchain && \ 27 | tar xJf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz --strip-components=1 -C /opt/arm-gnu-toolchain && \ 28 | rm /tmp/*.tar.xz 29 | 30 | ENV PATH="${PATH}:/opt/arm-gnu-toolchain/bin" 31 | 32 | 33 | FROM base AS build-arm64 34 | 35 | 36 | FROM build-${TARGETARCH} 37 | WORKDIR /usr/local/src/enroot 38 | COPY . . 39 | RUN git clean -fxd 40 | 41 | COPY pkg/release/rpm-build.sh /usr/local/bin/ 42 | 43 | CMD ["/usr/local/bin/rpm-build.sh", "/output"] 44 | -------------------------------------------------------------------------------- /pkg/deb/control: -------------------------------------------------------------------------------- 1 | Source: #PACKAGE# 2 | Section: utils 3 | Priority: optional 4 | Maintainer: #USERNAME# <#EMAIL#> 5 | Build-Depends: #BUILD_DEPS#, autotools-dev, dh-apparmor 6 | Standards-Version: #POLICY# 7 | Homepage: https://github.com/NVIDIA/enroot 8 | 9 | Package: #PACKAGE# 10 | Architecture: any 11 | Replaces: ${Replaces} 12 | Conflicts: ${Replaces} 13 | Depends: ${shlibs:Depends}, ${misc:Depends}, 14 | bash (>= 4.2), 15 | curl, 16 | gawk | mawk, 17 | jq (>= 1.5), 18 | parallel, 19 | passwd, 20 | squashfs-tools, 21 | zstd, 22 | bsdmainutils, 23 | # coreutils, 24 | # findutils, 25 | # grep, 26 | # gzip, 27 | # libc-bin, 28 | # sed, 29 | # tar, 30 | # util-linux, 31 | # ncurses-bin 32 | Recommends: pigz 33 | Suggests: libnvidia-container-tools, squashfuse, fuse-overlayfs 34 | Description: Unprivileged container sandboxing utility 35 | A simple yet powerful tool to turn traditional container/OS images into 36 | unprivileged sandboxes. 37 | . 38 | This package provides the main utility, its set of helper binaries and 39 | standard configuration files. 40 | 41 | Package: #PACKAGE#+caps 42 | Architecture: any 43 | Depends: #PACKAGE# (= ${binary:Version}), libcap2-bin, ${misc:Depends} 44 | Description: Unprivileged container sandboxing utility (extra capabilities) 45 | A simple yet powerful tool to turn traditional container/OS images into 46 | unprivileged sandboxes. 47 | . 48 | This dependency package grants extra capabilities to unprivileged users which 49 | allows them to import and convert container images directly. 50 | -------------------------------------------------------------------------------- /conf/hooks/extra/50-mig-config.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | shopt -s lastpipe 19 | 20 | source "${ENROOT_LIBRARY_PATH}/common.sh" 21 | 22 | common::checkcmd grep 23 | 24 | tac "${ENROOT_ENVIRON}" | grep "^NVIDIA_" | while IFS='=' read -r key value; do 25 | [ -v "${key}" ] || export "${key}=${value}" 26 | done || : 27 | 28 | if [ "${NVIDIA_VISIBLE_DEVICES:-void}" = "void" ] || [ "${NVIDIA_VISIBLE_DEVICES}" = "none" ]; then 29 | exit 0 30 | fi 31 | if [[ "${NVIDIA_VISIBLE_DEVICES}" =~ "MIG-" ]] || [[ "${NVIDIA_VISIBLE_DEVICES}" =~ .:. ]]; then 32 | exit 0 33 | fi 34 | 35 | common::checkcmd nvidia-smi 36 | 37 | nvsmi_args=("--query-gpu=mig.mode.current" "--format=csv,noheader") 38 | 39 | if [ "${NVIDIA_VISIBLE_DEVICES}" != "all" ]; then 40 | nvsmi_args+=("-i" "${NVIDIA_VISIBLE_DEVICES}") 41 | fi 42 | 43 | if nvidia-smi "${nvsmi_args[@]}" | grep -q "Enabled"; then 44 | echo "NVIDIA_MIG_CONFIG_DEVICES=all" >> "${ENROOT_ENVIRON}" 45 | fi 46 | -------------------------------------------------------------------------------- /doc/cmd/batch.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot batch [options] [--] CONFIG [COMMAND] [ARG...] 4 | 5 | Shorthand version of "enroot start -c CONFIG" where the root filesystem is 6 | taken from the configuration file using the special directive ENROOT_ROOTFS. 7 | ``` 8 | 9 | # Description 10 | 11 | Start a container from a [configuration script](start.md#configuration-script) similar to the [start](start.md) command with the `--conf` option. 12 | Configuration parameters are passed through special comment directives. The `ENROOT_ROOTFS` directive is mandatory and specifies the root filesystem of the container. 13 | For example: 14 | ```bash 15 | #ENROOT_ROOTFS=ubuntu 16 | #ENROOT_REMAP_ROOT=y 17 | 18 | mounts() { 19 | echo "${PWD} /mnt none bind" 20 | } 21 | ``` 22 | 23 | # Configuration 24 | 25 | | Setting | Default | Description | 26 | | ------ | ------ | ------ | 27 | | `ENROOT_ROOTFS` | | Root filesystem of the container (required) | 28 | | `ENROOT_LOGIN_SHELL` | `yes` | Use a login shell to run the container initialization | 29 | | `ENROOT_ROOTFS_WRITABLE` | `no` | Make the container root filesystem writable (same as `--rw`) | 30 | | `ENROOT_REMAP_ROOT` | `no` | Remap the current user to root inside containers (same as `--root`) | 31 | | `ENROOT_ALLOW_SUPERUSER` | `no` | Allow root to retain his superuser privileges inside containers | 32 | 33 | See also [Standard Hooks](../standard-hooks.md) for additional configuration. 34 | 35 | # Example 36 | 37 | ```bash 38 | # Import Ubuntu from DockerHub and create a container out of it 39 | $ enroot import docker://ubuntu 40 | $ enroot create ubuntu.sqsh 41 | 42 | # Write a batch script to start the ubuntu container 43 | $ cat << EOF > ubuntu.batch && chmod +x ubuntu.batch 44 | #! /usr/bin/enroot batch 45 | #ENROOT_ROOTFS=ubuntu 46 | EOF 47 | 48 | # Start the container 49 | $ ./ubuntu.batch 50 | -------------------------------------------------------------------------------- /doc/image-format.md: -------------------------------------------------------------------------------- 1 | # Image format 2 | 3 | Enroot container images are standard [squashfs](https://www.kernel.org/doc/Documentation/filesystems/squashfs.txt) images with the following configuration files influencing the container runtime behavior: 4 | 5 | | File | Description | 6 | | ------ | ------ | 7 | | `/etc/rc` | Command script of the container (entrypoint) | 8 | | `/etc/fstab` | Mount configuration of the container | 9 | | `/etc/environment` | Environment of the container | 10 | 11 | These files follow the same format as the standard Linux/Unix ones (see _fstab(5)_, _rc(8)_, _pam_env(8)_) with the exceptions listed below. 12 | 13 | * `/etc/rc`: 14 | - The command and arguments of the [start](cmd/start.md) command are passed as input parameters. 15 | 16 | 17 | * `/etc/fstab`: 18 | - The target mountpoint is relative to the container rootfs. 19 | - Allows some fields to be omitted where it makes sense, for example `/proc /proc rbind` or `tmpfs /tmp` are valid fstab entries. 20 | - Adds the mount options `x-create=dir`, `x-create=file` and `x-create=auto` to create an empty directory or file before performing the mount. 21 | - Adds the mount options `x-move` and `x-detach` to move or detach a mountpoint respectively. 22 | - References to environment variables from the host of the form `${ENVVAR}` will be substituted. 23 | - The `fs_freq` field is ignored and the `fs_passno` is instead used to specify a specific mount order. 24 | 25 | ```sh 26 | # Example mounting the current working directory from the host inside the container 27 | ${PWD} /mnt none x-create=dir,bind 28 | ``` 29 | 30 | * `/etc/environment`: 31 | - References to environment variables from the host of the form `${ENVVAR}` will be substituted. 32 | 33 | ```sh 34 | # Example preserving the DISPLAY environment variable from the host 35 | DISPLAY=${DISPLAY} 36 | ``` 37 | -------------------------------------------------------------------------------- /doc/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ``` 4 | Usage: enroot COMMAND [ARG...] 5 | 6 | Command line utility for manipulating container sandboxes. 7 | 8 | Commands: 9 | batch [options] [--] CONFIG [COMMAND] [ARG...] 10 | bundle [options] [--] IMAGE 11 | create [options] [--] IMAGE 12 | exec [options] [--] PID COMMAND [ARG...] 13 | export [options] [--] NAME 14 | import [options] [--] URI 15 | list [options] 16 | remove [options] [--] NAME... 17 | start [options] [--] NAME|IMAGE [COMMAND] [ARG...] 18 | version 19 | ``` 20 | 21 | ## Commands 22 | 23 | Refer to the documentation below for details on each command usage: 24 | 25 | * [batch](cmd/batch.md) 26 | * [bundle](cmd/bundle.md) 27 | * [create](cmd/create.md) 28 | * [exec](cmd/exec.md) 29 | * [export](cmd/export.md) 30 | * [import](cmd/import.md) 31 | * [list](cmd/list.md) 32 | * [remove](cmd/remove.md) 33 | * [start](cmd/start.md) 34 | * [version](cmd/version.md) 35 | 36 | ## Example 37 | 38 | ```sh 39 | # Import the CUDA 12.9.1 image from NVIDIA GPU Cloud (NGC) 40 | $ enroot import docker://nvcr.io#nvidia/cuda:12.9.1-devel-ubuntu24.04 41 | 42 | # Create a container out of it 43 | $ enroot create --name cuda nvidia+cuda+12.9.1-devel-ubuntu24.04.sqsh 44 | $ enroot list 45 | cuda 46 | 47 | # Compile the vectorAdd sample inside the container 48 | $ enroot start --root --rw cuda sh -c 'apt update && apt install --no-install-recommends -y git cmake' 49 | $ enroot start --root --rw cuda sh -c 'git clone --branch=v12.9 https://github.com/NVIDIA/cuda-samples.git /usr/local/cuda/samples' 50 | $ enroot start --rw cuda sh -c 'cd /usr/local/cuda/samples/Samples/0_Introduction/vectorAdd && cmake . && make -j' 51 | 52 | # Run vectorAdd 53 | $ enroot start --rw cuda /usr/local/cuda/samples/Samples/0_Introduction/vectorAdd/vectorAdd 54 | 55 | # Export the modified container as a container image 56 | $ enroot export --output cuda-vecadd.sqsh cuda 57 | 58 | # Remove the container 59 | $ enroot remove cuda 60 | ``` 61 | -------------------------------------------------------------------------------- /conf/hooks/extra/50-slurm-pytorch.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | if ! grep -q "^PYTORCH_VERSION=" "${ENROOT_ENVIRON}"; then 20 | exit 0 21 | fi 22 | 23 | if [ -n "${SLURM_STEP_NODELIST-}" ] && ! grep -q "^MASTER_ADDR=" "${ENROOT_ENVIRON}" && command -v scontrol > /dev/null; then 24 | printf "MASTER_ADDR=%s\n" "$(scontrol show hostname "${SLURM_STEP_NODELIST}" | head -n1)" >> "${ENROOT_ENVIRON}" 25 | fi 26 | if [ -n "${SLURM_JOB_ID-}" ] && ! grep -q "^MASTER_PORT=" "${ENROOT_ENVIRON}"; then 27 | printf "MASTER_PORT=%s\n" "$((${SLURM_JOB_ID} % 4536 + 61000))" >> "${ENROOT_ENVIRON}" 28 | fi 29 | if [ -n "${SLURM_NTASKS-}" ] && ! grep -q "^WORLD_SIZE=" "${ENROOT_ENVIRON}"; then 30 | printf "WORLD_SIZE=%s\n" "${SLURM_NTASKS}" >> "${ENROOT_ENVIRON}" 31 | fi 32 | if [ -n "${SLURM_PROCID-}" ] && ! grep -q "^RANK=" "${ENROOT_ENVIRON}"; then 33 | printf "RANK=%s\n" "${SLURM_PROCID}" >> "${ENROOT_ENVIRON}" 34 | fi 35 | if [ -n "${SLURM_LOCALID-}" ] && ! grep -q "^LOCAL_RANK=" "${ENROOT_ENVIRON}"; then 36 | printf "LOCAL_RANK=%s\n" "${SLURM_LOCALID}" >> "${ENROOT_ENVIRON}" 37 | fi 38 | 39 | # Matching the behavior of torch.distributed.run: https://github.com/pytorch/pytorch/blob/v1.9.0/torch/distributed/run.py#L521-L532 40 | if [ "${SLURM_STEP_NUM_TASKS:-1}" -gt "${SLURM_STEP_NUM_NODES:-1}" ] && ! grep -q "^OMP_NUM_THREADS=" "${ENROOT_ENVIRON}"; then 41 | printf "OMP_NUM_THREADS=1\n" >> "${ENROOT_ENVIRON}" 42 | fi 43 | -------------------------------------------------------------------------------- /conf/bash_completion: -------------------------------------------------------------------------------- 1 | _enroot() 2 | { 3 | local cmd= cur= prev= words=() cword= 4 | COMPREPLY=() 5 | 6 | _get_comp_words_by_ref -n : cur prev words cword 7 | 8 | if [ "${cword}" -eq 1 ]; then 9 | COMPREPLY+=($(compgen -W "batch bundle create exec export import list remove start version help" -- "${cur}")) 10 | return 0 11 | fi 12 | 13 | cmd="${words[1]}" 14 | 15 | case "${cmd}" in 16 | batch|bundle|create|exec|export|import|list|start|remove) 17 | if [ "${cword}" -gt 2 ] && printf "%s\n" "${words[@]:2:${cword}-2}" | grep -qv -- ^--; then 18 | # Stop doing completion after we got an argument, except for "remove" which takes vaargs. 19 | [ "${cmd}" != "remove" ] && return 0 20 | else 21 | # Show options completion if there are no double-dashes. 22 | if ! printf "%s\n" "${words[@]:2:${cword}-2}" | grep -qx -- --; then 23 | local opts=$(enroot "${cmd}" --help 2> /dev/null | grep -owE -- "--[[:alpha:]_-]+") 24 | COMPREPLY+=($(compgen -W "-- --help ${opts}" -- "${cur}")) 25 | fi 26 | fi 27 | esac 28 | 29 | case "${cmd}" in 30 | batch) 31 | COMPREPLY+=($(compgen -f -- "${cur}")) 32 | ;; 33 | bundle|create) 34 | COMPREPLY+=($(compgen -f -X "!(*.sfs|*.sqfs|*.sqsh|*.squashfs)" -- "${cur}")) 35 | COMPREPLY+=($(compgen -d -- "${cur}")) 36 | ;; 37 | export|remove) 38 | COMPREPLY+=($(compgen -W "$(enroot list 2> /dev/null)" -- "${cur}")) 39 | ;; 40 | import) 41 | compopt +o filenames 42 | [ "${#COMPREPLY[@]}" -eq 0 ] && compopt -o nospace 43 | [[ "${cur}" == *:// ]] && return 0 44 | COMPREPLY+=($(compgen -W "docker:// dockerd://" -- "${cur}")) 45 | __ltrim_colon_completions "${cur}" 46 | ;; 47 | start) 48 | COMPREPLY+=($(compgen -W "$(enroot list 2> /dev/null)" -- "${cur}")) 49 | COMPREPLY+=($(compgen -f -X "!(*.sfs|*.sqfs|*.sqsh|*.squashfs)" -- "${cur}")) 50 | COMPREPLY+=($(compgen -d -- "${cur}")) 51 | ;; 52 | esac 53 | } 54 | 55 | complete -F _enroot -o filenames -o nosort enroot 56 | -------------------------------------------------------------------------------- /deps/libbsd/include/bsd/inttypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2018 Guillem Jover 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. The name of the author may not be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifdef LIBBSD_OVERLAY 28 | #include_next 29 | #else 30 | #include 31 | #endif 32 | 33 | #ifndef LIBBSD_INTTYPES_H 34 | #define LIBBSD_INTTYPES_H 35 | 36 | #ifdef LIBBSD_OVERLAY 37 | #include 38 | #else 39 | #include 40 | #endif 41 | 42 | __BEGIN_DECLS 43 | intmax_t strtoi(const char *__restrict nptr, char **__restrict endptr, 44 | int base, intmax_t lo, intmax_t hi, int *rstatus); 45 | uintmax_t strtou(const char *__restrict nptr, char **__restrict endptr, 46 | int base, uintmax_t lo, uintmax_t hi, int *rstatus); 47 | __END_DECLS 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /doc/requirements.md: -------------------------------------------------------------------------------- 1 | # Requirements 2 | 3 | The list of prerequisites for running Enroot is described below. 4 | 5 | You can automatically check these by running the `enroot-check` bundle for a given release: 6 | ```sh 7 | $ curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-check_4.0.1_$(uname -m).run 8 | $ chmod +x enroot-check_*.run 9 | 10 | $ ./enroot-check_*.run --verify 11 | 12 | $ ./enroot-check_*.run 13 | Bundle ran successfully! 14 | ``` 15 | 16 | ## Kernel version 17 | Linux Kernel >= 3.10 18 | 19 | ## Kernel configuration 20 | The following kernel configuration options must be enabled: 21 | * `CONFIG_NAMESPACES` 22 | * `CONFIG_USER_NS` 23 | * `CONFIG_SECCOMP_FILTER` 24 | 25 | * In order to import Docker images or use `enroot-mksquashovlfs` 26 | - `CONFIG_OVERLAY_FS` 27 | * In order to run containers with a glibc <= 2.13 28 | - `CONFIG_X86_VSYSCALL_EMULATION` 29 | - `CONFIG_VSYSCALL_EMULATE` (recommended) or `CONFIG_VSYSCALL_NATIVE` (or `vsycall=...` see below) 30 | 31 | ## Kernel command line 32 | The following kernel command line parameters must be set: 33 | * In order to run containers with a glibc <= 2.13 34 | - `vsyscall=emulate` (recommended) or `vsyscall=native` 35 | 36 | * On RHEL-based distributions 37 | - `namespace.unpriv_enable=1` 38 | - `user_namespace.enable=1` 39 | 40 | ## Kernel settings 41 | The following kernel settings must be set accordingly: 42 | 43 | * Linux 4.9 onwards 44 | - `/proc/sys/user/max_user_namespaces` must be greater than 1 45 | - `/proc/sys/user/max_mnt_namespaces` must be greater than 1 46 | 47 | * On some distributions (e.g. Archlinux-based, Debian-based) 48 | - `/proc/sys/kernel/unprivileged_userns_clone` must be enabled (equal to 1) 49 | 50 | * On some distributions (e.g. Ubuntu-based) 51 | - `/proc/sys/kernel/apparmor_restrict_unprivileged_userns` must be disabled (equal to 0) unless `{datadir}/enroot/apparmor.profile` is installed 52 | 53 | ## GPU support (optional) 54 | 55 | * GPU architecture > 2.1 (Fermi) 56 | * [NVIDIA drivers](https://www.nvidia.com/object/unix.html) >= 361.93 (untested on older versions) 57 | * [libnvidia-container-tools](https://nvidia.github.io/libnvidia-container/) >= 1.0 58 | -------------------------------------------------------------------------------- /doc/standard-hooks.md: -------------------------------------------------------------------------------- 1 | # Standard Hooks 2 | 3 | Several [pre-start hook scripts](configuration.md#pre-start-hook-scripts) are provided by default. 4 | Some of them can be turned on or off by using the following configuration settings: 5 | 6 | | Hook | Setting | Default | Description | 7 | | ---- | ------ | ------ | ------ | 8 | | [10-devices.sh](#10-devicessh) | `ENROOT_RESTRICT_DEV` | `no` | Restrict `/dev` inside the container to a minimal set of devices | 9 | | [10-home.sh](#10-homesh) | `ENROOT_MOUNT_HOME` | `no` | Mount the current user's home directory | 10 | | [98-nvidia.sh](#98-nvidiash) | `NVIDIA_[...]` | | Control NVIDIA GPU support | 11 | | [99-mellanox.sh](#99-mellanoxsh) | `MELLANOX_[...]` | | Control MELLANOX HCA support | 12 | 13 | --- 14 | 15 | ### 10-cgroups.sh 16 | 17 | Automatically mount the cgroup subsytems inside the container within a new cgroup namespace (if supported). 18 | 19 | This hook is always enabled. 20 | 21 | ### 10-devices.sh 22 | 23 | Restrict `/dev` inside the container to a minimal set of devices. 24 | 25 | To enable it, one needs to set `ENROOT_RESTRICT_DEV`. 26 | 27 | ### 10-home.sh 28 | 29 | Mount the current user's home directory inside the container and set the `HOME` environment variable accordingly. 30 | 31 | To enable it, one needs to set `ENROOT_MOUNT_HOME`. 32 | 33 | ### 10-shadow.sh 34 | 35 | Add new user and group entries to the container shadow databases `/etc/passwd` and `/etc/group`, these entries reflect the current user on the host. 36 | Additionally, create home and mail directories as defined by `/etc/login.defs` and `/etc/default/useradd` inside the container. 37 | 38 | This hook is always enabled. 39 | 40 | ### 98-nvidia.sh 41 | Provide GPU support to the container using [libnvidia-container](https://github.com/NVIDIA/libnvidia-container). 42 | Refer to [nvidia-container-runtime (Environment variables)](https://github.com/NVIDIA/nvidia-container-runtime/#environment-variables-oci-spec) 43 | for the list of supported settings and how to enable them. 44 | 45 | ### 99-mellanox.sh 46 | Provide IB HCA support to the container by injecting MOFED from the host inside the container. 47 | Devices are controlled with the `MELLANOX_VISIBLE_DEVICES` environment variable similar to how [98-nvidia.sh](#98-nvidiash) exposes GPUs. 48 | -------------------------------------------------------------------------------- /deps/libbsd/src/strtonum.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: strtonum.c,v 1.5 2018/01/04 20:57:29 kamil Exp $ */ 2 | /*- 3 | * Copyright (c) 2014 The NetBSD Foundation, Inc. 4 | * All rights reserved. 5 | * 6 | * This code is derived from software contributed to The NetBSD Foundation 7 | * by Christos Zoulas. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions 11 | * are met: 12 | * 1. Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | long long 39 | strtonum(const char *nptr, long long minval, long long maxval, 40 | const char **errstr) 41 | { 42 | int e; 43 | long long rv; 44 | const char *resp; 45 | 46 | if (errstr == NULL) 47 | errstr = &resp; 48 | 49 | rv = (long long)strtoi(nptr, NULL, 10, minval, maxval, &e); 50 | 51 | if (e == 0) { 52 | *errstr = NULL; 53 | return rv; 54 | } 55 | 56 | if (e == ERANGE) 57 | *errstr = (rv == maxval ? "too large" : "too small"); 58 | else 59 | *errstr = "invalid"; 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Sign your work 4 | 5 | Contributions to this project must follow the [Developer Certificate of Origin 6 | (DCO)](https://developercertificate.org/) 1.1 process by signing every commit with `git commit -s`. 7 | 8 | The sign-off is a simple line at the end of the explanation for the patch, which certifies that you 9 | wrote it or otherwise have the right to pass it on as an open-source patch. The rules are pretty 10 | simple: if you can certify the below: (from [developercertificate.org](https://developercertificate.org/)): 11 | ``` 12 | Developer Certificate of Origin 13 | Version 1.1 14 | 15 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 16 | 1 Letterman Drive 17 | Suite D4700 18 | San Francisco, CA, 94129 19 | 20 | Everyone is permitted to copy and distribute verbatim copies of this 21 | license document, but changing it is not allowed. 22 | 23 | 24 | Developer's Certificate of Origin 1.1 25 | 26 | By making a contribution to this project, I certify that: 27 | 28 | (a) The contribution was created in whole or in part by me and I 29 | have the right to submit it under the open source license 30 | indicated in the file; or 31 | 32 | (b) The contribution is based upon previous work that, to the best 33 | of my knowledge, is covered under an appropriate open source 34 | license and I have the right under that license to submit that 35 | work with modifications, whether created in whole or in part 36 | by me, under the same open source license (unless I am 37 | permitted to submit under a different license), as indicated 38 | in the file; or 39 | 40 | (c) The contribution was provided directly to me by some other 41 | person who certified (a), (b) or (c) and I have not modified 42 | it. 43 | 44 | (d) I understand and agree that this project and the contribution 45 | are public and that a record of the contribution (including all 46 | personal information I submit with it, including my sign-off) is 47 | maintained indefinitely and may be redistributed consistent with 48 | this project or the open source license(s) involved. 49 | ``` 50 | 51 | then you just add a line saying: 52 | ``` 53 | Signed-off-by: Random J Developer 54 | ``` 55 | 56 | using your real name (sorry, no pseudonyms or anonymous contributions.) 57 | -------------------------------------------------------------------------------- /conf/hooks/extra/50-sharp.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | shopt -s lastpipe 19 | 20 | source "${ENROOT_LIBRARY_PATH}/common.sh" 21 | 22 | common::checkcmd awk 23 | 24 | tac "${ENROOT_ENVIRON}" | grep "^MELLANOX_" | while IFS='=' read -r key value; do 25 | [ -v "${key}" ] || export "${key}=${value}" 26 | done || : 27 | 28 | if [ "${MELLANOX_VISIBLE_DEVICES:-void}" = "void" ] || [ "${MELLANOX_VISIBLE_DEVICES}" = "none" ]; then 29 | exit 0 30 | fi 31 | 32 | if [ "${SLURM_NETWORK:-}" != "sharp" ]; then 33 | exit 0 34 | fi 35 | 36 | # Disable SHARP lazy locking and initialization. 37 | # https://docs.mellanox.com/display/sharpv214/Mellanox+SHARP+Collective+Library 38 | if ! grep -q "^SHARP_COLL_LOCK_ON_COMM_INIT=" "${ENROOT_ENVIRON}"; then 39 | printf "SHARP_COLL_LOCK_ON_COMM_INIT=1\n" >> "${ENROOT_ENVIRON}" 40 | fi 41 | if ! grep -q "^SHARP_COLL_NUM_COLL_GROUP_RESOURCE_ALLOC_THRESHOLD=" "${ENROOT_ENVIRON}"; then 42 | printf "SHARP_COLL_NUM_COLL_GROUP_RESOURCE_ALLOC_THRESHOLD=0\n" >> "${ENROOT_ENVIRON}" 43 | fi 44 | 45 | # https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html#nccl-collnet-enable 46 | if ! grep -q "^NCCL_COLLNET_ENABLE=" "${ENROOT_ENVIRON}"; then 47 | printf "NCCL_COLLNET_ENABLE=1\n" >> "${ENROOT_ENVIRON}" 48 | fi 49 | 50 | if [ -n "${SLURM_STEP_NUM_NODES-}" ] && ! grep -q "^NCCL_SHARP_GROUP_SIZE_THRESH=" "${ENROOT_ENVIRON}"; then 51 | printf "NCCL_SHARP_GROUP_SIZE_THRESH=%s\n" "${SLURM_STEP_NUM_NODES}" >> "${ENROOT_ENVIRON}" 52 | fi 53 | if [ -n "${OMPI_MCA_orte_num_nodes-}" ] && ! grep -q "^NCCL_SHARP_GROUP_SIZE_THRESH=" "${ENROOT_ENVIRON}"; then 54 | printf "NCCL_SHARP_GROUP_SIZE_THRESH=%s\n" "${OMPI_MCA_orte_num_nodes}" >> "${ENROOT_ENVIRON}" 55 | fi 56 | -------------------------------------------------------------------------------- /conf/enroot.conf.in: -------------------------------------------------------------------------------- 1 | #ENROOT_LIBRARY_PATH @libdir@ 2 | #ENROOT_SYSCONF_PATH @sysconfdir@ 3 | #ENROOT_RUNTIME_PATH ${XDG_RUNTIME_DIR}/enroot 4 | #ENROOT_CONFIG_PATH ${XDG_CONFIG_HOME}/enroot 5 | #ENROOT_CACHE_PATH ${XDG_CACHE_HOME}/enroot 6 | #ENROOT_DATA_PATH ${XDG_DATA_HOME}/enroot 7 | #ENROOT_TEMP_PATH ${TMPDIR:-/tmp} 8 | 9 | # Gzip program used to uncompress digest layers. 10 | #ENROOT_GZIP_PROGRAM gzip 11 | 12 | # Options passed to zstd to compress digest layers. 13 | #ENROOT_ZSTD_OPTIONS -1 14 | 15 | # Options passed to mksquashfs to produce container images. 16 | #ENROOT_SQUASH_OPTIONS -comp lzo -noD -exit-on-error 17 | 18 | # Make the container root filesystem writable by default. 19 | #ENROOT_ROOTFS_WRITABLE no 20 | 21 | # Remap the current user to root inside containers by default. 22 | #ENROOT_REMAP_ROOT no 23 | 24 | # Maximum number of processors to use for parallel tasks (0 means unlimited). 25 | #ENROOT_MAX_PROCESSORS $(nproc) 26 | 27 | # Maximum number of concurrent connections (0 means unlimited). 28 | #ENROOT_MAX_CONNECTIONS 10 29 | 30 | # Maximum time in seconds to wait for connections establishment (0 means unlimited). 31 | #ENROOT_CONNECT_TIMEOUT 30 32 | 33 | # Maximum time in seconds to wait for network operations to complete (0 means unlimited). 34 | #ENROOT_TRANSFER_TIMEOUT 0 35 | 36 | # Number of times network operations should be retried. 37 | #ENROOT_TRANSFER_RETRIES 0 38 | 39 | # Use a login shell to run the container initialization. 40 | #ENROOT_LOGIN_SHELL yes 41 | 42 | # Allow root to retain his superuser privileges inside containers. 43 | #ENROOT_ALLOW_SUPERUSER no 44 | 45 | # Use HTTP for outgoing requests instead of HTTPS (UNSECURE!). 46 | #ENROOT_ALLOW_HTTP no 47 | 48 | # Include user-specific configuration inside bundles by default. 49 | #ENROOT_BUNDLE_ALL no 50 | 51 | # Generate an embedded checksum inside bundles by default. 52 | #ENROOT_BUNDLE_CHECKSUM no 53 | 54 | # Mount the current user's home directory by default. 55 | #ENROOT_MOUNT_HOME no 56 | 57 | # Restrict /dev inside the container to a minimal set of devices. 58 | #ENROOT_RESTRICT_DEV no 59 | 60 | # Always use --force on command invocations. 61 | #ENROOT_FORCE_OVERRIDE no 62 | 63 | # SSL certificates settings: 64 | #SSL_CERT_DIR 65 | #SSL_CERT_FILE 66 | 67 | # Proxy settings: 68 | #all_proxy 69 | #no_proxy 70 | #http_proxy 71 | #https_proxy 72 | -------------------------------------------------------------------------------- /pkg/debbuild: -------------------------------------------------------------------------------- 1 | #! /usr/bin/enroot batch 2 | #ENROOT_REMAP_ROOT=y 3 | #ENROOT_ROOTFS_WRITABLE=y 4 | #ENROOT_ROOTFS=${ENROOT_ROOTFS:-ubuntu.sqsh} 5 | 6 | mounts() { 7 | echo "$(dirname $0)/.. /usr/local/src/enroot" 8 | } 9 | 10 | environ() { 11 | echo "DO_RELEASE=${DO_RELEASE-}" 12 | echo "CROSS_COMPILE=${CROSS_COMPILE-}" 13 | echo "SHELL=/bin/bash" 14 | } 15 | 16 | rc() { 17 | release=$(. /etc/os-release 2> /dev/null; echo "${VERSION_CODENAME-}") 18 | 19 | cat <<- EOF > /etc/apt/sources.list 20 | deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${release} main restricted universe multiverse 21 | deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${release}-updates main restricted universe multiverse 22 | deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ ${release}-backports main restricted universe multiverse 23 | deb [arch=amd64] http://security.ubuntu.com/ubuntu/ ${release}-security main restricted universe multiverse 24 | deb [arch=arm64,ppc64el] http://ports.ubuntu.com/ ${release} main restricted universe multiverse 25 | deb [arch=arm64,ppc64el] http://ports.ubuntu.com/ ${release}-updates main restricted universe multiverse 26 | EOF 27 | 28 | apt-get -y update && apt-get -y install --no-install-recommends \ 29 | autotools-dev \ 30 | build-essential \ 31 | devscripts \ 32 | dh-make \ 33 | dh-apparmor \ 34 | fakeroot \ 35 | lintian \ 36 | lsb-release \ 37 | rename \ 38 | libmd-dev 39 | 40 | if [[ "${CROSS_COMPILE}" =~ "aarch64-linux-gnu" ]]; then 41 | dpkg --add-architecture arm64 42 | 43 | apt-get -y install --no-install-recommends \ 44 | gcc-8-aarch64-linux-gnu \ 45 | linux-libc-dev-arm64-cross \ 46 | libc6-dev-arm64-cross \ 47 | libmd-dev:arm64 48 | 49 | export ARCH=aarch64 50 | export CC=aarch64-linux-gnu-gcc-8 51 | elif [[ "${CROSS_COMPILE}" =~ "powerpc64le-linux-gnu" ]]; then 52 | dpkg --add-architecture ppc64el 53 | 54 | apt-get -y install --no-install-recommends \ 55 | gcc-8-powerpc64le-linux-gnu \ 56 | linux-libc-dev-ppc64el-cross \ 57 | libc6-dev-ppc64el-cross \ 58 | libmd-dev:ppc64el 59 | 60 | export ARCH=powerpc64le 61 | export CC=powerpc64le-linux-gnu-gcc-8 62 | fi 63 | 64 | cd /usr/local/src/enroot 65 | 66 | if [ "$1" = "--hardened" ]; then 67 | make deb PACKAGE=enroot-hardened 68 | else 69 | CPPFLAGS="-DALLOW_SPECULATION -DINHERIT_FDS" make deb 70 | fi 71 | } 72 | -------------------------------------------------------------------------------- /conf/hooks/10-devices.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | if [ -z "${ENROOT_RESTRICT_DEV-}" ]; then 20 | exit 0 21 | fi 22 | 23 | source "${ENROOT_LIBRARY_PATH}/common.sh" 24 | 25 | cat << EOF | enroot-mount --root "${ENROOT_ROOTFS}" - 26 | none /dev none x-detach,nofail,silent 27 | tmpfs /dev tmpfs x-create=dir,rw,nosuid,noexec,mode=755,slave 28 | /dev/zero /dev/zero none x-create=file,bind,rw,nosuid,noexec,private 29 | /dev/null /dev/null none x-create=file,bind,rw,nosuid,noexec,private 30 | /dev/full /dev/full none x-create=file,bind,rw,nosuid,noexec,private 31 | /dev/urandom /dev/urandom none x-create=file,bind,rw,nosuid,noexec,private 32 | /dev/random /dev/random none x-create=file,bind,rw,nosuid,noexec,private 33 | devpts /dev/pts devpts x-create=dir,rw,nosuid,noexec,newinstance,ptmxmode=0666,mode=620,slave 34 | /dev/tty /dev/tty none x-create=file,bind,rw,nosuid,noexec,private 35 | /dev/shm /dev/shm none x-create=dir,bind,rw,nosuid,noexec,nodev,rslave 36 | /dev/mqueue /dev/mqueue none x-create=dir,bind,rw,nosuid,noexec,nodev,rslave 37 | /dev/hugepages /dev/hugepages none x-create=dir,bind,rw,nosuid,noexec,nodev,rslave,nofail,silent 38 | /dev/log /dev/log none x-create=file,bind,rw,nosuid,noexec,nodev,private 39 | EOF 40 | 41 | if [ -t 0 ]; then 42 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "$(common::realpath /dev/stdin) /dev/console none x-create=file,bind,rw,nosuid,noexec,private" 43 | fi 44 | 45 | ln -s "/proc/self/fd" "${ENROOT_ROOTFS}/dev/fd" 46 | ln -s "/dev/pts/ptmx" "${ENROOT_ROOTFS}/dev/ptmx" 47 | ln -s "/proc/self/fd/0" "${ENROOT_ROOTFS}/dev/stdin" 48 | ln -s "/proc/self/fd/1" "${ENROOT_ROOTFS}/dev/stdout" 49 | ln -s "/proc/self/fd/2" "${ENROOT_ROOTFS}/dev/stderr" 50 | -------------------------------------------------------------------------------- /deps/libbsd/include/bsd/unistd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2006 Robert Millan 3 | * Copyright © 2008-2011 Guillem Jover 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. The name of the author may not be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 17 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 18 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 19 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifdef LIBBSD_OVERLAY 29 | #include 30 | #if __has_include_next() 31 | #include_next 32 | #endif 33 | #else 34 | #include 35 | #if __has_include() 36 | #include 37 | #endif 38 | #endif 39 | 40 | #ifndef LIBBSD_UNISTD_H 41 | #define LIBBSD_UNISTD_H 42 | 43 | #include 44 | 45 | #if !defined(S_ISTXT) && defined(S_ISVTX) 46 | #define S_ISTXT S_ISVTX 47 | #endif 48 | 49 | __BEGIN_DECLS 50 | extern int optreset; 51 | 52 | #ifdef LIBBSD_OVERLAY 53 | #undef getopt 54 | #define getopt(argc, argv, optstr) bsd_getopt(argc, argv, optstr) 55 | #endif 56 | 57 | int bsd_getopt(int argc, char * const argv[], const char *shortopts); 58 | 59 | mode_t getmode(const void *set, mode_t mode); 60 | void *setmode(const char *mode_str); 61 | 62 | void closefrom(int lowfd); 63 | 64 | /* Compatibility with sendmail implementations. */ 65 | #define initsetproctitle(c, a, e) setproctitle_init((c), (a), (e)) 66 | 67 | void setproctitle_init(int argc, char *argv[], char *envp[]); 68 | void setproctitle(const char *fmt, ...) 69 | __printflike(1, 2); 70 | 71 | int getpeereid(int s, uid_t *euid, gid_t *egid); 72 | __END_DECLS 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ENROOT 2 | 3 | A simple, yet powerful tool to turn traditional container/OS images into unprivileged sandboxes. 4 | 5 | Enroot can be thought of as an enhanced unprivileged `chroot(1)`. It uses the same underlying technologies as containers but removes much of the isolation they inherently provide while preserving filesystem separation. 6 | 7 | This approach is generally preferred in high-performance environments or virtualized environments where portability and reproducibility is important, but extra isolation is not warranted. 8 | 9 | Enroot is also similar to other tools like `proot(1)` or `fakeroot(1)` but instead relies on more recent features from the Linux kernel (i.e. user and mount namespaces), and provides facilities to import well known container image formats (e.g. [Docker](https://www.docker.com/)). 10 | 11 | Usage example: 12 | 13 | ```sh 14 | # Import and start an Ubuntu image from DockerHub 15 | $ enroot import docker://ubuntu 16 | $ enroot create ubuntu.sqsh 17 | $ enroot start ubuntu 18 | ``` 19 | 20 | ## Key Concepts 21 | 22 | * Adheres to the [KISS principle](https://en.wikipedia.org/wiki/KISS_principle) and [Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy) 23 | * Standalone (no daemon) 24 | * Fully unprivileged and multi-user capable (no setuid binary, cgroup inheritance, per-user configuration/container store...) 25 | * Easy to use (simple image format, scriptable, root remapping...) 26 | * Little to no isolation (no performance overhead, simplifies HPC deployements) 27 | * Entirely composable and extensible (system-wide and user-specific configurations) 28 | * Fast Docker image import (3x to 5x speedup on large images) 29 | * Built-in GPU support with [libnvidia-container](https://github.com/nvidia/libnvidia-container) 30 | * Facilitate collaboration and development workflows (bundles, in-memory containers...) 31 | 32 | ## Documentation 33 | 34 | 1. [Requirements](doc/requirements.md) 35 | 1. [Installation](doc/installation.md) 36 | 1. [Image format](doc/image-format.md) 37 | 1. [Configuration](doc/configuration.md) 38 | 1. [Standard Hooks](doc/standard-hooks.md) 39 | 1. [Usage](doc/usage.md) 40 | 41 | 42 | ## Copyright and License 43 | 44 | This project is released under the [Apache License 2.0](https://github.com/NVIDIA/enroot/blob/master/LICENSE). 45 | 46 | ## Issues and Contributing 47 | 48 | * Please let us know by [filing a new issue](https://github.com/NVIDIA/enroot/issues/new) 49 | * You can contribute by opening a [pull request](https://help.github.com/articles/using-pull-requests/), please make sure you read [CONTRIBUTING](CONTRIBUTING.md) first. 50 | 51 | ## Reporting Security Issues 52 | 53 | When reporting a security issue, do not create an issue or file a pull request. 54 | Instead, disclose the issue responsibly by sending an email to `psirtnvidia.com`. 55 | -------------------------------------------------------------------------------- /doc/configuration.md: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | ## Runtime configuration 4 | 5 | The runtime can be configured through the file `enroot.conf` (under `/etc/enroot` by default) or by using environment variables. 6 | Environment variables take precedence over the configuration file. 7 | 8 | The following table describes standard paths used by the runtime: 9 | 10 | | Setting | Default | Description | 11 | | ------ | ------ | ------ | 12 | | `ENROOT_LIBRARY_PATH` | `/usr/lib/enroot` | Path to library sources | 13 | | `ENROOT_SYSCONF_PATH` | `/etc/enroot` | Path to system configuration files | 14 | | `ENROOT_RUNTIME_PATH` | `${XDG_RUNTIME_DIR}/enroot` | Path to the runtime working directory | 15 | | `ENROOT_CONFIG_PATH` | `${XDG_CONFIG_HOME}/enroot` | Path to user configuration files | 16 | | `ENROOT_CACHE_PATH` | `${XDG_CACHE_HOME}/enroot` | Path to user image/credentials cache | 17 | | `ENROOT_DATA_PATH` | `${XDG_DATA_HOME}/enroot` | Path to user container storage | 18 | | `ENROOT_TEMP_PATH` | `${TMPDIR}` | Path to temporary directory | 19 | 20 | When `enroot.conf` has been read, and if there is a directory `enroot.conf.d` next to `enroot.conf`, all files in that directory matching `*.conf` will be considered, too. 21 | 22 | ## Container configuration 23 | 24 | Common configurations can be applied to all containers by leveraging the following directories under `ENROOT_SYSCONF_PATH` (system-wide) and/or `ENROOT_CONFIG_PATH` (user-specific). 25 | 26 | | Directory | Description | 27 | | ------ | ------ | 28 | | `environ.d` | Environment configuration files | 29 | | `mounts.d` | Mount configuration files | 30 | | `hooks.d` | Pre-start hook scripts | 31 | 32 | ### Environment configuration files 33 | Environment files are used to export environment variables inside containers. 34 | They have the `.env` extension and follow the same format as described in [Image format (/etc/environment)](image-format.md). 35 | 36 | ### Mount configuration files 37 | Mount files are used to mount filesystems, files or directories inside containers. 38 | They have the `.fstab` extension and follow the same format as described in [Image format (/etc/fstab)](image-format.md). 39 | 40 | ### Pre-start hook scripts 41 | Pre-start hooks are used to perform specific actions before the container starts. 42 | They are standard bash scripts with the `.sh` extension and run with full capabilities before the container has switched to its final root. 43 | 44 | 45 | The host environment as well as the following environment variables are made available to hooks and configuration files: 46 | 47 | | Environment | Description | 48 | | ------ | ------ | 49 | | `ENROOT_PID` | PID of the container | 50 | | `ENROOT_ROOTFS` | Path to the container root filesystem | 51 | | `ENROOT_MOUNTS` | Path to the container mount file to be read at startup | 52 | | `ENROOT_ENVIRON` | Path to the container environment file to be read at startup | 53 | -------------------------------------------------------------------------------- /conf/hooks/extra/50-slurm-pmi.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | shopt -s lastpipe 19 | 20 | if [ -z "${SLURM_JOB_ID-}" ] || [ -z "${SLURM_STEP_ID-}" ]; then 21 | exit 0 22 | fi 23 | 24 | for var in $(compgen -e "SLURM_"); do 25 | printf "%s=%s\n" "${var}" "${!var}" >> "${ENROOT_ENVIRON}" 26 | done 27 | 28 | # Check for PMIx support. 29 | if [[ -z "${SLURM_MPI_TYPE-}" || "${SLURM_MPI_TYPE}" == pmix* ]] && compgen -e "PMIX_" > /dev/null; then 30 | source "${ENROOT_LIBRARY_PATH}/common.sh" 31 | 32 | common::checkcmd scontrol awk 33 | 34 | scontrol show config | awk '/^SlurmdSpoolDir|^TmpFS/ {print $3}' \ 35 | | { read -r slurm_spool; read -r slurm_tmpfs; } || : 36 | 37 | if [ -z "${slurm_spool}" ] || [ -z "${slurm_tmpfs}" ]; then 38 | common::err "Could not read SLURM configuration" 39 | fi 40 | 41 | for var in $(compgen -e "PMIX_"); do 42 | printf "%s=%s\n" "${var}" "${!var}" >> "${ENROOT_ENVIRON}" 43 | done 44 | if [ -n "${PMIX_PTL_MODULE-}" ] && [ -z "${PMIX_MCA_ptl-}" ]; then 45 | printf "PMIX_MCA_ptl=%s\n" ${PMIX_PTL_MODULE} >> "${ENROOT_ENVIRON}" 46 | fi 47 | if [ -n "${PMIX_SECURITY_MODE-}" ] && [ -z "${PMIX_MCA_psec-}" ]; then 48 | printf "PMIX_MCA_psec=%s\n" ${PMIX_SECURITY_MODE} >> "${ENROOT_ENVIRON}" 49 | fi 50 | if [ -n "${PMIX_GDS_MODULE-}" ] && [ -z "${PMIX_MCA_gds-}" ]; then 51 | printf "PMIX_MCA_gds=%s\n" ${PMIX_GDS_MODULE} >> "${ENROOT_ENVIRON}" 52 | fi 53 | 54 | if [ -e "${slurm_tmpfs}/spmix_appdir_${SLURM_JOB_UID}_${SLURM_JOB_ID}.${SLURM_STEP_ID}" ]; then 55 | printf "%s x-create=dir,bind,rw,nosuid,noexec,nodev,private,nofail\n" "${slurm_tmpfs}/spmix_appdir_${SLURM_JOB_UID}_${SLURM_JOB_ID}.${SLURM_STEP_ID}" >> "${ENROOT_MOUNTS}" 56 | else 57 | printf "%s x-create=dir,bind,rw,nosuid,noexec,nodev,private,nofail\n" "${slurm_tmpfs}/spmix_appdir_${SLURM_JOB_ID}.${SLURM_STEP_ID}" >> "${ENROOT_MOUNTS}" 58 | fi 59 | printf "%s x-create=dir,bind,rw,nosuid,noexec,nodev,private\n" "${slurm_spool}/pmix.${SLURM_JOB_ID}.${SLURM_STEP_ID}" >> "${ENROOT_MOUNTS}" 60 | fi 61 | 62 | # Check for PMI/PMI2 support. 63 | if compgen -e "PMI_" > /dev/null; then 64 | for var in $(compgen -e "PMI_"); do 65 | printf "%s=%s\n" "${var}" "${!var}" >> "${ENROOT_ENVIRON}" 66 | done 67 | fi 68 | -------------------------------------------------------------------------------- /pkg/deb/changelog: -------------------------------------------------------------------------------- 1 | #PACKAGE# (4.0.1-1) UNRELEASED; urgency=medium 2 | 3 | * Release v4.0.1 4 | 5 | -- #USERNAME# <#EMAIL#> Tue, 14 Oct 2025 02:38:35 +0000 6 | 7 | #PACKAGE# (4.0.0-1) UNRELEASED; urgency=medium 8 | 9 | * Release v4.0.0 10 | 11 | -- #USERNAME# <#EMAIL#> Thu, 02 Oct 2025 00:00:40 +0000 12 | 13 | #PACKAGE# (3.5.0-1) UNRELEASED; urgency=medium 14 | 15 | * Release v3.5.0 16 | 17 | -- #USERNAME# <#EMAIL#> Thu, 16 May 2024 23:35:14 +0000 18 | 19 | #PACKAGE# (3.4.1-1) UNRELEASED; urgency=medium 20 | 21 | * Release v3.4.1 22 | 23 | -- #USERNAME# <#EMAIL#> Wed, 08 Feb 2023 07:01:13 +0000 24 | 25 | #PACKAGE# (3.4.0-1) UNRELEASED; urgency=medium 26 | 27 | * Release v3.4.0 28 | 29 | -- #USERNAME# <#EMAIL#> Thu, 04 Nov 2021 21:50:36 +0000 30 | 31 | #PACKAGE# (3.3.1-1) UNRELEASED; urgency=medium 32 | 33 | * Release v3.3.1 34 | 35 | -- #USERNAME# <#EMAIL#> Fri, 06 Aug 2021 23:53:15 +0000 36 | 37 | #PACKAGE# (3.3.0-1) UNRELEASED; urgency=medium 38 | 39 | * Release v3.3.0 40 | 41 | -- #USERNAME# <#EMAIL#> Tue, 06 Apr 2021 09:23:36 +0000 42 | 43 | #PACKAGE# (3.2.0-1) UNRELEASED; urgency=medium 44 | 45 | * Release v3.2.0 46 | 47 | -- #USERNAME# <#EMAIL#> Wed, 02 Dec 2020 07:57:54 +0000 48 | 49 | #PACKAGE# (3.1.1-1) UNRELEASED; urgency=medium 50 | 51 | * Release v3.1.1 52 | 53 | -- #USERNAME# <#EMAIL#> Thu, 06 Aug 2020 00:38:56 +0000 54 | 55 | #PACKAGE# (3.1.0-1) UNRELEASED; urgency=medium 56 | 57 | * Release v3.1.0 58 | 59 | -- #USERNAME# <#EMAIL#> Tue, 30 Jun 2020 21:17:26 +0000 60 | 61 | #PACKAGE# (3.0.2-1) UNRELEASED; urgency=medium 62 | 63 | * Release v3.0.2 64 | 65 | -- #USERNAME# <#EMAIL#> Tue, 07 Apr 2020 06:49:53 +0000 66 | 67 | #PACKAGE# (3.0.1-1) UNRELEASED; urgency=medium 68 | 69 | * Release v3.0.1 70 | 71 | -- #USERNAME# <#EMAIL#> Fri, 13 Mar 2020 23:12:27 +0000 72 | 73 | #PACKAGE# (3.0.0-1) UNRELEASED; urgency=medium 74 | 75 | * Release v3.0.0 76 | 77 | -- #USERNAME# <#EMAIL#> Sat, 01 Feb 2020 00:54:17 +0000 78 | 79 | #PACKAGE# (2.2.0-1) UNRELEASED; urgency=medium 80 | 81 | * Release v2.2.0 82 | 83 | -- #USERNAME# <#EMAIL#> Wed, 30 Oct 2019 17:17:13 +0000 84 | 85 | #PACKAGE# (2.1.0-1) UNRELEASED; urgency=medium 86 | 87 | * Release v2.1.0 88 | 89 | -- #USERNAME# <#EMAIL#> Thu, 17 Oct 2019 09:05:51 +0000 90 | 91 | #PACKAGE# (2.0.1-1) UNRELEASED; urgency=medium 92 | 93 | * Release v2.0.1 94 | 95 | -- #USERNAME# <#EMAIL#> Thu, 05 Sep 2019 21:30:56 +0000 96 | 97 | #PACKAGE# (2.0.0-1) UNRELEASED; urgency=medium 98 | 99 | * Release v2.0.0 100 | 101 | -- #USERNAME# <#EMAIL#> Tue, 13 Aug 2019 22:35:08 +0000 102 | 103 | #PACKAGE# (1.1.0-1) UNRELEASED; urgency=medium 104 | 105 | * Release v1.1.0 106 | 107 | -- #USERNAME# <#EMAIL#> Mon, 03 Jun 2019 22:42:20 +0000 108 | 109 | #PACKAGE# (1.0.0-1) UNRELEASED; urgency=medium 110 | 111 | * Initial release 112 | 113 | -- #USERNAME# <#EMAIL#> Thu, 18 Apr 2019 22:11:23 +0000 114 | -------------------------------------------------------------------------------- /bin/compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2005-2021 Rich Felker, et al. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef __GLIBC__ 31 | # define compat_getmntent_r getmntent_r 32 | # define compat_lastlog lastlog 33 | #else 34 | 35 | static inline struct mntent * 36 | compat_getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) 37 | { 38 | int n[8]; 39 | 40 | *mnt = (struct mntent){0}; 41 | 42 | do { 43 | memset(n, 0, sizeof(n)); 44 | 45 | fgets(linebuf, buflen, f); 46 | if (feof(f) || ferror(f)) 47 | return (NULL); 48 | 49 | if (!strchr(linebuf, '\n')) { 50 | fscanf(f, "%*[^\n]%*[\n]"); 51 | errno = ERANGE; 52 | return (NULL); 53 | } 54 | sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", 55 | n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, 56 | &mnt->mnt_freq, &mnt->mnt_passno); 57 | } while (n[1] == 0 || linebuf[n[0]] == '#'); 58 | 59 | linebuf[n[1]] = '\0'; 60 | mnt->mnt_fsname = linebuf + n[0]; 61 | 62 | if (n[3] > 0) { 63 | linebuf[n[3]] = '\0'; 64 | mnt->mnt_dir = linebuf + n[2]; 65 | } 66 | if (n[5] > 0) { 67 | linebuf[n[5]] = '\0'; 68 | mnt->mnt_type = linebuf + n[4]; 69 | } 70 | if (n[7] > 0) { 71 | linebuf[n[7]] = '\0'; 72 | mnt->mnt_opts = linebuf + n[6]; 73 | } 74 | return (mnt); 75 | } 76 | 77 | struct compat_lastlog { 78 | #ifdef __x86_64__ 79 | int32_t ll_time; 80 | #else 81 | time_t ll_time; 82 | #endif 83 | char ll_line[UT_LINESIZE]; 84 | char ll_host[UT_HOSTSIZE]; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /deps/Makefile: -------------------------------------------------------------------------------- 1 | unexport prefix exec_prefix bindir libdir sysconfdir DESTDIR 2 | 3 | LOCKFILE := Makefile.lock 4 | AR := flock $(LOCKFILE) $(AR) 5 | ARFLAGS := crU 6 | 7 | MAKESELF_VERSION := 2.4.5 8 | MUSL_VERSION := 1.2.5 9 | LINUX_HEADER_VERSION := 4.19.88-1 10 | 11 | .PHONY: all libbsd makeself musl linux-headers clean update 12 | .DEFAULT_GOAL := all 13 | 14 | ifdef CROSS_COMPILE 15 | HOST_ARG := --host=$(CROSS_COMPILE:-=) 16 | endif 17 | 18 | export CPPFLAGS := -D_FORTIFY_SOURCE=2 19 | export CFLAGS := -O2 -fdata-sections -ffunction-sections -fstack-protector -fPIE 20 | 21 | # Required for Musl on PPC64 22 | ifeq "$(ARCH:power%=p%)" "ppc64le" 23 | CFLAGS += -mlong-double-64 24 | endif 25 | 26 | MAKEOVERRIDES := 27 | 28 | LIBBSD_SRC := libbsd/src/closefrom.c \ 29 | libbsd/src/strtoi.c \ 30 | libbsd/src/strtonum.c \ 31 | libbsd/src/strtou.c \ 32 | libbsd/src/fparseln.c 33 | 34 | makeself/.stamp: 35 | install -m 755 -D makeself/makeself.sh dist/makeself/bin/enroot-makeself 36 | touch $@ 37 | 38 | ifndef FORCE_GLIBC 39 | ifneq (,$(findstring gcc, $(notdir $(CC)))) 40 | %.o: CC := $(CURDIR)/dist/musl/bin/musl-gcc 41 | else ifneq (,$(findstring clang, $(notdir $(CC)))) 42 | %.o: CC := $(CURDIR)/dist/musl/bin/musl-clang 43 | else 44 | $(error MUSL CC wrapper not found for $(CC)) 45 | endif 46 | endif 47 | %.o: CPPFLAGS += -DHAVE_DIRFD -DHAVE_DIRENT_H -DLIBBSD_OVERLAY -isystem libbsd/include/bsd 48 | 49 | libbsd/.stamp: dist/libbsd/libbsd.a($(LIBBSD_SRC:.c=.o)) 50 | find libbsd/include -type f -exec install -D -m 644 {} dist/{} \; 51 | touch $@ 52 | dist/libbsd/libbsd.a($(LIBBSD_SRC:.c=.o)): | dist/libbsd 53 | dist/libbsd: 54 | install -d $@ 55 | 56 | musl/.stamp: 57 | # XXX Add static PIE support to the GCC wrapper 58 | -patch -d musl -N -r - -p1 < musl.patch 59 | cd musl && ./configure --prefix=$(CURDIR)/dist/musl --disable-shared $(HOST_ARG) 60 | $(MAKE) -C musl install 61 | # XXX Workaround for GCC < 5.0 62 | touch $(CURDIR)/dist/musl/include/sys/cdefs.h 63 | touch $@ 64 | 65 | # XXX Quirk for PPC64 directory name 66 | ifeq "$(ARCH:power%=p%)" "ppc64le" 67 | linux-headers/.stamp: export ARCH:=powerpc 68 | endif 69 | linux-headers/.stamp: 70 | $(MAKE) -C linux-headers install prefix=$(CURDIR)/dist/linux 71 | touch $@ 72 | 73 | all: libbsd makeself linux-headers $(if $(FORCE_GLIBC),,musl) 74 | 75 | musl: musl/.stamp 76 | linux-headers: linux-headers/.stamp 77 | .NOTPARALLEL: libbsd 78 | libbsd: $(if $(FORCE_GLIBC),,musl) libbsd/.stamp 79 | makeself: makeself/.stamp 80 | 81 | clean: 82 | -cd makeself && { git clean -f -d -x; $(RM) .stamp; } 83 | -cd libbsd && $(RM) .stamp 84 | -cd musl && { git clean -f -d -x; $(MAKE) distclean; git checkout .; $(RM) .stamp; } 85 | -cd linux-headers && { git clean -f -d -x; $(RM) .stamp; } 86 | rm -rf dist 87 | $(RM) $(LOCKFILE) 88 | 89 | update: clean 90 | git submodule sync --recursive 91 | cd makeself && { git fetch origin; git checkout -f release-$(MAKESELF_VERSION); } 92 | cd musl && { git fetch origin; git checkout -f v$(MUSL_VERSION); } 93 | cd linux-headers && { git fetch origin; git checkout -f v$(LINUX_HEADER_VERSION); } 94 | -------------------------------------------------------------------------------- /deps/libbsd/src/strtoi.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: _strtoi.h,v 1.2 2015/01/18 17:55:22 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | * 31 | * Original version ID: 32 | * NetBSD: src/lib/libc/locale/_wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp 33 | * 34 | * Created by Kamil Rytarowski, based on ID: 35 | * NetBSD: src/common/lib/libc/stdlib/_strtoul.h,v 1.7 2013/05/17 12:55:56 joe… 36 | */ 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #define _DIAGASSERT(t) 46 | 47 | intmax_t 48 | strtoi(const char *__restrict nptr, 49 | char **__restrict endptr, int base, 50 | intmax_t lo, intmax_t hi, int *rstatus) 51 | { 52 | int serrno; 53 | intmax_t im; 54 | char *ep; 55 | int rep; 56 | 57 | _DIAGASSERT(hi >= lo); 58 | 59 | _DIAGASSERT(nptr != NULL); 60 | /* endptr may be NULL */ 61 | 62 | if (endptr == NULL) 63 | endptr = &ep; 64 | 65 | if (rstatus == NULL) 66 | rstatus = &rep; 67 | 68 | serrno = errno; 69 | errno = 0; 70 | 71 | im = strtoimax(nptr, endptr, base); 72 | 73 | *rstatus = errno; 74 | errno = serrno; 75 | 76 | if (*rstatus == 0) { 77 | /* No digits were found */ 78 | if (nptr == *endptr) 79 | *rstatus = ECANCELED; 80 | /* There are further characters after number */ 81 | else if (**endptr != '\0') 82 | *rstatus = ENOTSUP; 83 | } 84 | 85 | if (im < lo) { 86 | if (*rstatus == 0) 87 | *rstatus = ERANGE; 88 | return lo; 89 | } 90 | if (im > hi) { 91 | if (*rstatus == 0) 92 | *rstatus = ERANGE; 93 | return hi; 94 | } 95 | 96 | return im; 97 | } 98 | -------------------------------------------------------------------------------- /deps/libbsd/src/strtou.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: _strtoi.h,v 1.2 2015/01/18 17:55:22 christos Exp $ */ 2 | 3 | /*- 4 | * Copyright (c) 1990, 1993 5 | * The Regents of the University of California. All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 3. Neither the name of the University nor the names of its contributors 16 | * may be used to endorse or promote products derived from this software 17 | * without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 | * SUCH DAMAGE. 30 | * 31 | * Original version ID: 32 | * NetBSD: src/lib/libc/locale/_wcstoul.h,v 1.2 2003/08/07 16:43:03 agc Exp 33 | * 34 | * Created by Kamil Rytarowski, based on ID: 35 | * NetBSD: src/common/lib/libc/stdlib/_strtoul.h,v 1.7 2013/05/17 12:55:56 joe… 36 | */ 37 | 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #define _DIAGASSERT(t) 46 | 47 | uintmax_t 48 | strtou(const char *__restrict nptr, 49 | char **__restrict endptr, int base, 50 | uintmax_t lo, uintmax_t hi, int *rstatus) 51 | { 52 | int serrno; 53 | uintmax_t im; 54 | char *ep; 55 | int rep; 56 | 57 | _DIAGASSERT(hi >= lo); 58 | 59 | _DIAGASSERT(nptr != NULL); 60 | /* endptr may be NULL */ 61 | 62 | if (endptr == NULL) 63 | endptr = &ep; 64 | 65 | if (rstatus == NULL) 66 | rstatus = &rep; 67 | 68 | serrno = errno; 69 | errno = 0; 70 | 71 | im = strtoumax(nptr, endptr, base); 72 | 73 | *rstatus = errno; 74 | errno = serrno; 75 | 76 | if (*rstatus == 0) { 77 | /* No digits were found */ 78 | if (nptr == *endptr) 79 | *rstatus = ECANCELED; 80 | /* There are further characters after number */ 81 | else if (**endptr != '\0') 82 | *rstatus = ENOTSUP; 83 | } 84 | 85 | if (im < lo) { 86 | if (*rstatus == 0) 87 | *rstatus = ERANGE; 88 | return lo; 89 | } 90 | if (im > hi) { 91 | if (*rstatus == 0) 92 | *rstatus = ERANGE; 93 | return hi; 94 | } 95 | 96 | return im; 97 | } 98 | -------------------------------------------------------------------------------- /doc/cmd/bundle.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot bundle [options] [--] IMAGE 4 | 5 | Create a self-extracting bundle from a container image. 6 | 7 | Options: 8 | -a, --all Include runtime and user configuration files in the bundle 9 | -c, --checksum Generate an embedded checksum 10 | -d, --desc TEXT Provide a description of the bundle 11 | -o, --output BUNDLE Name of the output bundle file (defaults to "IMAGE.run") 12 | -t, --target DIR Target directory used by --keep (defaults to "$PWD/BUNDLE") 13 | -f, --force Overwrite an existing bundle 14 | ``` 15 | ``` 16 | Usage: bundle.run [options] [--] [COMMAND] [ARG...] 17 | 18 | Options: 19 | -i, --info Display the information about this bundle 20 | -k, --keep Keep the bundle extracted in the target directory 21 | -q, --quiet Supress the progress bar output 22 | -v, --verify Verify that the host configuration is compatible with the bundle 23 | -x, --extract Extract the bundle in the target directory and exit (implies --keep) 24 | 25 | -c, --conf CONFIG Specify a configuration script to run before the container starts 26 | -e, --env KEY[=VAL] Export an environment variable inside the container 27 | --rc SCRIPT Override the command script inside the container 28 | -m, --mount FSTAB Perform a mount from the host inside the container (colon-separated) 29 | -r, --root Ask to be remapped to root inside the container 30 | -w, --rw Make the container root filesystem writable 31 | ``` 32 | 33 | # Description 34 | 35 | Create a self-extracting bundle from a container image which can be used to start a container on most Linux distributions with no external dependencies. 36 | The resulting bundle takes the same arguments as the [start](start.md) command. 37 | 38 | The target directory used to keep the container filesystem can be defined using the `--target` option and defaults to `$PWD/`. 39 | By default when generating a bundle, only system-wide configuration is copied to the bundle unless `--all` is specified, in which case runtime and user-specified configuration is copied as well. 40 | 41 | Before executing a bundle, `--verify` can be used to check whether or not the host meets the necessary requirements. 42 | 43 | If `--keep` is not provided at launch, `$ENROOT_TEMP_PATH` will be used for extraction. 44 | 45 | # Configuration 46 | 47 | | Environment | Default | Description | 48 | | ------ | ------ | ------ | 49 | | `ENROOT_BUNDLE_ALL` | `no` | Include runtime and user-specific configuration inside bundles (same as `--all`) | 50 | | `ENROOT_BUNDLE_CHECKSUM` | `no` | Generate an embedded checksum inside bundles (same as `--checksum`) | 51 | | `ENROOT_FORCE_OVERRIDE` | `no` | Overwrite the bundle if it already exists (same as `--force`) | 52 | 53 | # Example 54 | 55 | ```sh 56 | # Import Ubuntu from DockerHub and generate a bundle from it 57 | $ enroot import docker://ubuntu 58 | $ enroot bundle --target '${HOME}/.local/share/enroot/hello-world' ubuntu.sqsh 59 | 60 | # Execute the bundle by writing a message at the root of its filesystem and keep it extracted 61 | $ ./ubuntu.run --keep --rw tee /message <<< "Hello World" 62 | 63 | # Display the message inside the bundle root filesystem 64 | $ enroot start hello-world cat /message 65 | ``` 66 | -------------------------------------------------------------------------------- /deps/libbsd/include/bsd/libutil.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1996 Peter Wemm . 3 | * All rights reserved. 4 | * Copyright (c) 2002 Networks Associates Technology, Inc. 5 | * All rights reserved. 6 | * 7 | * Portions of this software were developed for the FreeBSD Project by 8 | * ThinkSec AS and NAI Labs, the Security Research Division of Network 9 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10 | * ("CBOSS"), as part of the DARPA CHATS research program. 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, is permitted provided that the following conditions 14 | * are met: 15 | * 1. Redistributions of source code must retain the above copyright 16 | * notice, this list of conditions and the following disclaimer. 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notice, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 3. The name of the author may not be used to endorse or promote 21 | * products derived from this software without specific prior written 22 | * permission. 23 | * 24 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | * SUCH DAMAGE. 35 | * 36 | * $FreeBSD: src/lib/libutil/libutil.h,v 1.47 2008/04/23 00:49:12 scf Exp $ 37 | */ 38 | 39 | #ifndef LIBBSD_LIBUTIL_H 40 | #define LIBBSD_LIBUTIL_H 41 | 42 | #ifdef LIBBSD_OVERLAY 43 | #include 44 | #else 45 | #include 46 | #endif 47 | #include 48 | #include 49 | #include 50 | 51 | struct pidfh; 52 | 53 | __BEGIN_DECLS 54 | int humanize_number(char *buf, size_t len, int64_t bytes, 55 | const char *suffix, int scale, int flags); 56 | int expand_number(const char *_buf, uint64_t *_num); 57 | 58 | int flopen(const char *_path, int _flags, ...); 59 | int flopenat(int dirfd, const char *path, int flags, ...); 60 | 61 | struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr); 62 | int pidfile_fileno(const struct pidfh *pfh); 63 | int pidfile_write(struct pidfh *pfh); 64 | int pidfile_close(struct pidfh *pfh); 65 | int pidfile_remove(struct pidfh *pfh); 66 | 67 | char *fparseln(FILE *, size_t *, size_t *, const char[3], int); 68 | __END_DECLS 69 | 70 | /* Values for humanize_number(3)'s flags parameter. */ 71 | #define HN_DECIMAL 0x01 72 | #define HN_NOSPACE 0x02 73 | #define HN_B 0x04 74 | #define HN_DIVISOR_1000 0x08 75 | #define HN_IEC_PREFIXES 0x10 76 | 77 | /* Values for humanize_number(3)'s scale parameter. */ 78 | #define HN_GETSCALE 0x10 79 | #define HN_AUTOSCALE 0x20 80 | 81 | /* 82 | * fparseln() specific operation flags. 83 | */ 84 | #define FPARSELN_UNESCESC 0x01 85 | #define FPARSELN_UNESCCONT 0x02 86 | #define FPARSELN_UNESCCOMM 0x04 87 | #define FPARSELN_UNESCREST 0x08 88 | #define FPARSELN_UNESCALL 0x0f 89 | 90 | #endif /* !LIBBSD_LIBUTIL_H */ 91 | -------------------------------------------------------------------------------- /conf/hooks/98-nvidia.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | shopt -s lastpipe 19 | 20 | export PATH="${PATH}:/usr/sbin:/sbin:${ENROOT_ROOTFS}/usr/bin:${ENROOT_ROOTFS}/usr/local/bin" 21 | 22 | source "${ENROOT_LIBRARY_PATH}/common.sh" 23 | 24 | common::checkcmd grep ldconfig 25 | 26 | tac "${ENROOT_ENVIRON}" | grep "^NVIDIA_" | while IFS='=' read -r key value; do 27 | [ -v "${key}" ] || export "${key}=${value}" 28 | done || : 29 | 30 | cli_args=("--no-cgroups" "--ldconfig=@$(command -v ldconfig.real || command -v ldconfig)") 31 | 32 | # https://github.com/nvidia/nvidia-container-runtime#nvidia_visible_devices 33 | if [ "${NVIDIA_VISIBLE_DEVICES:-void}" = "void" ]; then 34 | exit 0 35 | fi 36 | if [ "${NVIDIA_VISIBLE_DEVICES}" != "none" ]; then 37 | cli_args+=("--device=${NVIDIA_VISIBLE_DEVICES}") 38 | fi 39 | 40 | # https://github.com/NVIDIA/nvidia-container-runtime#nvidia_mig_config_devices 41 | if [ -n "${NVIDIA_MIG_CONFIG_DEVICES-}" ]; then 42 | cli_args+=("--mig-config=${NVIDIA_MIG_CONFIG_DEVICES}") 43 | fi 44 | # https://github.com/NVIDIA/nvidia-container-runtime#nvidia_mig_monitor_devices 45 | if [ -n "${NVIDIA_MIG_MONITOR_DEVICES-}" ]; then 46 | cli_args+=("--mig-monitor=${NVIDIA_MIG_MONITOR_DEVICES}") 47 | fi 48 | 49 | # https://github.com/nvidia/nvidia-container-runtime#nvidia_driver_capabilities 50 | if [ -z "${NVIDIA_DRIVER_CAPABILITIES-}" ]; then 51 | NVIDIA_DRIVER_CAPABILITIES="utility" 52 | fi 53 | for cap in ${NVIDIA_DRIVER_CAPABILITIES//,/ }; do 54 | case "${cap}" in 55 | all) 56 | cli_args+=("--compute" "--compat32" "--display" "--graphics" "--utility" "--video") 57 | break 58 | ;; 59 | compute|compat32|display|graphics|utility|video) 60 | cli_args+=("--${cap}") ;; 61 | *) 62 | common::err "Unknown NVIDIA driver capability: ${cap}" ;; 63 | esac 64 | done 65 | 66 | # https://github.com/nvidia/nvidia-container-runtime#nvidia_require_ 67 | if [ -z "${NVIDIA_DISABLE_REQUIRE-}" ]; then 68 | for req in $(compgen -e "NVIDIA_REQUIRE_"); do 69 | cli_args+=("--require=${!req}") 70 | done 71 | fi 72 | 73 | if ! command -v nvidia-container-cli > /dev/null; then 74 | common::err "Command not found: nvidia-container-cli, see https://github.com/NVIDIA/libnvidia-container" 75 | fi 76 | if ! grep -q nvidia_uvm /proc/modules; then 77 | common::log WARN "Kernel module nvidia_uvm is not loaded. Make sure the NVIDIA device driver is installed and loaded." 78 | fi 79 | 80 | # Add support for GDRCopy and IMEX channels. 81 | if [[ " ${cli_args[@]} " =~ " --compute " ]]; then 82 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "/dev/gdrdrv /dev/gdrdrv none x-create=file,bind,ro,nosuid,noexec,private,nofail,silent" 83 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "/dev/nvidia-caps-imex-channels /dev/nvidia-caps-imex-channels none x-create=dir,bind,ro,nosuid,noexec,private,nofail,silent" 84 | fi 85 | 86 | exec nvidia-container-cli --user ${NVIDIA_DEBUG_LOG+--debug=/dev/stderr} configure "${cli_args[@]}" "${ENROOT_ROOTFS}" 87 | -------------------------------------------------------------------------------- /deps/libbsd/include/bsd/stdlib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2005 Aurelien Jarno 3 | * Copyright © 2006 Robert Millan 4 | * Copyright © 2008-2011 Guillem Jover 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 3. The name of the author may not be used to endorse or promote products 15 | * derived from this software without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 20 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #ifdef LIBBSD_OVERLAY 30 | #include_next 31 | #else 32 | #include 33 | #endif 34 | 35 | /* For compatibility with NetBSD, which defines humanize_number here. */ 36 | #ifdef LIBBSD_OVERLAY 37 | #include 38 | #else 39 | #include 40 | #endif 41 | 42 | #ifndef LIBBSD_STDLIB_H 43 | #define LIBBSD_STDLIB_H 44 | 45 | #ifdef LIBBSD_OVERLAY 46 | #include 47 | #else 48 | #include 49 | #endif 50 | #include 51 | #include 52 | 53 | __BEGIN_DECLS 54 | #if !defined(__GLIBC__) || \ 55 | !__GLIBC_PREREQ(2, 36) || \ 56 | !defined(_DEFAULT_SOURCE) 57 | uint32_t arc4random(void); 58 | void arc4random_buf(void *_buf, size_t n); 59 | uint32_t arc4random_uniform(uint32_t upper_bound); 60 | #endif 61 | void arc4random_stir(void); 62 | void arc4random_addrandom(unsigned char *dat, int datlen); 63 | 64 | int dehumanize_number(const char *str, int64_t *size); 65 | 66 | const char *getprogname(void); 67 | void setprogname(const char *); 68 | 69 | int heapsort(void *, size_t, size_t, int (*)(const void *, const void *)); 70 | int mergesort(void *base, size_t nmemb, size_t size, 71 | int (*cmp)(const void *, const void *)); 72 | int radixsort(const unsigned char **base, int nmemb, 73 | const unsigned char *table, unsigned endbyte); 74 | int sradixsort(const unsigned char **base, int nmemb, 75 | const unsigned char *table, unsigned endbyte); 76 | 77 | void *reallocf(void *ptr, size_t size); 78 | #if !defined(__GLIBC__) || \ 79 | !__GLIBC_PREREQ(2, 26) || \ 80 | (__GLIBC_PREREQ(2, 26) && !__GLIBC_PREREQ(2, 29) && !defined(_GNU_SOURCE)) || \ 81 | (__GLIBC_PREREQ(2, 29) && !defined(_DEFAULT_SOURCE)) 82 | void *reallocarray(void *ptr, size_t nmemb, size_t size); 83 | #endif 84 | void *recallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t size); 85 | void freezero(void *ptr, size_t size); 86 | 87 | long long strtonum(const char *nptr, long long minval, long long maxval, 88 | const char **errstr); 89 | 90 | char *getbsize(int *headerlenp, long *blocksizep); 91 | __END_DECLS 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /pkg/rpm/SPECS/enroot.spec: -------------------------------------------------------------------------------- 1 | %define _prefix %{nil} 2 | %define _exec_prefix /usr 3 | %define _libdir /usr/lib 4 | %define _datarootdir /usr/share 5 | 6 | Name: %{PACKAGE} 7 | Version: %{VERSION} 8 | Release: 1%{?dist} 9 | License: ASL 2.0 10 | Vendor: %{USERNAME} 11 | Packager: %{USERNAME} <%{EMAIL}> 12 | URL: https://github.com/NVIDIA/enroot 13 | 14 | BuildRequires: make gcc libtool libmd-devel 15 | 16 | Summary: Unprivileged container sandboxing utility 17 | %if "%{?getenv:PACKAGE}" != "" 18 | Conflicts: enroot 19 | %endif 20 | Requires: bash >= 4.2, curl, gawk, jq >= 1.5, parallel, shadow-utils, squashfs-tools 21 | Requires: coreutils, grep, findutils, gzip, glibc-common, sed, tar, util-linux, zstd 22 | #Recommends: pigz, ncurses 23 | #Suggests: libnvidia-container-tools, squashfuse, fuse-overlayfs 24 | %description 25 | A simple yet powerful tool to turn traditional container/OS images into 26 | unprivileged sandboxes. 27 | 28 | This package provides the main utility, its set of helper binaries and 29 | standard configuration files. 30 | %files 31 | %license LICENSE 32 | %config(noreplace) %{_sysconfdir}/* 33 | %{_libdir}/* 34 | %{_bindir}/* 35 | %{_datadir}/* 36 | 37 | %package -n %{name}+caps 38 | Summary: Unprivileged container sandboxing utility (extra capabilities) 39 | Requires: %{name}%{?_isa} = %{version}-%{release}, libcap 40 | %description -n %{name}+caps 41 | A simple yet powerful tool to turn traditional container/OS images into 42 | unprivileged sandboxes. 43 | 44 | This dependency package grants extra capabilities to unprivileged users which 45 | allows them to import and convert container images directly. 46 | %posttrans -n %{name}+caps 47 | /usr/sbin/setcap cap_sys_admin+ep %{_bindir}/enroot-mksquashovlfs 48 | /usr/sbin/setcap cap_sys_admin,cap_mknod+pe %{_bindir}/enroot-aufs2ovlfs 49 | %preun -n %{name}+caps 50 | /usr/sbin/setcap cap_sys_admin-ep %{_bindir}/enroot-mksquashovlfs 51 | /usr/sbin/setcap cap_sys_admin,cap_mknod-pe %{_bindir}/enroot-aufs2ovlfs 52 | %files -n %{name}+caps 53 | 54 | %build 55 | %make_build prefix=%{_prefix} exec_prefix=%{_exec_prefix} libdir=%{_libdir} datarootdir=%{_datarootdir} 56 | 57 | %install 58 | %make_install prefix=%{_prefix} exec_prefix=%{_exec_prefix} libdir=%{_libdir} datarootdir=%{_datarootdir} 59 | 60 | %changelog 61 | * Tue Oct 14 2025 %{packager} 4.0.1-1 62 | - Release v4.0.1 63 | 64 | * Thu Oct 02 2025 %{packager} 4.0.0-1 65 | - Release v4.0.0 66 | 67 | * Thu May 16 2024 %{packager} 3.5.0-1 68 | - Release v3.5.0 69 | 70 | * Wed Feb 08 2023 %{packager} 3.4.1-1 71 | - Release v3.4.1 72 | 73 | * Thu Nov 11 2021 %{packager} 3.4.0-2 74 | - Fix scriplet ordering during package upgrade 75 | 76 | * Thu Nov 04 2021 %{packager} 3.4.0-1 77 | - Release v3.4.0 78 | 79 | * Fri Aug 06 2021 %{packager} 3.3.1-1 80 | - Release v3.3.1 81 | 82 | * Tue Apr 06 2021 %{packager} 3.3.0-1 83 | - Release v3.3.0 84 | 85 | * Wed Dec 02 2020 %{packager} 3.2.0-1 86 | - Release v3.2.0 87 | 88 | * Thu Aug 06 2020 %{packager} 3.1.1-1 89 | - Release v3.1.1 90 | 91 | * Tue Jun 30 2020 %{packager} 3.1.0-1 92 | - Release v3.1.0 93 | 94 | * Tue Apr 07 2020 %{packager} 3.0.2-1 95 | - Release v3.0.2 96 | 97 | * Fri Mar 13 2020 %{packager} 3.0.1-1 98 | - Release v3.0.1 99 | 100 | * Sat Feb 01 2020 %{packager} 3.0.0-1 101 | - Release v3.0.0 102 | 103 | * Wed Oct 30 2019 %{packager} 2.2.0-1 104 | - Release v2.2.0 105 | 106 | * Thu Oct 17 2019 %{packager} 2.1.0-1 107 | - Release v2.1.0 108 | 109 | * Thu Sep 05 2019 %{packager} 2.0.1-1 110 | - Release v2.0.1 111 | 112 | * Tue Aug 13 2019 %{packager} 2.0.0-1 113 | - Release v2.0.0 114 | 115 | * Mon Jun 03 2019 %{packager} 1.1.0-1 116 | - Release v1.1.0 117 | 118 | * Sat Apr 20 2019 %{packager} 1.0.0-1 119 | - Initial release 120 | -------------------------------------------------------------------------------- /conf/hooks/10-shadow.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | export PATH="${PATH}:/usr/sbin:/sbin" 20 | 21 | source "${ENROOT_LIBRARY_PATH}/common.sh" 22 | 23 | common::checkcmd awk getent sed grpck pwck 24 | 25 | readonly nobody=$(< /proc/sys/kernel/overflowuid) 26 | readonly nogroup=$(< /proc/sys/kernel/overflowgid) 27 | readonly pwdent=$(common::getpwent) 28 | readonly grpent=$(common::getgrent) 29 | 30 | # Load the default shadow settings. 31 | if [ -f "${ENROOT_ROOTFS}/etc/login.defs" ]; then 32 | declare $(awk '(NF && $1 !~ "^#"){ print "def_"$1"="$2 }' "${ENROOT_ROOTFS}/etc/login.defs") 33 | fi 34 | if [ -f "${ENROOT_ROOTFS}/etc/default/useradd" ]; then 35 | declare $(awk '(NF && $1 !~ "^#"){ print "def_"$1 }' "${ENROOT_ROOTFS}/etc/default/useradd") 36 | fi 37 | 38 | # Read the user/group database entries for the current user on the host. 39 | IFS=':' read -r user x uid x gecos home shell <<< "${pwdent}" 40 | IFS=':' read -r group x gid x <<< "${grpent}" 41 | 42 | if [ ! -x "${ENROOT_ROOTFS}${shell}" ]; then 43 | shell="${def_SHELL:-/bin/sh}" 44 | fi 45 | 46 | touch "${ENROOT_ROOTFS}/etc/passwd" "${ENROOT_ROOTFS}/etc/group" 47 | trap 'rm -f "${pwddb-}" "${grpdb-}"' EXIT 48 | pwddb=$(mktemp -p "${ENROOT_ROOTFS}/etc" .passwd.XXXXXX) 49 | grpdb=$(mktemp -p "${ENROOT_ROOTFS}/etc" .group.XXXXXX) 50 | 51 | # Generate passwd and group entries for root, nobody and the current user. 52 | # XXX Remove the _apt user/group otherwise apt will try to drop privileges and fail. 53 | sed '/^_apt:/d' "${ENROOT_ROOTFS}/etc/passwd" - << EOF >> "${pwddb}" 54 | root:x:0:0:root:/root:${shell} 55 | nobody:x:${nobody}:${nogroup}:nobody:/:/sbin/nologin 56 | ${user}:x:${uid}:${gid}:${gecos}:${home}:${shell} 57 | EOF 58 | 59 | sed '/^_apt:/d' "${ENROOT_ROOTFS}/etc/group" - << EOF >> "${grpdb}" 60 | root:x:0: 61 | nogroup:x:${nogroup}: 62 | ${group}:x:${gid}: 63 | EOF 64 | 65 | # Check and install the new databases making sure our generated entries come first. 66 | yes 2> /dev/null | grpck -R "${ENROOT_ROOTFS}" "${grpdb#${ENROOT_ROOTFS}}" /etc/gshadow > /dev/null 2>&1 || : 67 | { tail -n -3 "${grpdb}"; head -n -3 "${grpdb}"; } > "${grpdb}-" && mv "${grpdb}-" "${grpdb}" 68 | mv "${grpdb}" "${ENROOT_ROOTFS}/etc/group" 69 | 70 | yes 2> /dev/null | pwck -R "${ENROOT_ROOTFS}" "${pwddb#${ENROOT_ROOTFS}}" /etc/shadow > /dev/null 2>&1 || : 71 | { tail -n -3 "${pwddb}"; head -n -3 "${pwddb}"; } > "${pwddb}-" && mv "${pwddb}-" "${pwddb}" 72 | mv "${pwddb}" "${ENROOT_ROOTFS}/etc/passwd" 73 | 74 | # Create the user home directory if it doesn't exist and populate it with the content of the skeleton directory. 75 | if [ ! -e "${ENROOT_ROOTFS}${home}" ] && [ "${def_CREATE_HOME:-yes}" = "yes" ]; then 76 | ( umask "${def_UMASK:-077}" && mkdir -p "${ENROOT_ROOTFS}${home}" ) 77 | skel="${def_SKEL:-/etc/skel}" 78 | if [ -d "${ENROOT_ROOTFS}${skel}" ]; then 79 | cp -Lpr "${ENROOT_ROOTFS}${skel}/." "${ENROOT_ROOTFS}${home}" 80 | fi 81 | fi 82 | 83 | # Create the user mailbox if it doesn't exist. 84 | if [ "${def_CREATE_MAIL_SPOOL:-no}" = "yes" ]; then 85 | maildir="${def_MAIL_DIR:-/var/mail}" 86 | if [ ! -e "${ENROOT_ROOTFS}${maildir}/${user}" ]; then 87 | mkdir -p "${ENROOT_ROOTFS}${maildir}" 88 | ( umask 007 && touch "${ENROOT_ROOTFS}${maildir}/${user}" ) 89 | fi 90 | fi 91 | -------------------------------------------------------------------------------- /bin/enroot-mksquashovlfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "common.h" 28 | 29 | #ifndef MOUNTPOINT 30 | # define MOUNTPOINT "/mnt" 31 | #endif 32 | 33 | static struct capabilities_v3 caps; 34 | 35 | static void 36 | init_capabilities(void) 37 | { 38 | CAP_INIT_V3(&caps); 39 | 40 | if (capget(&caps.hdr, caps.data) < 0) 41 | err(EXIT_FAILURE, "failed to get capabilities"); 42 | 43 | CAP_FOREACH(&caps, n) { 44 | if (n == CAP_DAC_READ_SEARCH || n == CAP_DAC_OVERRIDE) 45 | continue; 46 | CAP_CLR(&caps, permitted, n); 47 | CAP_CLR(&caps, effective, n); 48 | CAP_CLR(&caps, inheritable, n); 49 | } 50 | CAP_SET(&caps, permitted, CAP_SYS_ADMIN); 51 | CAP_SET(&caps, effective, CAP_SYS_ADMIN); 52 | 53 | if (capset(&caps.hdr, caps.data) < 0) 54 | err(EXIT_FAILURE, "failed to set capabilities"); 55 | } 56 | 57 | int 58 | main(int argc, char *argv[]) 59 | { 60 | const char *mountpoint; 61 | char *mountopts = NULL; 62 | 63 | if (argc < 3) { 64 | printf("Usage: %s DIR[:DIR...] DEST [options]\n", argv[0]); 65 | return (0); 66 | } 67 | 68 | init_capabilities(); 69 | 70 | if ((mountpoint = getenv("MOUNTPOINT")) == NULL) 71 | mountpoint = MOUNTPOINT; 72 | if (*mountpoint != '/') 73 | errx(EXIT_FAILURE, "MOUNTPOINT environment variable must be an absolute path"); 74 | 75 | /* 76 | * Ideally we would like to do this as an unprivileged user since some distributions support mounting 77 | * overlayfs inside a userns (e.g. Ubuntu). However, due to the lack of support for trusted xattrs, 78 | * opaque whiteouts would be silently ignored (cf. aufs2ovlfs). 79 | */ 80 | #if 0 81 | if (unshare_userns(false) < 0) 82 | err(EXIT_FAILURE, "failed to create user namespace"); 83 | #endif 84 | if (unshare(CLONE_NEWNS) < 0) 85 | err(EXIT_FAILURE, "failed to create mount namespace"); 86 | if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) 87 | err(EXIT_FAILURE, "failed to set mount propagation"); 88 | 89 | if (asprintf(&mountopts, "lowerdir=%s", argv[1]) < 0 || 90 | mount(NULL, mountpoint, "overlay", 0, mountopts) < 0) 91 | err(EXIT_FAILURE, "failed to mount overlay: %s", argv[1]); 92 | free(mountopts); 93 | 94 | CAP_CLR(&caps, permitted, CAP_SYS_ADMIN); 95 | CAP_CLR(&caps, effective, CAP_SYS_ADMIN); 96 | if (capset(&caps.hdr, caps.data) < 0 || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) 97 | err(EXIT_FAILURE, "failed to drop privileges"); 98 | 99 | argv[1] = (char *)mountpoint; 100 | if (execvpe("mksquashfs", argv, (char * const []){(char *)"PATH="_PATH_STDPATH, NULL}) < 0) 101 | err(EXIT_FAILURE, "failed to execute mksquashfs"); 102 | return (0); 103 | } 104 | -------------------------------------------------------------------------------- /doc/cmd/import.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ``` 4 | Usage: enroot import [options] [--] URI 5 | 6 | Import a container image from a specific location. 7 | 8 | Schemes: 9 | docker://[USER@][REGISTRY#]IMAGE[:TAG] Import a Docker image from a registry 10 | dockerd://IMAGE[:TAG] Import a Docker image from the Docker daemon 11 | podman://IMAGE[:TAG] Import a Docker image from a local Podman repository 12 | 13 | Options: 14 | -a, --arch Architecture of the image (defaults to host architecture) 15 | -o, --output Name of the output image file (defaults to "URI.sqsh") 16 | ``` 17 | 18 | # Description 19 | 20 | Import and convert (if necessary) a container image from a specific location to an [Enroot image](../image-format.md). 21 | The resulting image can be unpacked using the [create](create.md) command. 22 | 23 | Credentials can be configured through the file `$ENROOT_CONFIG_PATH/.credentials` following the netrc file format. 24 | If the password field starts with a `$` sign, it will be substituted. For example: 25 | ```sh 26 | # NVIDIA GPU Cloud (both endpoints are required) 27 | machine nvcr.io login $oauthtoken password 28 | machine authn.nvidia.com login $oauthtoken password 29 | 30 | # DockerHub 31 | machine registry-1.docker.io login password 32 | 33 | # Google Artifact Registry: 34 | # Where us-docker.pkg.dev is the hostname for the container images stored in Artifact Registry. This should be replaced with the hostname you are using (i.e. us-west1-docker.pkg.dev). 35 | # If using multiple hostnames, add one line per hostname 36 | # Google Artifact Registry with OAuth 37 | machine us-docker.pkg.dev login oauth2accesstoken password $(gcloud auth print-access-token) 38 | # Google Artifact Registry with JSON 39 | machine us-docker.pkg.dev login _json_key password $(jq -c '.' $GOOGLE_APPLICATION_CREDENTIALS | sed 's/ /\\u0020/g') 40 | 41 | # Amazon Elastic Container Registry 42 | machine 12345.dkr.ecr.eu-west-2.amazonaws.com login AWS password $(aws ecr get-login-password --region eu-west-2) 43 | 44 | # Azure Container Registry with ACR refresh token 45 | machine myregistry.azurecr.io login 00000000-0000-0000-0000-000000000000 password $(az acr login --name myregistry --expose-token --query accessToken | tr -d '"') 46 | # Azure Container Registry with ACR admin user 47 | machine myregistry.azurecr.io login myregistry password $(az acr credential show --name myregistry --subscription mysub --query passwords[0].value | tr -d '"') 48 | ``` 49 | 50 | ### Supported schemes 51 | #### [Docker (docker://)](https://www.docker.com/) 52 | 53 | Docker image manifest version 2, schema 2. 54 | Digests are cached under `$ENROOT_CACHE_PATH/`. 55 | 56 | #### [Docker Daemon (dockerd://)](https://www.docker.com/) 57 | 58 | Docker image manifest version 2, schema 2. 59 | Requires the Docker CLI to communicate with the Docker daemon. 60 | 61 | #### [Podman (podman://)](https://www.podman.io/) 62 | 63 | Docker image manifest version 2, schema 2. 64 | Requires the Podman CLI to communicate with the local Podman repository. 65 | 66 | # Configuration 67 | 68 | | Setting | Default | Description | 69 | | ------ | ------ | ------ | 70 | | `ENROOT_GZIP_PROGRAM` | `pigz` _or_ `gzip` | Gzip program used to uncompress digest layers | 71 | | `ENROOT_ZSTD_OPTIONS` | `-1` | Options passed to zstd to compress digest layers | 72 | | `ENROOT_SQUASH_OPTIONS` | `-comp lzo -noD -exit-on-error` | Options passed to mksquashfs to produce container images | 73 | | `ENROOT_MAX_PROCESSORS` | `$(nproc)` | Maximum number of processors to use for parallel tasks (0 means unlimited) | 74 | | `ENROOT_MAX_CONNECTIONS` | `10` | Maximum number of concurrent connections (0 means unlimited) | 75 | | `ENROOT_CONNECT_TIMEOUT` | `30` | Maximum time in seconds to wait for connections establishment (0 means unlimited) | 76 | | `ENROOT_TRANSFER_TIMEOUT` | `0` | Maximum time in seconds to wait for network operations to complete (0 means unlimited) | 77 | | `ENROOT_TRANSFER_RETRIES` | `0` | Number of times network operations should be retried | 78 | | `ENROOT_ALLOW_HTTP` | `no` | Use HTTP for outgoing requests instead of HTTPS **(UNSECURE!)** | 79 | 80 | # Example 81 | 82 | ```sh 83 | # Import PyTorch 25.06 from NVIDIA GPU Cloud (NGC) 84 | $ enroot import --output pytorch.sqsh docker://nvcr.io#nvidia/pytorch:25.06-py3 85 | ``` 86 | 87 | # Known issues 88 | 89 | * Older versions of curl (< 7.61) do not support more than 256 characters passwords. 90 | -------------------------------------------------------------------------------- /conf/hooks/99-mellanox.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -euo pipefail 18 | shopt -s lastpipe nullglob 19 | 20 | export PATH="${PATH}:/usr/sbin:/sbin" 21 | 22 | source "${ENROOT_LIBRARY_PATH}/common.sh" 23 | 24 | common::checkcmd grep awk ldd ldconfig 25 | 26 | tac "${ENROOT_ENVIRON}" | grep "^MELLANOX_" | while IFS='=' read -r key value; do 27 | [ -v "${key}" ] || export "${key}=${value}" 28 | done || : 29 | 30 | if [ "${MELLANOX_VISIBLE_DEVICES:-void}" = "void" ] || [ "${MELLANOX_VISIBLE_DEVICES}" = "none" ]; then 31 | exit 0 32 | fi 33 | : ${MELLANOX_CONFIG_DIR:=/etc/libibverbs.d} 34 | 35 | declare -a drivers=() 36 | declare -a devices=() 37 | declare -a ifaces=() 38 | declare -a issms=() 39 | declare -a umads=() 40 | declare -A providers=() 41 | 42 | # Lookup all the devices and their respective driver. 43 | for uevent in /sys/bus/pci/drivers/mlx?_core/*/infiniband_verbs/*/uevent; do 44 | case "${uevent}" in 45 | *mlx4*) drivers+=("mlx4") ;; 46 | *mlx5*) drivers+=("mlx5") ;; 47 | *) continue ;; 48 | esac 49 | devices+=("$(. "${uevent}"; echo "/dev/${DEVNAME}")") 50 | done 51 | 52 | # Lookup all the interfaces. 53 | for uevent in /sys/bus/pci/drivers/mlx?_core/*/infiniband/*/uevent; do 54 | ifaces+=("$(. "${uevent}"; echo "${NAME}")") 55 | done 56 | 57 | # Lookup all the management devices. 58 | for uevent in /sys/bus/pci/drivers/mlx?_core/*/infiniband_mad/*/uevent; do 59 | case "${uevent}" in 60 | *issm*) issms+=("$(. "${uevent}"; echo "/dev/${DEVNAME}")") ;; 61 | *umad*) umads+=("$(. "${uevent}"; echo "/dev/${DEVNAME}")") ;; 62 | *) continue ;; 63 | esac 64 | done 65 | 66 | # Hide all the device entries in sysfs by default and mount RDMA CM. 67 | cat << EOF | enroot-mount --root "${ENROOT_ROOTFS}" - 68 | tmpfs /sys/class/infiniband tmpfs nosuid,noexec,nodev,mode=755,private 69 | tmpfs /sys/class/infiniband_verbs tmpfs nosuid,noexec,nodev,mode=755,private 70 | tmpfs /sys/class/infiniband_cm tmpfs nosuid,noexec,nodev,mode=755,private,nofail,silent 71 | tmpfs /sys/class/infiniband_mad tmpfs nosuid,noexec,nodev,mode=755,private 72 | /sys/class/infiniband_verbs/abi_version /sys/class/infiniband_verbs/abi_version none x-create=file,bind,ro,nosuid,noexec,nodev,private 73 | /sys/class/infiniband_cm/abi_version /sys/class/infiniband_cm/abi_version none x-create=file,bind,ro,nosuid,noexec,nodev,private,nofail,silent 74 | /sys/class/infiniband_mad/abi_version /sys/class/infiniband_mad/abi_version none x-create=file,bind,ro,nosuid,noexec,nodev,private 75 | /dev/infiniband/rdma_cm /dev/infiniband/rdma_cm none x-create=file,bind,ro,nosuid,noexec,private 76 | EOF 77 | 78 | # Mount all the visible devices specified. 79 | if [ "${MELLANOX_VISIBLE_DEVICES}" = "all" ]; then 80 | MELLANOX_VISIBLE_DEVICES="$(seq -s, 0 $((${#devices[@]} - 1)))" 81 | fi 82 | for id in ${MELLANOX_VISIBLE_DEVICES//,/ }; do 83 | if [[ ! "${id}" =~ ^[[:digit:]]+$ ]] || [ "${id}" -lt 0 ] || [ "${id}" -ge "${#devices[@]}" ]; then 84 | common::err "Unknown MELLANOX device id: ${id}" 85 | fi 86 | providers["${drivers[id]}"]=true 87 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "${devices[id]} ${devices[id]} none x-create=file,bind,ro,nosuid,noexec,private" 88 | ln -s "$(common::realpath "/sys/class/infiniband/${ifaces[id]}")" "${ENROOT_ROOTFS}/sys/class/infiniband/${ifaces[id]}" 89 | ln -s "$(common::realpath "/sys/class/infiniband_verbs/${devices[id]##*/}")" "${ENROOT_ROOTFS}/sys/class/infiniband_verbs/${devices[id]##*/}" 90 | 91 | if [ -n "${ENROOT_ALLOW_SUPERUSER-}" ] && [ "$(awk '{print $2}' /proc/self/uid_map)" -eq 0 ]; then 92 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "${umads[id]} ${umads[id]} none x-create=file,bind,ro,nosuid,noexec,private,nofail,silent" 93 | enroot-mount --root "${ENROOT_ROOTFS}" - <<< "${issms[id]} ${issms[id]} none x-create=file,bind,ro,nosuid,noexec,private,nofail,silent" 94 | ln -s "$(common::realpath "/sys/class/infiniband_mad/${umads[id]##*/}")" "${ENROOT_ROOTFS}/sys/class/infiniband_mad/${umads[id]##*/}" 95 | ln -s "$(common::realpath "/sys/class/infiniband_mad/${issms[id]##*/}")" "${ENROOT_ROOTFS}/sys/class/infiniband_mad/${issms[id]##*/}" 96 | fi 97 | done 98 | -------------------------------------------------------------------------------- /doc/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## From packages 4 | 5 | Two package flavors are available, standard and hardened. As a rule of thumb, the hardened flavor will be slightly more secure but will suffer from a larger overhead. 6 | 7 | The table below describes each package flavor and their characteristics: 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
FlavorPackageDescription
Standardenroot 22 |

Main utility, helper binaries and standard configuration files.

23 |
    24 |
  • Open file descriptors are inherited
  • 25 |
  • Spectre variant 2 (IBPB/STIBP) mitigations are disabled
  • 26 |
  • Spectre variant 4 (SSBD) mitigations are disabled
  • 27 |
28 |
enroot+capsGrants extra capabilities to unprivileged users which allows
them to import and convert container images.
Hardenedenroot-hardenedMain utility, helper binaries and standard configuration files.
enroot-hardened+capsGrants extra capabilities to unprivileged users which allows
them to import and convert container images.
45 | 46 | #### Standard flavor 47 | 48 | ```sh 49 | # Debian-based distributions 50 | arch=$(dpkg --print-architecture) 51 | curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot_4.0.1-1_${arch}.deb 52 | curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot+caps_4.0.1-1_${arch}.deb # optional 53 | sudo apt install -y ./*.deb 54 | 55 | # RHEL-based distributions 56 | arch=$(uname -m) 57 | sudo dnf install -y epel-release # required on some distributions 58 | sudo dnf install -y https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-4.0.1-1.el8.${arch}.rpm 59 | sudo dnf install -y https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot+caps-4.0.1-1.el8.${arch}.rpm # optional 60 | ``` 61 | 62 | #### Hardened flavor 63 | 64 | ```sh 65 | # Debian-based distributions 66 | arch=$(dpkg --print-architecture) 67 | curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-hardened_4.0.1-1_${arch}.deb 68 | curl -fSsL -O https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-hardened+caps_4.0.1-1_${arch}.deb # optional 69 | sudo apt install -y ./*.deb 70 | 71 | # RHEL-based distributions 72 | arch=$(uname -m) 73 | sudo dnf install -y epel-release # required on some distributions 74 | sudo dnf install -y https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-hardened-4.0.1-1.el8.${arch}.rpm 75 | sudo dnf install -y https://github.com/NVIDIA/enroot/releases/download/v4.0.1/enroot-hardened+caps-4.0.1-1.el8.${arch}.rpm # optional 76 | ``` 77 | 78 | ## From source 79 | 80 | Install the build dependencies and clone the repository: 81 | ```sh 82 | # Debian-based distributions 83 | sudo apt install -y git gcc make libcap2-bin libtool automake libmd-dev 84 | 85 | # RHEL-based distributions: 86 | sudo dnf install -y git gcc make libcap libtool automake libmd-devel 87 | 88 | # Archlinux-based distributions: 89 | sudo pacman --noconfirm -S git gcc make libtool automake libmd 90 | 91 | git clone --recurse-submodules https://github.com/NVIDIA/enroot.git 92 | ``` 93 | 94 | Install the runtime dependencies: 95 | ```sh 96 | # Debian-based distributions 97 | sudo apt install -y curl gawk jq squashfs-tools parallel 98 | sudo apt install -y fuse-overlayfs libnvidia-container-tools pigz squashfuse # optional 99 | 100 | # RHEL-based distributions 101 | sudo dnf install -y epel-release # required on some distributions 102 | sudo dnf install -y jq squashfs-tools parallel 103 | sudo dnf install -y fuse-overlayfs libnvidia-container-tools pigz squashfuse # optional 104 | 105 | # Archlinux-based distributions 106 | sudo pacman --noconfirm -S jq parallel squashfs-tools 107 | sudo pacman --noconfirm -S fuse-overlayfs libnvidia-container-tools pigz squashfuse # optional 108 | ``` 109 | 110 | Build and install Enroot: 111 | ```sh 112 | cd enroot 113 | sudo make install 114 | ``` 115 | 116 | In order to allow unprivileged users to import images: 117 | ```sh 118 | sudo make setcap 119 | ``` 120 | -------------------------------------------------------------------------------- /doc/cmd/start.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | ``` 3 | Usage: enroot start [options] [--] NAME|IMAGE [COMMAND] [ARG...] 4 | 5 | Start a container and invoke the command script within its root filesystem. 6 | Command and arguments are passed to the script as input parameters. 7 | 8 | In the absence of a command script and if a command was given, it will be executed directly. 9 | Otherwise, an interactive shell will be started within the container. 10 | 11 | Options: 12 | -c, --conf CONFIG Specify a configuration script to run before the container starts 13 | -e, --env KEY[=VAL] Export an environment variable inside the container 14 | --rc SCRIPT Override the command script inside the container 15 | -r, --root Ask to be remapped to root inside the container 16 | -w, --rw Make the container root filesystem writable 17 | -m, --mount FSTAB Perform a mount from the host inside the container (colon-separated) 18 | ``` 19 | 20 | # Description 21 | 22 | Start a container by invoking its command script (or entrypoint), refer to [Image format (/etc/rc)](../image-format.md). 23 | 24 | By default the root filesystem of the container is made read-only unless the `--rw` option has been provided. 25 | The `--root` option can also be provided in order to remap the current user to be root inside the container. 26 | 27 | A configuration script can be specified with `--conf` to perform specific actions before the container starts like mounting files or setting environment variables. 28 | 29 | Mounts and environment variables can also be specified on the command line with `--mount` and `--env`. They follow the same format as described in [Image format (/etc/fstab)](../image-format.md) and [Image format (/etc/environment)](../image-format.md) 30 | with the exception that fstab fields are colon-separated. 31 | 32 | 33 | ### Configuration script 34 | 35 | Configuration scripts are standard bash scripts called before any containerization happened with the command and arguments of the container passed as input parameters. 36 | Configuration parameters can be passed through special comment directives, for example `#ENROOT_REMAP_ROOT=y`. 37 | 38 | One or more of the following functions can be defined: 39 | 40 | | Function | Description | 41 | | ------ | ------ | 42 | | `environ()` | Outputs [environment configuration](../configuration.md#environment-configuration-files) | 43 | | `mounts()` | Outputs [mount configuration](../configuration.md#mount-configuration-files) | 44 | | `hooks()` | A specific instance of [pre-start hook scripts](../configuration.md#pre-start-hook-scripts) | 45 | | `rc()` | Override the command script inside the container (similarly to `--rc`) | 46 | 47 | Here is an example of such configuration: 48 | 49 | ```sh 50 | #ENROOT_REMAP_ROOT=y 51 | 52 | environ() { 53 | # Keep all the environment from the host 54 | env 55 | } 56 | 57 | mounts() { 58 | # Mount the X11 unix-domain socket 59 | echo "/tmp/.X11-unix /tmp/.X11-unix none x-create=dir,bind" 60 | 61 | # Mount the current working directory to /mnt 62 | echo "${PWD} /mnt none bind" 63 | } 64 | 65 | hooks() { 66 | # Set the DISPLAY environment variable if not set 67 | [ -z "${DISPLAY-}" ] && echo "DISPLAY=:0.0" >> ${ENROOT_ENVIRON} 68 | 69 | # Record the date when the container was last started 70 | date > ${ENROOT_ROOTFS}/last_started 71 | } 72 | 73 | rc() { 74 | cat /last_started 75 | exec bash 76 | } 77 | ``` 78 | 79 | ### Starting container images 80 | 81 | Since Linux 4.18, it is now possible to start container images directly without the need to create containers first. 82 | Enroot will attempt to do so if the following programs are installed on the host: 83 | * [fuse-overlayfs](https://github.com/containers/fuse-overlayfs) 84 | * [squashfuse](https://github.com/vasi/squashfuse) 85 | 86 | Note that all changes will be stored in memory and will not persist after the container terminates. 87 | 88 | # Configuration 89 | 90 | | Setting | Default | Description | 91 | | ------ | ------ | ------ | 92 | | `ENROOT_LOGIN_SHELL` | `yes` | Use a login shell to run the container initialization | 93 | | `ENROOT_ROOTFS_WRITABLE` | `no` | Make the container root filesystem writable (same as `--rw`) | 94 | | `ENROOT_REMAP_ROOT` | `no` | Remap the current user to root inside containers (same as `--root`) | 95 | | `ENROOT_ALLOW_SUPERUSER` | `no` | Allow root to retain his superuser privileges inside containers | 96 | 97 | See also [Standard Hooks](../standard-hooks.md) for additional configuration. 98 | 99 | # Example 100 | 101 | ```sh 102 | # Edit a file from the current directory within a CentOS container 103 | $ echo Hello World > foo 104 | $ enroot start --root --rw --env EDITOR --mount .:mnt centos sudoedit /mnt/foo 105 | ``` 106 | 107 | ```sh 108 | # Import a CUDA development image from DockerHub and compile a program locally (Linux >= 4.18) 109 | $ enroot import docker://nvidia/cuda:10.0-devel 110 | $ enroot start --mount .:mnt cuda+devel.sqsh nvcc /mnt/hello-world.cu 111 | ``` 112 | -------------------------------------------------------------------------------- /deps/libbsd/src/fparseln.c: -------------------------------------------------------------------------------- 1 | /* $NetBSD: fparseln.c,v 1.10 2009/10/21 01:07:45 snj Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1997 Christos Zoulas. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #define _DIAGASSERT(t) 36 | 37 | static int isescaped(const char *, const char *, int); 38 | 39 | /* isescaped(): 40 | * Return true if the character in *p that belongs to a string 41 | * that starts in *sp, is escaped by the escape character esc. 42 | */ 43 | static int 44 | isescaped(const char *sp, const char *p, int esc) 45 | { 46 | const char *cp; 47 | size_t ne; 48 | 49 | _DIAGASSERT(sp != NULL); 50 | _DIAGASSERT(p != NULL); 51 | 52 | /* No escape character */ 53 | if (esc == '\0') 54 | return 0; 55 | 56 | /* Count the number of escape characters that precede ours */ 57 | for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne++) 58 | continue; 59 | 60 | /* Return true if odd number of escape characters */ 61 | return (ne & 1) != 0; 62 | } 63 | 64 | 65 | /* fparseln(): 66 | * Read a line from a file parsing continuations ending in \ 67 | * and eliminating trailing newlines, or comments starting with 68 | * the comment char. 69 | */ 70 | char * 71 | fparseln(FILE *fp, size_t *size, size_t *lineno, const char str[3], int flags) 72 | { 73 | static const char dstr[3] = { '\\', '\\', '#' }; 74 | 75 | ssize_t s; 76 | size_t len, ptrlen; 77 | char *buf; 78 | char *ptr, *cp; 79 | int cnt; 80 | char esc, con, nl, com; 81 | 82 | _DIAGASSERT(fp != NULL); 83 | 84 | len = 0; 85 | buf = NULL; 86 | ptrlen = 0; 87 | ptr = NULL; 88 | cnt = 1; 89 | 90 | if (str == NULL) 91 | str = dstr; 92 | 93 | esc = str[0]; 94 | con = str[1]; 95 | com = str[2]; 96 | /* 97 | * XXX: it would be cool to be able to specify the newline character, 98 | * getdelim(3) does let us, but supporting it would diverge from BSDs. 99 | */ 100 | nl = '\n'; 101 | 102 | flockfile(fp); 103 | 104 | while (cnt) { 105 | cnt = 0; 106 | 107 | if (lineno) 108 | (*lineno)++; 109 | 110 | s = getline(&ptr, &ptrlen, fp); 111 | if (s < 0) 112 | break; 113 | 114 | if (s && com) { /* Check and eliminate comments */ 115 | for (cp = ptr; cp < ptr + s; cp++) 116 | if (*cp == com && !isescaped(ptr, cp, esc)) { 117 | s = cp - ptr; 118 | cnt = s == 0 && buf == NULL; 119 | break; 120 | } 121 | } 122 | 123 | if (s && nl) { /* Check and eliminate newlines */ 124 | cp = &ptr[s - 1]; 125 | 126 | if (*cp == nl) 127 | s--; /* forget newline */ 128 | } 129 | 130 | if (s && con) { /* Check and eliminate continuations */ 131 | cp = &ptr[s - 1]; 132 | 133 | if (*cp == con && !isescaped(ptr, cp, esc)) { 134 | s--; /* forget continuation char */ 135 | cnt = 1; 136 | } 137 | } 138 | 139 | if (s == 0) { 140 | /* 141 | * nothing to add, skip realloc except in case 142 | * we need a minimal buf to return an empty line 143 | */ 144 | if (cnt || buf != NULL) 145 | continue; 146 | } 147 | 148 | if ((cp = realloc(buf, len + s + 1)) == NULL) { 149 | funlockfile(fp); 150 | free(buf); 151 | free(ptr); 152 | return NULL; 153 | } 154 | buf = cp; 155 | 156 | (void) memcpy(buf + len, ptr, s); 157 | len += s; 158 | buf[len] = '\0'; 159 | } 160 | 161 | funlockfile(fp); 162 | free(ptr); 163 | 164 | if ((flags & FPARSELN_UNESCALL) != 0 && esc && buf != NULL && 165 | strchr(buf, esc) != NULL) { 166 | ptr = cp = buf; 167 | while (cp[0] != '\0') { 168 | int skipesc; 169 | 170 | while (cp[0] != '\0' && cp[0] != esc) 171 | *ptr++ = *cp++; 172 | if (cp[0] == '\0' || cp[1] == '\0') 173 | break; 174 | 175 | skipesc = 0; 176 | if (cp[1] == com) 177 | skipesc += (flags & FPARSELN_UNESCCOMM); 178 | if (cp[1] == con) 179 | skipesc += (flags & FPARSELN_UNESCCONT); 180 | if (cp[1] == esc) 181 | skipesc += (flags & FPARSELN_UNESCESC); 182 | if (cp[1] != com && cp[1] != con && cp[1] != esc) 183 | skipesc = (flags & FPARSELN_UNESCREST); 184 | 185 | if (skipesc) 186 | cp++; 187 | else 188 | *ptr++ = *cp++; 189 | *ptr++ = *cp++; 190 | } 191 | *ptr = '\0'; 192 | len = strlen(buf); 193 | } 194 | 195 | if (size) 196 | *size = len; 197 | return buf; 198 | } 199 | -------------------------------------------------------------------------------- /bin/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define NORETURN __attribute__((noreturn)) 34 | #define MAYBE_UNUSED __attribute__((unused)) 35 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x)) 36 | #define SAVE_ERRNO(x) __extension__ ({ int save_errno = errno; x; errno = save_errno; }) 37 | #define SHIFT_ARGS(x) argv[x] = argv[0]; argv += x; argc -= x 38 | 39 | struct capabilities_v3 { 40 | struct __user_cap_header_struct hdr; 41 | struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; 42 | }; 43 | 44 | extern int capset(cap_user_header_t, cap_user_data_t); 45 | extern int capget(cap_user_header_t, const cap_user_data_t); 46 | 47 | #define CAP_INIT_V3(caps) *caps = (struct capabilities_v3){{_LINUX_CAPABILITY_VERSION_3, 0}, {{0}}} 48 | #define CAP_SET(caps, set, n) (caps)->data[n / 32].set |= (1u << n % 32) 49 | #define CAP_CLR(caps, set, n) (caps)->data[n / 32].set &= ~(1u << n % 32) 50 | #define CAP_ISSET(caps, set, n) (caps)->data[n / 32].set & (1u << n % 32) 51 | #define CAP_FOREACH(caps, n) for (size_t n = 0; n < 32 * ARRAY_SIZE((caps)->data); ++n) 52 | #define CAP_COPY(caps, dst, src) for (size_t i = 0; i < ARRAY_SIZE((caps)->data); ++i) \ 53 | (caps)->data[i].dst = (caps)->data[i].src 54 | 55 | static bool debug_flag; 56 | 57 | static void __attribute__((constructor)) 58 | init(void) 59 | { 60 | debug_flag = (getenv("ENROOT_DEBUG") != NULL); 61 | } 62 | 63 | static inline void __attribute__((format(printf, 1, 2), nonnull(1))) 64 | warndbg(const char *fmt, ...) 65 | { 66 | va_list ap; 67 | 68 | if (debug_flag) { 69 | va_start(ap, fmt); 70 | vwarn(fmt, ap); 71 | va_end(ap); 72 | } 73 | } 74 | 75 | static inline bool 76 | strnull(const char *str) 77 | { 78 | return (str == NULL || *str == '\0'); 79 | } 80 | 81 | static inline char * 82 | strtrim(const char *str, const char *prefix) 83 | { 84 | size_t len; 85 | 86 | len = strlen(prefix); 87 | if (!strncmp(str, prefix, len)) 88 | return ((char *)str + len); 89 | return ((char *)str); 90 | } 91 | 92 | static inline int 93 | unshare_userns(bool remap_root) 94 | { 95 | char *uidmap = NULL, *gidmap = NULL; 96 | int rv = -1; 97 | 98 | if (asprintf(&gidmap, "%u %u 1", remap_root ? 0 : getegid(), getegid()) < 0) { 99 | gidmap = NULL; 100 | goto err; 101 | } 102 | if (asprintf(&uidmap, "%u %u 1", remap_root ? 0 : geteuid(), geteuid()) < 0) { 103 | uidmap = NULL; 104 | goto err; 105 | } 106 | 107 | if (unshare(CLONE_NEWUSER) < 0) 108 | goto err; 109 | 110 | struct { const char *path, *data; } procf[] = { 111 | {"/proc/self/setgroups", "deny"}, 112 | {"/proc/self/gid_map", gidmap}, 113 | {"/proc/self/uid_map", uidmap}, 114 | }; 115 | for (int fd, i = 0; i < (int)ARRAY_SIZE(procf); ++i) { 116 | if ((fd = open(procf[i].path, O_WRONLY)) < 0) 117 | goto err; 118 | if (write(fd, procf[i].data, strlen(procf[i].data)) < 0) { 119 | SAVE_ERRNO(close(fd)); 120 | goto err; 121 | } 122 | if (close(fd) < 0) 123 | goto err; 124 | } 125 | rv = 0; 126 | 127 | err: 128 | free(gidmap); 129 | free(uidmap); 130 | return (rv); 131 | } 132 | 133 | static inline bool 134 | envvar_valid(const char *str) 135 | { 136 | if (strchr(str, '=') == NULL) 137 | return (false); 138 | if (!isalpha(*str) && *str != '_') 139 | return (false); 140 | while (*++str != '=') { 141 | if (!isalnum(*str) && *str != '_') 142 | return (false); 143 | } 144 | return (true); 145 | } 146 | 147 | static inline int 148 | load_environment(const char *envfile) 149 | { 150 | FILE *fs; 151 | char *buf = NULL, *ptr; 152 | size_t n = 0; 153 | 154 | if ((fs = fopen(envfile, "r")) == NULL) 155 | return (-1); 156 | if (clearenv() < 0) 157 | return (-1); 158 | while (getline(&buf, &n, fs) >= 0) { 159 | buf[strcspn(buf, "\n")] = '\0'; 160 | if (!envvar_valid(buf)) 161 | continue; 162 | 163 | ptr = strchr(buf, '='); 164 | *ptr++ = '\0'; 165 | if (setenv(buf, ptr, 1) < 0) 166 | goto err; 167 | } 168 | if (!feof(fs)) 169 | goto err; 170 | if (fclose(fs) < 0) 171 | goto err; 172 | free(buf); 173 | return (0); 174 | 175 | err: 176 | free(buf); 177 | SAVE_ERRNO(fclose(fs)); 178 | return (-1); 179 | } 180 | -------------------------------------------------------------------------------- /bin/enroot-aufs2ovlfs.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #define _GNU_SOURCE 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "common.h" 32 | 33 | #define AUFS_WH_PREFIX ".wh." 34 | #define AUFS_WH_OPQ_SUFFIX ".opq" 35 | #define AUFS_WH_PREFIX_LEN (sizeof(AUFS_WH_PREFIX) - 1) 36 | 37 | static struct capabilities_v3 caps; 38 | 39 | static void 40 | init_capabilities(void) 41 | { 42 | CAP_INIT_V3(&caps); 43 | 44 | if (capget(&caps.hdr, caps.data) < 0) 45 | err(EXIT_FAILURE, "failed to get capabilities"); 46 | 47 | CAP_FOREACH(&caps, n) { 48 | if (n == CAP_DAC_READ_SEARCH || n == CAP_DAC_OVERRIDE) 49 | continue; 50 | CAP_CLR(&caps, permitted, n); 51 | CAP_CLR(&caps, effective, n); 52 | CAP_CLR(&caps, inheritable, n); 53 | } 54 | CAP_SET(&caps, permitted, CAP_MKNOD); 55 | CAP_SET(&caps, permitted, CAP_SYS_ADMIN); 56 | 57 | if (capset(&caps.hdr, caps.data) < 0) 58 | err(EXIT_FAILURE, "failed to set capabilities"); 59 | } 60 | 61 | static int 62 | do_mknod(const char *path) 63 | { 64 | CAP_SET(&caps, effective, CAP_MKNOD); 65 | if (capset(&caps.hdr, caps.data) < 0) 66 | return (-1); 67 | 68 | if (mknod(path, S_IFCHR|0600, makedev(0, 0)) < 0) 69 | return (-1); 70 | 71 | CAP_CLR(&caps, effective, CAP_MKNOD); 72 | if (capset(&caps.hdr, caps.data) < 0) 73 | return (-1); 74 | return (0); 75 | } 76 | 77 | static int 78 | do_setxattr(const char *path) 79 | { 80 | CAP_SET(&caps, effective, CAP_SYS_ADMIN); 81 | if (capset(&caps.hdr, caps.data) < 0) 82 | return (-1); 83 | 84 | if (setxattr(path, "trusted.overlay.opaque", "y", 1, XATTR_CREATE) < 0) 85 | return (-1); 86 | 87 | if (setxattr(path, "user.overlay.opaque", "y", 1, XATTR_CREATE) < 0) 88 | return (-1); 89 | 90 | CAP_CLR(&caps, effective, CAP_SYS_ADMIN); 91 | if (capset(&caps.hdr, caps.data) < 0) 92 | return (-1); 93 | return (0); 94 | } 95 | 96 | static int 97 | handle_whiteout(const char *path, MAYBE_UNUSED const struct stat *sb, int type, MAYBE_UNUSED struct FTW *ftwbuf) 98 | { 99 | int flag = (type == FTW_DP || type == FTW_DNR) ? AT_REMOVEDIR : 0; 100 | const char *filename = path + ftwbuf->base; 101 | char *whiteout; 102 | 103 | if (!strcmp(filename, AUFS_WH_PREFIX AUFS_WH_PREFIX AUFS_WH_OPQ_SUFFIX)) { 104 | if (unlinkat(-1, path, flag) < 0) 105 | err(EXIT_FAILURE, "failed to remove opaque aufs whiteout: %s", path); 106 | if ((whiteout = strdup(path)) == NULL) 107 | err(EXIT_FAILURE, "failed to allocate memory"); 108 | whiteout[ftwbuf->base] = '\0'; 109 | if (do_setxattr(whiteout) < 0) 110 | err(EXIT_FAILURE, "failed to create opaque ovlfs whiteout: %s", whiteout); 111 | free(whiteout); 112 | return (0); 113 | } 114 | 115 | if (!strncmp(filename, AUFS_WH_PREFIX AUFS_WH_PREFIX, 2 * AUFS_WH_PREFIX_LEN)) 116 | errx(EXIT_FAILURE, "unsupported aufs whiteout: %s", path); 117 | 118 | if (!strncmp(filename, AUFS_WH_PREFIX, AUFS_WH_PREFIX_LEN)) { 119 | if (unlinkat(-1, path, flag) < 0) 120 | err(EXIT_FAILURE, "failed to remove aufs whiteout: %s", path); 121 | if ((whiteout = strdup(path)) == NULL) 122 | err(EXIT_FAILURE, "failed to allocate memory"); 123 | strcpy(whiteout + ftwbuf->base, filename + AUFS_WH_PREFIX_LEN); 124 | if (do_mknod(whiteout) < 0) 125 | err(EXIT_FAILURE, "failed to create ovlfs whiteout: %s", whiteout); 126 | free(whiteout); 127 | } 128 | return (0); 129 | } 130 | 131 | int 132 | main(int argc, char *argv[]) 133 | { 134 | char path[PATH_MAX]; 135 | 136 | if (argc < 2) { 137 | printf("Usage: %s DIR\n", argv[0]); 138 | return (0); 139 | } 140 | 141 | init_capabilities(); 142 | 143 | /* 144 | * Ideally we would like to do this as an unprivileged user, however setting trusted xattrs is currently 145 | * gated by CAP_SYS_ADMIN in the init userns, and mknod on userns-owned filesystems (Linux 4.19) hasn't 146 | * been picked up by mainstream distributions. 147 | */ 148 | #if 0 149 | if (unshare_userns(false) < 0) 150 | err(EXIT_FAILURE, "failed to create user namespace"); 151 | #endif 152 | if (realpath(argv[1], path) == NULL) 153 | err(EXIT_FAILURE, "failed to resolve path: %s", argv[1]); 154 | if (nftw(path, handle_whiteout, FOPEN_MAX, FTW_MOUNT|FTW_PHYS|FTW_DEPTH) < 0) /* FTW_CHDIR is not supported on Musl. */ 155 | err(EXIT_FAILURE, "failed to walk directory: %s", path); 156 | return (0); 157 | } 158 | -------------------------------------------------------------------------------- /deps/libbsd/src/closefrom.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-License-Identifier: ISC 3 | * 4 | * Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018 5 | * Todd C. Miller 6 | * 7 | * Permission to use, copy, modify, and distribute this software for any 8 | * purpose with or without fee is hereby granted, provided that the above 9 | * copyright notice and this permission notice appear in all copies. 10 | * 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | */ 19 | 20 | #ifdef __linux__ 21 | # include 22 | # if defined(__NR_close_range) && !defined(SYS_close_range) 23 | # define SYS_close_range __NR_close_range 24 | # endif 25 | #endif 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #ifdef HAVE_PSTAT_GETPROC 32 | # include 33 | # include 34 | #else 35 | # ifdef HAVE_DIRENT_H 36 | # include 37 | # define NAMLEN(dirent) strlen((dirent)->d_name) 38 | # else 39 | # define dirent direct 40 | # define NAMLEN(dirent) (dirent)->d_namlen 41 | # ifdef HAVE_SYS_NDIR_H 42 | # include 43 | # endif 44 | # ifdef HAVE_SYS_DIR_H 45 | # include 46 | # endif 47 | # ifdef HAVE_NDIR_H 48 | # include 49 | # endif 50 | # endif 51 | #endif 52 | 53 | #ifndef OPEN_MAX 54 | # define OPEN_MAX 256 55 | #endif 56 | 57 | static inline void 58 | closefrom_close(int fd) 59 | { 60 | #ifdef __APPLE__ 61 | /* Avoid potential libdispatch crash when we close its fds. */ 62 | (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 63 | #else 64 | (void)close(fd); 65 | #endif 66 | } 67 | 68 | #if defined(__linux__) && defined(SYS_close_range) 69 | static inline int 70 | sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags) 71 | { 72 | return syscall(SYS_close_range, fd, max_fd, flags); 73 | } 74 | #endif 75 | 76 | /* 77 | * Close all file descriptors greater than or equal to lowfd. 78 | * This is the expensive (fallback) method. 79 | */ 80 | static void 81 | closefrom_fallback(int lowfd) 82 | { 83 | long fd, maxfd; 84 | 85 | /* 86 | * Fall back on sysconf(_SC_OPEN_MAX) or getdtablesize(). This is 87 | * equivalent to checking the RLIMIT_NOFILE soft limit. It is 88 | * possible for there to be open file descriptors past this limit 89 | * but there is not much we can do about that since the hard limit 90 | * may be RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems). 91 | */ 92 | #ifdef HAVE_SYSCONF 93 | maxfd = sysconf(_SC_OPEN_MAX); 94 | #else 95 | maxfd = getdtablesize(); 96 | #endif /* HAVE_SYSCONF */ 97 | if (maxfd < OPEN_MAX) 98 | maxfd = OPEN_MAX; 99 | 100 | /* Make sure we did not get RLIM_INFINITY as the upper limit. */ 101 | if (maxfd > INT_MAX) 102 | maxfd = INT_MAX; 103 | 104 | for (fd = lowfd; fd < maxfd; fd++) 105 | closefrom_close(fd); 106 | } 107 | 108 | #if defined(HAVE_PSTAT_GETPROC) 109 | static int 110 | closefrom_pstat(int lowfd) 111 | { 112 | struct pst_status pst; 113 | int fd; 114 | 115 | /* 116 | * EOVERFLOW is not a fatal error for the fields we use. 117 | * See the "EOVERFLOW Error" section of pstat_getvminfo(3). 118 | */ 119 | if (pstat_getproc(&pst, sizeof(pst), 0, getpid()) != -1 || 120 | errno == EOVERFLOW) { 121 | for (fd = lowfd; fd <= pst.pst_highestfd; fd++) 122 | (void)close(fd); 123 | return 0; 124 | } 125 | return -1; 126 | } 127 | #elif defined(HAVE_DIRFD) 128 | static int 129 | closefrom_procfs(int lowfd) 130 | { 131 | const char *path; 132 | DIR *dirp; 133 | struct dirent *dent; 134 | int *fd_array = NULL; 135 | int fd_array_used = 0; 136 | int fd_array_size = 0; 137 | int ret = 0; 138 | int i; 139 | 140 | /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */ 141 | # ifdef __APPLE__ 142 | path = "/dev/fd"; 143 | # else 144 | path = "/proc/self/fd"; 145 | # endif 146 | dirp = opendir(path); 147 | if (dirp == NULL) 148 | return -1; 149 | 150 | while ((dent = readdir(dirp)) != NULL) { 151 | const char *errstr; 152 | int fd; 153 | 154 | fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr); 155 | if (errstr != NULL || fd == dirfd(dirp)) 156 | continue; 157 | 158 | if (fd_array_used >= fd_array_size) { 159 | int *ptr; 160 | 161 | if (fd_array_size > 0) 162 | fd_array_size *= 2; 163 | else 164 | fd_array_size = 32; 165 | 166 | ptr = reallocarray(fd_array, fd_array_size, sizeof(int)); 167 | if (ptr == NULL) { 168 | ret = -1; 169 | break; 170 | } 171 | fd_array = ptr; 172 | } 173 | 174 | fd_array[fd_array_used++] = fd; 175 | } 176 | 177 | for (i = 0; i < fd_array_used; i++) 178 | closefrom_close(fd_array[i]); 179 | 180 | free(fd_array); 181 | (void)closedir(dirp); 182 | 183 | return ret; 184 | } 185 | #endif 186 | 187 | /* 188 | * Close all file descriptors greater than or equal to lowfd. 189 | * We try the fast way first, falling back on the slow method. 190 | */ 191 | void 192 | closefrom(int lowfd) 193 | { 194 | if (lowfd < 0) 195 | lowfd = 0; 196 | 197 | /* Try the fast methods first, if possible. */ 198 | #if defined(HAVE_FCNTL_CLOSEM) 199 | if (fcntl(lowfd, F_CLOSEM, 0) != -1) 200 | return; 201 | #endif /* HAVE_FCNTL_CLOSEM */ 202 | #if defined(__linux__) && defined(SYS_close_range) 203 | if (sys_close_range(lowfd, UINT_MAX, 0) == 0) 204 | return; 205 | #endif 206 | 207 | #if defined(HAVE_PSTAT_GETPROC) 208 | if (closefrom_pstat(lowfd) != -1) 209 | return; 210 | #elif defined(HAVE_DIRFD) 211 | if (closefrom_procfs(lowfd) != -1) 212 | return; 213 | #endif /* HAVE_DIRFD */ 214 | 215 | /* Do things the slow way. */ 216 | closefrom_fallback(lowfd); 217 | } 218 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | prefix ?= /usr/local 2 | exec_prefix ?= $(prefix) 3 | bindir ?= $(exec_prefix)/bin 4 | libdir ?= $(exec_prefix)/lib 5 | sysconfdir ?= $(prefix)/etc 6 | datarootdir ?= $(prefix)/share 7 | datadir ?= $(datarootdir) 8 | 9 | override DESTDIR := $(abspath $(DESTDIR)) 10 | 11 | BINDIR = $(DESTDIR)$(bindir) 12 | LIBDIR = $(DESTDIR)$(libdir)/enroot 13 | SYSCONFDIR = $(DESTDIR)$(sysconfdir)/enroot 14 | DATADIR = $(DESTDIR)$(datadir)/enroot 15 | 16 | VERSION := 4.0.1 17 | PACKAGE ?= enroot 18 | ARCH ?= $(shell uname -m) 19 | DEBUG ?= 20 | CROSS_COMPILE ?= 21 | FORCE_GLIBC ?= 22 | DO_RELEASE ?= 23 | 24 | USERNAME := NVIDIA CORPORATION 25 | EMAIL := cudatools@nvidia.com 26 | 27 | BIN := enroot 28 | 29 | SRCS := src/common.sh \ 30 | src/bundle.sh \ 31 | src/docker.sh \ 32 | src/runtime.sh 33 | 34 | DEPS := deps/dist/makeself/bin/enroot-makeself \ 35 | 36 | UTILS := bin/enroot-aufs2ovlfs \ 37 | bin/enroot-mksquashovlfs \ 38 | bin/enroot-mount \ 39 | bin/enroot-switchroot \ 40 | bin/enroot-nsenter 41 | 42 | CONFIGFILE := enroot.conf 43 | CONFIG := conf/$(CONFIGFILE) 44 | CONFIGINFO := conf/$(CONFIGFILE).d/README 45 | 46 | HOOKS := conf/hooks/10-aptfix.sh \ 47 | conf/hooks/10-cgroups.sh \ 48 | conf/hooks/10-devices.sh \ 49 | conf/hooks/10-home.sh \ 50 | conf/hooks/10-localtime.sh \ 51 | conf/hooks/10-shadow.sh \ 52 | conf/hooks/98-nvidia.sh \ 53 | conf/hooks/99-mellanox.sh \ 54 | 55 | CONFIG_EXTRA := conf/bash_completion \ 56 | conf/apparmor.profile 57 | 58 | HOOKS_EXTRA := conf/hooks/extra/50-slurm-pmi.sh \ 59 | conf/hooks/extra/50-slurm-pytorch.sh \ 60 | conf/hooks/extra/50-mig-config.sh \ 61 | conf/hooks/extra/50-sharp.sh 62 | 63 | MOUNTS := conf/mounts/10-system.fstab \ 64 | conf/mounts/20-config.fstab 65 | 66 | MOUNTS_EXTRA := conf/mounts/extra/30-lxcfs.fstab 67 | 68 | ENVIRON := conf/environ/10-terminal.env 69 | 70 | .PHONY: all install uninstall clean dist deps depsclean mostlyclean deb distclean release 71 | .DEFAULT_GOAL := all 72 | 73 | CPPFLAGS := -D_FORTIFY_SOURCE=2 -isystem $(CURDIR)/deps/dist/libbsd/include -isystem $(CURDIR)/deps/dist/linux/include $(CPPFLAGS) 74 | CFLAGS := -std=c99 -O2 -fstack-protector -fPIE -pedantic \ 75 | -Wall -Wextra -Wcast-align -Wpointer-arith -Wmissing-prototypes -Wnonnull \ 76 | -Wwrite-strings -Wlogical-op -Wformat=2 -Wmissing-format-attribute -Winit-self -Wshadow \ 77 | -Wstrict-prototypes -Wunreachable-code -Wconversion -Wsign-conversion $(CFLAGS) 78 | LDFLAGS := -Wl,-zrelro -Wl,-znow -Wl,-zdefs -Wl,--as-needed -Wl,--gc-sections -L$(CURDIR)/deps/dist/libbsd $(LDFLAGS) 79 | LDLIBS := -l:libbsd.a 80 | 81 | ifdef DEBUG 82 | CFLAGS += -g3 -fno-omit-frame-pointer -fno-common -fsanitize=undefined,address,leak 83 | LDLIBS += -lubsan 84 | else 85 | CFLAGS += -s 86 | endif 87 | 88 | # Required for Musl on PPC64 89 | ifeq "$(ARCH:power%=p%)" "ppc64le" 90 | CFLAGS += -mlong-double-64 91 | endif 92 | 93 | # Infer the compiler used for cross compilation if not specified. 94 | ifeq "$(origin CC)" "default" 95 | CC := $(shell readlink -f $(shell sh -c 'command -v $(CC)')) 96 | ifdef CROSS_COMPILE 97 | CC := $(CROSS_COMPILE)$(notdir $(CC)) 98 | endif 99 | endif 100 | 101 | # Required for Debuild 102 | ifeq "$(ARCH:power%=p%)" "ppc64le" 103 | HOST_TYPE = $(shell $(CC) -dumpmachine) 104 | else 105 | HOST_TYPE = $(ARCH)-linux-gnu 106 | endif 107 | 108 | export CC ARCH CROSS_COMPILE 109 | 110 | # Compile the utilities statically against musl libc. 111 | ifndef FORCE_GLIBC 112 | ifneq (,$(findstring gcc, $(notdir $(CC)))) 113 | $(UTILS): override CC := $(CURDIR)/deps/dist/musl/bin/musl-gcc 114 | $(UTILS): LDFLAGS += -pie -static-pie 115 | else ifneq (,$(findstring clang, $(notdir $(CC)))) 116 | $(UTILS): override CC := $(CURDIR)/deps/dist/musl/bin/musl-clang 117 | $(UTILS): LDFLAGS += -pie -static-pie 118 | else 119 | $(error MUSL CC wrapper not found for $(CC)) 120 | endif 121 | endif 122 | 123 | $(BIN) $(CONFIG): %: %.in 124 | sed -e 's;@sysconfdir@;$(SYSCONFDIR);' \ 125 | -e 's;@libdir@;$(LIBDIR);' \ 126 | -e 's;@version@;$(VERSION);' $< > $@ 127 | 128 | $(DEPS) $(UTILS): | deps 129 | 130 | all: $(BIN) $(CONFIG) $(DEPS) $(UTILS) 131 | 132 | deps: 133 | -git submodule update --init 134 | $(MAKE) -C deps 135 | 136 | depsclean: 137 | $(MAKE) -C deps clean 138 | 139 | install: all 140 | install -d -m 755 $(SYSCONFDIR) $(LIBDIR) $(BINDIR) $(DATADIR) 141 | install -d -m 755 $(addprefix $(SYSCONFDIR)/, environ.d mounts.d hooks.d $(CONFIGFILE).d) 142 | install -d -m 755 $(addprefix $(DATADIR)/, environ.d mounts.d hooks.d) 143 | install -m 644 $(ENVIRON) $(SYSCONFDIR)/environ.d 144 | install -m 644 $(MOUNTS) $(SYSCONFDIR)/mounts.d 145 | install -m 755 $(HOOKS) $(SYSCONFDIR)/hooks.d 146 | install -m 755 $(HOOKS_EXTRA) $(DATADIR)/hooks.d 147 | install -m 644 $(MOUNTS_EXTRA) $(DATADIR)/mounts.d 148 | install -m 644 $(CONFIG_EXTRA) $(DATADIR) 149 | install -m 644 $(CONFIG) $(SYSCONFDIR) 150 | install -m 644 $(CONFIGINFO) $(SYSCONFDIR)/$(CONFIGFILE).d 151 | install -m 644 $(SRCS) $(LIBDIR) 152 | install -m 755 $(BIN) $(UTILS) $(DEPS) $(BINDIR) 153 | 154 | uninstall: 155 | $(RM) $(addprefix $(BINDIR)/, $(notdir $(BIN)) $(notdir $(UTILS)) $(notdir $(DEPS))) 156 | $(RM) -r $(LIBDIR) $(SYSCONFDIR) $(DATADIR) 157 | 158 | mostlyclean: 159 | $(RM) $(BIN) $(CONFIG) $(UTILS) 160 | 161 | clean: mostlyclean depsclean 162 | 163 | dist: DESTDIR := enroot_$(VERSION) 164 | dist: install 165 | mkdir -p dist 166 | sed -i 's;$(DESTDIR);;' $(BINDIR)/$(BIN) $(SYSCONFDIR)/$(notdir $(CONFIG)) 167 | tar --numeric-owner --owner=0 --group=0 -C $(dir $(DESTDIR)) -caf dist/$(DESTDIR)_$(ARCH).tar.xz $(notdir $(DESTDIR)) 168 | $(RM) -r $(DESTDIR) 169 | 170 | distclean: clean 171 | $(RM) -r dist 172 | 173 | setcap: 174 | setcap cap_sys_admin+pe $(BINDIR)/enroot-mksquashovlfs 175 | setcap cap_sys_admin,cap_mknod+pe $(BINDIR)/enroot-aufs2ovlfs 176 | 177 | deb: export DEBFULLNAME := $(USERNAME) 178 | deb: export DEBEMAIL := $(EMAIL) 179 | deb: clean 180 | $(RM) -r debian 181 | dh_make -y -d -s -c apache -t $(CURDIR)/pkg/deb -p $(PACKAGE)_$(VERSION) --createorig && cp -ar pkg/deb/source debian 182 | debuild --preserve-env -us -uc -G -i -tc --host-type $(HOST_TYPE) 183 | mkdir -p dist && find .. -maxdepth 1 -type f -name '$(PACKAGE)*' -exec mv {} dist \; 184 | $(RM) -r debian 185 | 186 | rpm: clean 187 | mkdir -p dist 188 | rpmbuild --target=$(ARCH) --clean -ba -D"_topdir $(CURDIR)/pkg/rpm" -D"PACKAGE $(PACKAGE)" -D"VERSION $(VERSION)" -D"USERNAME $(USERNAME)" -D"EMAIL $(EMAIL)" pkg/rpm/SPECS/* 189 | -rpmlint pkg/rpm/RPMS/* 190 | $(RM) -r $(addprefix pkg/rpm/, BUILDROOT SOURCES) 191 | 192 | release: clean 193 | ./pkg/release/docker-release-build.sh 194 | ./pkg/release/docker-run-build.sh 195 | find dist -type f 196 | -------------------------------------------------------------------------------- /deps/libbsd/include/bsd/sys/cdefs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2004-2006, 2009-2011 Guillem Jover 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 3. The name of the author may not be used to endorse or promote products 13 | * derived from this software without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 | * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef __has_include 28 | #define __has_include(x) 1 29 | #endif 30 | #ifndef __has_include_next 31 | #define __has_include_next(x) 1 32 | #endif 33 | #ifndef __has_attribute 34 | #define __has_attribute(x) 0 35 | #endif 36 | /* Clang expands this to 1 if an identifier is *not* reserved. */ 37 | #ifndef __is_identifier 38 | #define __is_identifier(x) 1 39 | #endif 40 | 41 | #ifdef LIBBSD_OVERLAY 42 | /* 43 | * Some libc implementations do not have a , in particular 44 | * musl, try to handle this gracefully. 45 | */ 46 | #if __has_include_next() 47 | #include_next 48 | #endif 49 | #else 50 | #if __has_include() 51 | #include 52 | #endif 53 | #endif 54 | 55 | #ifndef LIBBSD_SYS_CDEFS_H 56 | #define LIBBSD_SYS_CDEFS_H 57 | 58 | #ifndef __BEGIN_DECLS 59 | #ifdef __cplusplus 60 | #define __BEGIN_DECLS extern "C" { 61 | #define __END_DECLS } 62 | #else 63 | #define __BEGIN_DECLS 64 | #define __END_DECLS 65 | #endif 66 | #endif 67 | 68 | /* 69 | * On non-glibc based systems, we cannot unconditionally use the 70 | * __GLIBC_PREREQ macro as it gets expanded before evaluation. 71 | */ 72 | #ifndef __GLIBC_PREREQ 73 | #define __GLIBC_PREREQ(maj, min) 0 74 | #endif 75 | 76 | /* 77 | * Some kFreeBSD headers expect those macros to be set for sanity checks. 78 | */ 79 | #ifndef _SYS_CDEFS_H_ 80 | #define _SYS_CDEFS_H_ 81 | #endif 82 | #ifndef _SYS_CDEFS_H 83 | #define _SYS_CDEFS_H 84 | #endif 85 | 86 | #define LIBBSD_CONCAT(x, y) x ## y 87 | #define LIBBSD_STRING(x) #x 88 | 89 | #ifdef __GNUC__ 90 | #define LIBBSD_GCC_VERSION (__GNUC__ << 8 | __GNUC_MINOR__) 91 | #else 92 | #define LIBBSD_GCC_VERSION 0 93 | #endif 94 | 95 | #if LIBBSD_GCC_VERSION >= 0x0405 || __has_attribute(__deprecated__) 96 | #define LIBBSD_DEPRECATED(x) __attribute__((__deprecated__(x))) 97 | #elif LIBBSD_GCC_VERSION >= 0x0301 98 | #define LIBBSD_DEPRECATED(x) __attribute__((__deprecated__)) 99 | #else 100 | #define LIBBSD_DEPRECATED(x) 101 | #endif 102 | 103 | #if LIBBSD_GCC_VERSION >= 0x0200 || defined(__clang__) 104 | #define LIBBSD_REDIRECT(name, proto, alias) name proto __asm__(LIBBSD_ASMNAME(#alias)) 105 | #endif 106 | #define LIBBSD_ASMNAME(cname) LIBBSD_ASMNAME_PREFIX(__USER_LABEL_PREFIX__, cname) 107 | #define LIBBSD_ASMNAME_PREFIX(prefix, cname) LIBBSD_STRING(prefix) cname 108 | 109 | #ifndef __dead2 110 | # if LIBBSD_GCC_VERSION >= 0x0207 || __has_attribute(__noreturn__) 111 | # define __dead2 __attribute__((__noreturn__)) 112 | # else 113 | # define __dead2 114 | # endif 115 | #endif 116 | 117 | #ifndef __pure2 118 | # if LIBBSD_GCC_VERSION >= 0x0207 || __has_attribute(__const__) 119 | # define __pure2 __attribute__((__const__)) 120 | # else 121 | # define __pure2 122 | # endif 123 | #endif 124 | 125 | #ifndef __packed 126 | # if LIBBSD_GCC_VERSION >= 0x0207 || __has_attribute(__packed__) 127 | # define __packed __attribute__((__packed__)) 128 | # else 129 | # define __packed 130 | # endif 131 | #endif 132 | 133 | #ifndef __aligned 134 | # if LIBBSD_GCC_VERSION >= 0x0207 || __has_attribute(__aligned__) 135 | # define __aligned(x) __attribute__((__aligned__(x))) 136 | # else 137 | # define __aligned(x) 138 | # endif 139 | #endif 140 | 141 | /* Linux headers define a struct with a member names __unused. 142 | * Debian bugs: #522773 (linux), #522774 (libc). 143 | * Disable for now. */ 144 | #if 0 145 | #ifndef __unused 146 | # if LIBBSD_GCC_VERSION >= 0x0300 147 | # define __unused __attribute__((__unused__)) 148 | # else 149 | # define __unused 150 | # endif 151 | #endif 152 | #endif 153 | 154 | #ifndef __printflike 155 | # if LIBBSD_GCC_VERSION >= 0x0300 || __has_attribute(__format__) 156 | # define __printflike(x, y) __attribute((__format__(__printf__, (x), (y)))) 157 | # else 158 | # define __printflike(x, y) 159 | # endif 160 | #endif 161 | 162 | #ifndef __nonnull 163 | # if LIBBSD_GCC_VERSION >= 0x0302 || __has_attribute(__nonnull__) 164 | # define __nonnull(x) __attribute__((__nonnull__(x))) 165 | # else 166 | # define __nonnull(x) 167 | # endif 168 | #endif 169 | 170 | #ifndef __bounded__ 171 | # define __bounded__(x, y, z) 172 | #endif 173 | 174 | /* 175 | * Return the number of elements in a statically-allocated array, 176 | * __x. 177 | */ 178 | #define __arraycount(__x) (sizeof(__x) / sizeof(__x[0])) 179 | 180 | /* 181 | * We define this here since , , and 182 | * require it. 183 | */ 184 | #ifndef __offsetof 185 | # if LIBBSD_GCC_VERSION >= 0x0401 || !__is_identifier(__builtin_offsetof) 186 | # define __offsetof(type, field) __builtin_offsetof(type, field) 187 | # else 188 | # ifndef __cplusplus 189 | # define __offsetof(type, field) \ 190 | ((size_t)(uintptr_t)((const volatile void *)&((type *)0)->field)) 191 | # else 192 | # define __offsetof(type, field) \ 193 | (__offsetof__ (reinterpret_cast \ 194 | (&reinterpret_cast \ 195 | (static_cast (0)->field)))) 196 | # endif 197 | # endif 198 | #endif 199 | 200 | #define __rangeof(type, start, end) \ 201 | (__offsetof(type, end) - __offsetof(type, start)) 202 | 203 | /* 204 | * Given the pointer x to the member m of the struct s, return 205 | * a pointer to the containing structure. When using GCC, we first 206 | * assign pointer x to a local variable, to check that its type is 207 | * compatible with member m. 208 | */ 209 | #ifndef __containerof 210 | # if LIBBSD_GCC_VERSION >= 0x0301 || !__is_identifier(__typeof__) 211 | # define __containerof(x, s, m) ({ \ 212 | const volatile __typeof__(((s *)0)->m) *__x = (x); \ 213 | __DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m)); \ 214 | }) 215 | # else 216 | # define __containerof(x, s, m) \ 217 | __DEQUALIFY(s *, (const volatile char *)(x) - __offsetof(s, m)) 218 | # endif 219 | #endif 220 | 221 | #ifndef __RCSID 222 | # define __RCSID(x) 223 | #endif 224 | 225 | #ifndef __FBSDID 226 | # define __FBSDID(x) 227 | #endif 228 | 229 | #ifndef __RCSID 230 | # define __RCSID(x) 231 | #endif 232 | 233 | #ifndef __RCSID_SOURCE 234 | # define __RCSID_SOURCE(x) 235 | #endif 236 | 237 | #ifndef __SCCSID 238 | # define __SCCSID(x) 239 | #endif 240 | 241 | #ifndef __COPYRIGHT 242 | # define __COPYRIGHT(x) 243 | #endif 244 | 245 | #ifndef __DECONST 246 | #define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var)) 247 | #endif 248 | 249 | #ifndef __DEVOLATILE 250 | #define __DEVOLATILE(type, var) ((type)(uintptr_t)(volatile void *)(var)) 251 | #endif 252 | 253 | #ifndef __DEQUALIFY 254 | #define __DEQUALIFY(type, var) ((type)(uintptr_t)(const volatile void *)(var)) 255 | #endif 256 | 257 | #endif 258 | -------------------------------------------------------------------------------- /src/common.sh: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | [ -v _COMMON_SH_ ] && return || readonly _COMMON_SH_=1 16 | 17 | [ -t 2 ] && readonly TTY_ON=y || readonly TTY_OFF=y 18 | 19 | if [ -v TTY_ON ]; then 20 | if [ -x "$(command -v tput)" ] && [ "$(tput colors)" -ge 15 ]; then 21 | readonly clr=$(tput sgr0) 22 | readonly bold=$(tput bold) 23 | readonly red=$(tput setaf 1) 24 | readonly green=$(tput setaf 2) 25 | readonly yellow=$(tput setaf 3) 26 | readonly blue=$(tput setaf 12) 27 | fi 28 | fi 29 | 30 | common::fmt() { 31 | local -r fmt="$1" str="$2" 32 | 33 | printf "%s%s%s" "${!fmt-}" "${str}" "${clr-}" 34 | } 35 | 36 | common::log() { 37 | local -r lvl="${1-}" msg="${2-}" mod="${3-}" 38 | local prefix= 39 | 40 | if [ -n "${msg}" ]; then 41 | case "${lvl}" in 42 | INFO) prefix=$(common::fmt blue "[INFO]") ;; 43 | WARN) prefix=$(common::fmt yellow "[WARN]") ;; 44 | ERROR) prefix=$(common::fmt red "[ERROR]") ;; 45 | esac 46 | if [ "${msg}" = "-" ]; then 47 | while read -t .01 -r line; do 48 | printf "%s %b\n" "${prefix}" "${line}" >&2 49 | done 50 | else 51 | printf "%s %b\n" "${prefix}" "${msg}" >&2 52 | fi 53 | fi 54 | if [ -v TTY_ON ]; then 55 | if [ $# -eq 0 ] || [ "${mod}" = "NL" ]; then 56 | echo >&2 57 | fi 58 | fi 59 | } 60 | 61 | common::err() { 62 | local -r msg="$1" 63 | 64 | common::log ERROR "${msg}" 65 | exit 1 66 | } 67 | 68 | common::rmall() { 69 | local -r path="$1" 70 | 71 | rm --one-file-system --preserve-root -rf "${path}" 2> /dev/null || \ 72 | { chmod -f -R +wX "${path}" || :; rm --one-file-system --preserve-root -rf "${path}"; } 73 | } 74 | 75 | common::mktmpdir() { 76 | local -r prefix="$1" 77 | 78 | umask 077 79 | mktemp -d -p "${ENROOT_TEMP_PATH-}" "${prefix}.XXXXXXXXXX" 80 | } 81 | 82 | common::read() { 83 | read "$@" || : 84 | } 85 | 86 | common::readstrarray() { 87 | local -r arr="$1" str="$2" 88 | 89 | if [ -n "${str}" ]; then 90 | readarray -t "${arr}" <<< "${str}" 91 | fi 92 | } 93 | 94 | common::chdir() { 95 | cd "$1" 2> /dev/null || common::err "Could not change directory: $1" 96 | } 97 | 98 | common::curl() { 99 | local rv=0 code=0 status= 100 | 101 | exec {stdout}>&1 102 | { code=$(curl -o "/proc/self/fd/${stdout}" -w '%{http_code}' "$@") || rv=$?; } {stdout}>&1 103 | exec {stdout}>&- 104 | 105 | if [ "${code}" -ge 400 ] 2> /dev/null; then 106 | for ign in ${CURL_IGNORE-}; do 107 | [ "${code}" -eq "${ign}" ] && return 108 | done 109 | case "${code}" in 110 | 400) status="Bad Request" ;; 111 | 401) status="Unauthorized" ;; 112 | 402) status="Payment Required" ;; 113 | 403) status="Forbidden" ;; 114 | 404) status="Not Found" ;; 115 | 405) status="Method Not Allowed" ;; 116 | 406) status="Not Acceptable" ;; 117 | 407) status="Proxy Authentication Required" ;; 118 | 408) status="Request Time-out" ;; 119 | 409) status="Conflict" ;; 120 | 410) status="Gone" ;; 121 | 411) status="Length Required" ;; 122 | 412) status="Precondition Failed" ;; 123 | 413) status="Request Entity Too Large" ;; 124 | 414) status="Request-URI Too Large" ;; 125 | 415) status="Unsupported Media Type" ;; 126 | 416) status="Requested range not satisfiable" ;; 127 | 417) status="Expectation Failed" ;; 128 | 500) status="Internal Server Error" ;; 129 | 501) status="Not Implemented" ;; 130 | 502) status="Bad Gateway" ;; 131 | 503) status="Service Unavailable" ;; 132 | 504) status="Gateway Time-out" ;; 133 | esac 134 | common::err "URL ${@: -1} returned error code: ${code} ${status}" 135 | fi 136 | return ${rv} 137 | } 138 | 139 | common::jq() { 140 | if ! jq "$@" 2> /dev/null; then 141 | common::err "Could not process JSON input" 142 | fi 143 | } 144 | 145 | common::realpath() { 146 | local -r path="$1" 147 | local rpath= 148 | 149 | if ! rpath=$(readlink -f "${path}" 2> /dev/null); then 150 | common::err "No such file or directory: ${path}" 151 | fi 152 | printf "%s" "${rpath}" 153 | } 154 | 155 | common::envsubst() { 156 | local -r file="$1" 157 | 158 | [ ! -f "${file}" ] && return 159 | 160 | awk '{ 161 | line=$0 162 | while (match(line, /\${[A-Za-z_][A-Za-z0-9_]*}/)) { 163 | output = substr(line, 1, RSTART - 1) 164 | envvar = substr(line, RSTART, RLENGTH) 165 | 166 | gsub(/\$|{|}/, "", envvar) 167 | printf "%s%s", output, ENVIRON[envvar] 168 | 169 | line = substr(line, RSTART + RLENGTH) 170 | } 171 | print line 172 | }' "${file}" 173 | } 174 | 175 | common::evalnetrc() { 176 | local -r file="$1" 177 | 178 | [ ! -f "${file}" ] && return 179 | 180 | awk '{ 181 | if (NF >= 6 && $6 ~ "^\\$") { 182 | for(i=1; i<6; i++) printf "%s ", $i 183 | for(i=1; i<6; i++) sub("^["FS"]*[^"FS"]+["FS"]+", "", $0) 184 | system("stty sane; echo "$0) 185 | } else 186 | print 187 | }' "${file}" 188 | } 189 | 190 | common::envfmt() { 191 | local -r file="$1" 192 | 193 | # Remove leading spaces. 194 | # Remove comments and empty lines. 195 | # Remove ill-formed environment variables. 196 | # Remove reserved environment variables. 197 | # Remove surrounding quotes. 198 | sed -i -e 's/^[[:space:]]\+//' \ 199 | -e '/^#\|^$/d' \ 200 | -e '/^[[:alpha:]_][[:alnum:]_]*=/!d' \ 201 | -e '/^ENROOT_/d' \ 202 | -e 's/^\([[:alpha:]_][[:alnum:]_]*\)=[\"\x27]\(.*\)[\"\x27][[:space:]]*$/\1=\2/' \ 203 | "${file}" 204 | } 205 | 206 | common::runparts() { 207 | local -r action="$1" suffix="$2" dir="$3" 208 | 209 | shopt -s nullglob 210 | for file in "${dir}"/*"${suffix}"; do 211 | case "${action}" in 212 | list) 213 | printf "%s\n" "${file}" ;; 214 | exec) 215 | if [ -x "${file}" ]; then 216 | "${file}" || common::err "${file} exited with return code $?" 217 | fi 218 | ;; 219 | esac 220 | done 221 | shopt -u nullglob 222 | } 223 | 224 | common::checkcmd() { 225 | for cmd in "$@"; do 226 | command -v "${cmd}" > /dev/null || common::err "Command not found: ${cmd}" 227 | done 228 | } 229 | 230 | common::fixperms() { 231 | local -r path="$1" 232 | 233 | # Some distributions require CAP_DAC_OVERRIDE on several files and directories, fix these. 234 | # See https://bugzilla.redhat.com/show_bug.cgi?id=517575 for some context. 235 | chmod -f -R u+rX "${path}" || : 236 | find "${path}" -maxdepth 15 -type d ! -perm -u=w -exec chmod -f u+w {} \+ || : 237 | } 238 | 239 | common::getpwent() { 240 | local uid= 241 | 242 | read -r x uid x < /proc/self/uid_map 243 | getent passwd "${uid}" 244 | } 245 | 246 | common::getgrent() { 247 | local gid= 248 | 249 | read -r x gid x < /proc/self/gid_map 250 | getent group "${gid}" 251 | } 252 | 253 | common::debarch() { 254 | local -r arch="$1" 255 | 256 | case "${arch}" in 257 | x86_64) 258 | printf "amd64" ;; 259 | aarch64) 260 | printf "arm64" ;; 261 | ppc64le) 262 | printf "ppc64le" ;; 263 | *) 264 | common::err "Unsupported architecture: ${arch}" ;; 265 | esac 266 | } 267 | 268 | common::mountpoint() { 269 | local path="$1" 270 | 271 | path=$(common::realpath "${path}") 272 | while [ -n "${path}" ] && ! mountpoint -q "${path}"; do 273 | path="${path%/*}" 274 | done 275 | printf "%s" "${path:-/}" 276 | } 277 | -------------------------------------------------------------------------------- /pkg/deb/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: enroot 3 | Source: https://github.com/NVIDIA/enroot 4 | 5 | Files: * 6 | Copyright: #YEAR# #USERNAME# <#EMAIL#> 7 | License: Apache-2.0 8 | 9 | Files: debian/* 10 | Copyright: #YEAR# #USERNAME# <#EMAIL#> 11 | License: Apache-2.0 12 | 13 | Files: deps/linux-headers/* 14 | Copyright: 1991-2020 Linus Torvalds, et al 15 | License: GPL-2.0 WITH Linux-syscall-note 16 | 17 | Files: deps/musl/* 18 | Copyright: 2005-2020 Rich Felker, et al 19 | License: MIT 20 | 21 | Files: deps/makeself/* 22 | Copyright: 1998-2018 Stephane Peter 23 | License: GPL-2.0+ 24 | 25 | Files: 26 | deps/libbsd/src/closefrom.c 27 | deps/libbsd/src/strlcat.c 28 | deps/libbsd/src/strlcpy.c 29 | Copyright: 1998, 2004-2005, 2007, 2010, 2012-2015 Todd C. Miller 30 | License: ISC 31 | 32 | Files: deps/libbsd/src/strtoi.c 33 | Copyright: 1990, 1993 The Regents of the University of California 34 | License: BSD-3-Clause-Regents 35 | 36 | Files: 37 | deps/libbsd/include/bsd/string.h 38 | deps/libbsd/include/bsd/inttypes.h 39 | Copyright: 2004, 2005, 2009, 2011, 2018 Guillem Jover 40 | License: BSD-3-Clause 41 | 42 | Files: deps/libbsd/include/bsd/unistd.h 43 | Copyright: 2006 Robert Millan 44 | Copyright: 2008-2011 Guillem Jover 45 | License: BSD-3-Clause 46 | 47 | License: Apache-2.0 48 | Licensed under the Apache License, Version 2.0 (the "License"); 49 | you may not use this file except in compliance with the License. 50 | You may obtain a copy of the License at 51 | . 52 | http://www.apache.org/licenses/LICENSE-2.0 53 | . 54 | Unless required by applicable law or agreed to in writing, software 55 | distributed under the License is distributed on an "AS IS" BASIS, 56 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 57 | See the License for the specific language governing permissions and 58 | limitations under the License. 59 | . 60 | On Debian systems, the complete text of the Apache License, Version 2 61 | can be found in "/usr/share/common-licenses/Apache-2.0". 62 | 63 | License: GPL-2.0 64 | This program is free software; you can redistribute it and/or modify 65 | it under the terms of the GNU General Public License as published by 66 | the Free Software Foundation; version 2. 67 | . 68 | This program is distributed in the hope that it will be useful, 69 | but WITHOUT ANY WARRANTY; without even the implied warranty of 70 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 71 | GNU General Public License for more details. 72 | . 73 | You should have received a copy of the GNU General Public License 74 | along with this program. If not, see 75 | . 76 | On Debian systems, the complete text of the GNU General 77 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 78 | 79 | License: Linux-syscall-note 80 | NOTE! This copyright does *not* cover user programs that use kernel 81 | services by normal system calls - this is merely considered normal use 82 | of the kernel, and does *not* fall under the heading of "derived work". 83 | Also note that the GPL below is copyrighted by the Free Software 84 | Foundation, but the instance of code that it refers to (the Linux 85 | kernel) is copyrighted by me and others who actually wrote it. 86 | . 87 | Also note that the only valid version of the GPL as far as the kernel 88 | is concerned is _this_ particular version of the license (ie v2, not 89 | v2.2 or v3.x or whatever), unless explicitly otherwise stated. 90 | 91 | License: GPL-2.0+ 92 | This program is free software; you can redistribute it and/or modify 93 | it under the terms of the GNU General Public License as published by 94 | the Free Software Foundation; either version 2 of the License, or 95 | (at your option) any later version. 96 | . 97 | This program is distributed in the hope that it will be useful, 98 | but WITHOUT ANY WARRANTY; without even the implied warranty of 99 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 100 | GNU General Public License for more details. 101 | . 102 | You should have received a copy of the GNU General Public License 103 | along with this program. If not, see 104 | . 105 | On Debian systems, the complete text of the GNU General 106 | Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". 107 | 108 | License: ISC 109 | Permission to use, copy, modify, and distribute this software for any 110 | purpose with or without fee is hereby granted, provided that the above 111 | copyright notice and this permission notice appear in all copies. 112 | . 113 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 114 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 115 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 116 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 117 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 118 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 119 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 120 | 121 | License: BSD-3-Clause-Regents 122 | Redistribution and use in source and binary forms, with or without 123 | modification, are permitted provided that the following conditions 124 | are met: 125 | 1. Redistributions of source code must retain the above copyright 126 | notice, this list of conditions and the following disclaimer. 127 | 2. Redistributions in binary form must reproduce the above copyright 128 | notice, this list of conditions and the following disclaimer in the 129 | documentation and/or other materials provided with the distribution. 130 | 3. Neither the name of the University nor the names of its contributors 131 | may be used to endorse or promote products derived from this software 132 | without specific prior written permission. 133 | . 134 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 135 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 136 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 137 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 138 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 139 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 140 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 141 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 142 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 143 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 144 | SUCH DAMAGE. 145 | 146 | License: BSD-3-Clause 147 | Redistribution and use in source and binary forms, with or without 148 | modification, are permitted provided that the following conditions 149 | are met: 150 | 1. Redistributions of source code must retain the above copyright 151 | notice, this list of conditions and the following disclaimer. 152 | 2. Redistributions in binary form must reproduce the above copyright 153 | notice, this list of conditions and the following disclaimer in the 154 | documentation and/or other materials provided with the distribution. 155 | 3. The name of the author may not be used to endorse or promote products 156 | derived from this software without specific prior written permission. 157 | . 158 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 159 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 160 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 161 | THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 162 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 163 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 164 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 165 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 166 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 167 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 168 | 169 | License: MIT 170 | Permission is hereby granted, free of charge, to any person obtaining 171 | a copy of this software and associated documentation files (the 172 | "Software"), to deal in the Software without restriction, including 173 | without limitation the rights to use, copy, modify, merge, publish, 174 | distribute, sublicense, and/or sell copies of the Software, and to 175 | permit persons to whom the Software is furnished to do so, subject to 176 | the following conditions: 177 | . 178 | The above copyright notice and this permission notice shall be 179 | included in all copies or substantial portions of the Software. 180 | . 181 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 182 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 183 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 184 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 185 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 186 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 187 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 188 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | 193 | 194 | This product bundles libbsd, which is available under a dual 195 | "3-clause BSD" and "ISC" license. For details, see deps/libbsd/. 196 | 197 | This product bundles makeself, which is available under a 198 | "GNU General Public License v2.0" license. For details, see deps/makeself/. 199 | 200 | This product bundles linux-headers, which is available under a 201 | "GNU General Public License v2.0 WITH syscall exception" license. For details, see deps/linux-headers/. 202 | 203 | This product bundles musl, which is available under a 204 | "MIT" license. For details, see deps/musl/. 205 | -------------------------------------------------------------------------------- /bin/enroot-nsenter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #if !defined(__x86_64__) && !defined(__aarch64__) && !defined(__powerpc64__) 18 | # error "unsupported architecture" 19 | #endif 20 | 21 | #ifdef __aarch64__ 22 | #define __ARCH_WANT_SYSCALL_NO_AT 23 | #endif 24 | 25 | #define _GNU_SOURCE 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include 45 | #include 46 | 47 | #include "common.h" 48 | 49 | #ifndef PR_CAP_AMBIENT 50 | # define PR_CAP_AMBIENT 47 51 | #endif 52 | #ifndef PR_CAP_AMBIENT_IS_SET 53 | # define PR_CAP_AMBIENT_IS_SET 1 54 | #endif 55 | #ifndef PR_CAP_AMBIENT_RAISE 56 | # define PR_CAP_AMBIENT_RAISE 2 57 | #endif 58 | 59 | #ifndef CLONE_NEWCGROUP 60 | # define CLONE_NEWCGROUP 0x02000000 61 | #endif 62 | 63 | #ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW 64 | # define SECCOMP_FILTER_FLAG_SPEC_ALLOW 4 65 | #endif 66 | 67 | #ifndef PR_GET_SPECULATION_CTRL 68 | # define PR_GET_SPECULATION_CTRL 52 69 | #endif 70 | #ifndef PR_SET_SPECULATION_CTRL 71 | # define PR_SET_SPECULATION_CTRL 53 72 | #endif 73 | #ifndef PR_SPEC_PRCTL 74 | # define PR_SPEC_PRCTL 1 75 | #endif 76 | #ifndef PR_SPEC_ENABLE 77 | # define PR_SPEC_ENABLE 2 78 | #endif 79 | #ifndef PR_SPEC_DISABLE 80 | # define PR_SPEC_DISABLE 4 81 | #endif 82 | #ifndef PR_SPEC_DISABLE_NOEXEC 83 | # define PR_SPEC_DISABLE_NOEXEC 16 84 | #endif 85 | #ifndef PR_SPEC_STORE_BYPASS 86 | # define PR_SPEC_STORE_BYPASS 0 87 | #endif 88 | #ifndef PR_SPEC_INDIRECT_BRANCH 89 | # define PR_SPEC_INDIRECT_BRANCH 1 90 | #endif 91 | #ifndef PR_SPEC_L1D_FLUSH 92 | # define PR_SPEC_L1D_FLUSH 2 93 | #endif 94 | 95 | #ifndef AUDIT_ARCH_AARCH64 96 | #define AUDIT_ARCH_AARCH64 (EM_AARCH64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) 97 | #endif 98 | 99 | static struct sock_filter filter[] = { 100 | /* Check for the syscall architecture (x86_64 and aarch64 ABIs). */ 101 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, arch)), 102 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_X86_64, 3, 0), 103 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_AARCH64, 2, 0), 104 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_PPC64LE, 1, 0), 105 | /* FIXME We do not support x86, x32 and aarch32, allow all syscalls for now. */ 106 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 107 | 108 | /* Load the syscall number. */ 109 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, nr)), 110 | 111 | /* Return success on all the following syscalls. */ 112 | #if defined(SYS_chown) && defined(SYS_lchown) 113 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_chown, 15, 0), 114 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_lchown, 14, 0), 115 | #endif 116 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setuid, 13, 0), 117 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setgid, 12, 0), 118 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setreuid, 11, 0), 119 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setregid, 10, 0), 120 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setresuid, 9, 0), 121 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setresgid, 8, 0), 122 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setgroups, 7, 0), 123 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_fchownat, 6, 0), 124 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_fchown, 5, 0), 125 | 126 | /* For setfsuid/setfsgid we only return success if the uid/gid argument is not -1. */ 127 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setfsuid, 1, 0), 128 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SYS_setfsgid, 0, 2), 129 | BPF_STMT(BPF_LD|BPF_W|BPF_ABS, offsetof(struct seccomp_data, args[0])), 130 | BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, (uint32_t)-1, 0, 1), 131 | 132 | /* Execute the syscall as usual. */ 133 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW), 134 | /* Return success. */ 135 | BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO|(SECCOMP_RET_DATA & 0x0)), 136 | }; 137 | 138 | static void 139 | raise_capabilities(void) 140 | { 141 | struct capabilities_v3 caps; 142 | 143 | CAP_INIT_V3(&caps); 144 | 145 | if (capget(&caps.hdr, caps.data) < 0) 146 | err(EXIT_FAILURE, "failed to get capabilities"); 147 | 148 | CAP_COPY(&caps, inheritable, effective); 149 | if (capset(&caps.hdr, caps.data) < 0) 150 | err(EXIT_FAILURE, "failed to set capabilities"); 151 | 152 | CAP_FOREACH(&caps, n) { 153 | if (CAP_ISSET(&caps, inheritable, n)) { 154 | if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, n, 0, 0) < 0) 155 | err(EXIT_FAILURE, "failed to set capabilities"); 156 | } 157 | } 158 | } 159 | 160 | static void 161 | create_namespaces(bool user, bool mount, bool remap_root) 162 | { 163 | if (user) { 164 | if (!remap_root && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, 0, 0, 0) < 0 && errno == EINVAL) 165 | errx(EXIT_FAILURE, "kernel lacks support for ambient capabilities, consider using --remap-root instead"); 166 | if (unshare_userns(remap_root) < 0) 167 | err(EXIT_FAILURE, "failed to create user namespace"); 168 | if (!remap_root) 169 | raise_capabilities(); 170 | } 171 | if (mount) { 172 | if (unshare(CLONE_NEWNS) < 0) 173 | err(EXIT_FAILURE, "failed to create mount namespace"); 174 | } 175 | } 176 | 177 | static int 178 | do_setns(pid_t pid, int nstype) 179 | { 180 | char path[PATH_MAX]; 181 | const char *nsstr; 182 | int fd; 183 | struct stat s1, s2; 184 | 185 | switch (nstype) { 186 | case CLONE_NEWUSER: 187 | nsstr = "user"; 188 | break; 189 | case CLONE_NEWNS: 190 | nsstr = "mnt"; 191 | break; 192 | case CLONE_NEWCGROUP: 193 | nsstr = "cgroup"; 194 | break; 195 | default: 196 | errno = EINVAL; 197 | return (-1); 198 | } 199 | if ((size_t)snprintf(path, sizeof(path), "/proc/%d/ns/%s", pid, nsstr) >= sizeof(path)) { 200 | errno = ENAMETOOLONG; 201 | return (-1); 202 | } 203 | 204 | if (nstype == CLONE_NEWUSER) { 205 | if (stat(path, &s1) < 0) 206 | return (-1); 207 | if (stat("/proc/self/ns/user", &s2) < 0) 208 | return (-1); 209 | if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) 210 | return (0); 211 | } 212 | 213 | if ((fd = open(path, O_RDONLY)) < 0) { 214 | if (nstype == CLONE_NEWCGROUP && errno == ENOENT) 215 | return (0); 216 | goto err; 217 | } 218 | if (setns(fd, nstype) < 0) 219 | goto err; 220 | if (close(fd) < 0) 221 | goto err; 222 | return (0); 223 | 224 | err: 225 | SAVE_ERRNO(close(fd)); 226 | return (-1); 227 | } 228 | 229 | static void 230 | join_namespaces(pid_t pid, bool user, bool mount) 231 | { 232 | if (user) { 233 | if (do_setns(pid, CLONE_NEWUSER) < 0) 234 | err(EXIT_FAILURE, "failed to join user namespace"); 235 | } 236 | if (mount) { 237 | if (do_setns(pid, CLONE_NEWNS) < 0) 238 | err(EXIT_FAILURE, "failed to join mount namespace"); 239 | } 240 | if (do_setns(pid, CLONE_NEWCGROUP) < 0) 241 | err(EXIT_FAILURE, "failed to join cgroup namespace"); 242 | } 243 | 244 | MAYBE_UNUSED static int 245 | disable_mitigation(int spec) 246 | { 247 | switch (prctl(PR_GET_SPECULATION_CTRL, spec, 0, 0, 0)) { 248 | case PR_SPEC_PRCTL|PR_SPEC_DISABLE: 249 | case PR_SPEC_PRCTL|PR_SPEC_DISABLE_NOEXEC: 250 | if (prctl(PR_SET_SPECULATION_CTRL, spec, PR_SPEC_ENABLE, 0, 0) < 0) 251 | return (-1); 252 | break; 253 | case -1: 254 | if (errno != EINVAL && errno != ENODEV) 255 | return (-1); 256 | break; 257 | } 258 | return (0); 259 | } 260 | 261 | static int 262 | seccomp_set_filter(void) 263 | { 264 | #ifdef ALLOW_SPECULATION 265 | if ((int)syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_SPEC_ALLOW, &(const struct sock_fprog){ARRAY_SIZE(filter), filter}) == 0) 266 | return (0); 267 | else if (errno != EINVAL) 268 | return (-1); 269 | #endif 270 | return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &(const struct sock_fprog){ARRAY_SIZE(filter), filter}); 271 | } 272 | 273 | int 274 | main(int argc, char *argv[]) 275 | { 276 | bool user = false, mount = false, remap_root = false; 277 | char *envfile = NULL, *workdir = NULL; 278 | pid_t target = -1; 279 | int e; 280 | 281 | for (;;) { 282 | if (argc >= 3 && !strcmp(argv[1], "--target")) { 283 | target = (int)strtoi(argv[2], NULL, 10, 1, INT_MAX, &e); 284 | if (e != 0) 285 | errx(EXIT_FAILURE, "invalid argument: %s", argv[2]); 286 | SHIFT_ARGS(2); 287 | continue; 288 | } 289 | if (argc >= 3 && !strcmp(argv[1], "--envfile")) { 290 | envfile = argv[2]; 291 | SHIFT_ARGS(2); 292 | continue; 293 | } 294 | if (argc >= 3 && !strcmp(argv[1], "--workdir")) { 295 | workdir = argv[2]; 296 | SHIFT_ARGS(2); 297 | continue; 298 | } 299 | if (argc >= 2 && !strcmp(argv[1], "--user")) { 300 | user = true; 301 | SHIFT_ARGS(1); 302 | continue; 303 | } 304 | if (argc >= 2 && !strcmp(argv[1], "--mount")) { 305 | mount = true; 306 | SHIFT_ARGS(1); 307 | continue; 308 | } 309 | if (argc >= 2 && !strcmp(argv[1], "--remap-root")) { 310 | remap_root = true; 311 | SHIFT_ARGS(1); 312 | continue; 313 | } 314 | break; 315 | } 316 | if (argc < 2) { 317 | printf("Usage: %s [--target PID] [--user] [--mount] [--remap-root] [--envfile FILE] [--workdir DIR] COMMAND [ARG...]\n", argv[0]); 318 | return (0); 319 | } 320 | 321 | if (target < 0) 322 | create_namespaces(user, mount, remap_root); 323 | else 324 | join_namespaces(target, user, mount); 325 | 326 | if (user) { 327 | if (seccomp_set_filter() < 0) 328 | err(EXIT_FAILURE, "failed to register seccomp filter"); 329 | } 330 | if (envfile != NULL) { 331 | if (load_environment(envfile) < 0) 332 | err(EXIT_FAILURE, "failed to load environment: %s", envfile); 333 | } 334 | if (workdir != NULL) { 335 | if (chdir(workdir) < 0) 336 | err(EXIT_FAILURE, "failed to change directory: %s", workdir); 337 | } 338 | 339 | #ifdef ALLOW_SPECULATION 340 | if (disable_mitigation(PR_SPEC_STORE_BYPASS) < 0) 341 | err(EXIT_FAILURE, "failed to disable SSBD mitigation"); 342 | if (disable_mitigation(PR_SPEC_INDIRECT_BRANCH) < 0) 343 | err(EXIT_FAILURE, "failed to disable IBPB/STIBP mitigation"); 344 | if (disable_mitigation(PR_SPEC_L1D_FLUSH) < 0) 345 | err(EXIT_FAILURE, "failed to disable L1TF mitigation"); 346 | #endif 347 | #ifndef INHERIT_FDS 348 | closefrom(STDERR_FILENO + 1); 349 | #endif 350 | 351 | if (execvp(argv[1], &argv[1]) < 0) 352 | err(EXIT_FAILURE, "failed to execute: %s", argv[1]); 353 | return (0); 354 | } 355 | --------------------------------------------------------------------------------