Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow basic sandboxing of containers #1413

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions completions/zsh/_distrobox-create
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ _arguments -s \
'--pre-init-hooks[additional commands to execute prior to container initialization]:command:' \
'(--init -I)'{-I,--init}'[use init system inside the container]' \
'--nvidia[try to integrate host nVidia drivers in the guest]' \
'--unprivileged[do not drop security measures when creating a container]' \
'--unshare-devsys[do not share host devices and sysfs dirs from host]' \
'--unshare-groups[do not forward user''s additional groups into the container]' \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch!

'--unshare-home[do not mount host home directory into the container]' \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other comment

Suggested change
'--unshare-home[do not mount host home directory into the container]' \
'--unshare-home[do not mount host''s home directory into the container]' \

'--unshare-ipc[do not share ipc namespace with host]' \
'--unshare-netns[do not share the net namespace with host]' \
'--unshare-process[do not share process namespace with host]' \
'--unshare-root[do not mount host root directory into the container]' \
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See other comment

Suggested change
'--unshare-root[do not mount host root directory into the container]' \
'--unshare-root[do not mount host''s root directory into the container]' \

'--unshare-all[activate all the unshare flags]' \
'(--compatibility -C)'{-C,--compatibility}'[show list of compatible images]' \
'(--help -h)'{-h,--help}'[show this message]' \
Expand Down
12 changes: 12 additions & 0 deletions distrobox-assemble
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ pre_init_hooks=""
pull=""
root=""
start_now=""
unprivileged=""
unshare_home=""
unshare_ipc=""
unshare_netns=""
unshare_process=""
unshare_root=""
unshare_devsys=""
unshare_all=""
volume=""
Expand Down Expand Up @@ -323,15 +326,24 @@ run_distrobox()
if [ -n "${nvidia}" ] && [ "${nvidia}" -eq 1 ]; then
result_command="${result_command} --nvidia"
fi
if [ -n "${unprivileged}" ] && [ "${unprivileged}" -eq 1 ]; then
result_command="${result_command} --unprivileged"
fi
if [ -n "${unshare_netns}" ] && [ "${unshare_netns}" -eq 1 ]; then
result_command="${result_command} --unshare-netns"
fi
if [ -n "${unshare_home}" ] && [ "${unshare_home}" -eq 1 ]; then
result_command="${result_command} --unshare-home"
fi
if [ -n "${unshare_ipc}" ] && [ "${unshare_ipc}" -eq 1 ]; then
result_command="${result_command} --unshare-ipc"
fi
if [ -n "${unshare_process}" ] && [ "${unshare_process}" -eq 1 ]; then
result_command="${result_command} --unshare-process"
fi
if [ -n "${unshare_root}" ] && [ "${unshare_root}" -eq 1 ]; then
result_command="${result_command} --unshare-root"
fi
if [ -n "${unshare_devsys}" ] && [ "${unshare_devsys}" -eq 1 ]; then
result_command="${result_command} --unshare-devsys"
fi
Expand Down
63 changes: 49 additions & 14 deletions distrobox-create
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,13 @@ init=0
non_interactive=0
nvidia=0
nopasswd=0
unprivileged=0
unshare_ipc=0
unshare_groups=0
unshare_home=0
unshare_netns=0
unshare_process=0
unshare_root=0
unshare_devsys=0

# Use cd + dirname + pwd so that we do not have relative paths in mount points
Expand Down Expand Up @@ -214,11 +217,14 @@ Options:
this will make host's processes not visible from within the container. (assumes --unshare-process)
may require additional packages depending on the container image: https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-init-system-inside-a-distrobox
--nvidia: try to integrate host's nVidia drivers in the guest
--unshare-devsys: do not share host devices and sysfs dirs from host
--unshare-groups: do not forward user's additional groups into the container
--unprivileged: do not drop security measures when creating a container
--unshare-devsys: do not share host devices and sysfs dirs from host
--unshare-groups: do not forward user's additional groups into the container
--unshare-home: do not mount host home directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice description! I think grammatically, there is a small mistake.
I'm going to mark the other spots for convenience, so you could just click "accept suggestion".

Suggested change
--unshare-home: do not mount host home directory into the container
--unshare-home: do not mount host's home directory into the container

--unshare-ipc: do not share ipc namespace with host
--unshare-netns: do not share the net namespace with host
--unshare-process: do not share process namespace with host
--unshare-process: do not share process namespace with host
--unshare-root: do not mount host root directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the --unshare-home flag ^^

Suggested change
--unshare-root: do not mount host root directory into the container
--unshare-root: do not mount host's root directory into the container

--unshare-all: activate all the unshare flags below
--compatibility/-C: show list of compatible images
--help/-h: show this message
Expand Down Expand Up @@ -298,6 +304,10 @@ while :; do
shift
dryrun=1
;;
--unprivileged)
shift
unprivileged=1
;;
-r | --root)
shift
rootful=1
Expand All @@ -320,6 +330,10 @@ while :; do
shift
unshare_groups=1
;;
--unshare-home)
shift
unshare_home=1
;;
--unshare-netns)
shift
unshare_netns=1
Expand All @@ -328,6 +342,10 @@ while :; do
shift
unshare_process=1
;;
--unshare-root)
shift
unshare_root=1
;;
--unshare-devsys)
shift
unshare_devsys=1
Expand All @@ -337,8 +355,10 @@ while :; do
unshare_devsys=1
unshare_groups=1
unshare_ipc=1
unshare_home=1
Comment on lines 357 to +358
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These appear to be alphabetically sorted. I'd exchange these to follow the pattern :D

Suggested change
unshare_ipc=1
unshare_home=1
unshare_home=1
unshare_ipc=1

unshare_netns=1
unshare_process=1
unshare_root=1
;;
-C | --compatibility)
show_compatibility
Expand Down Expand Up @@ -640,11 +660,14 @@ get_clone_image()
# init: bool initful
# nvidia: bool nvidia integration
# rootful: bool rootful
# unprivileged: bool unprivileged
# unshare_devsys: bool unshare devsys
# unshare_groups: bool unshare groups
# unshare_home: bool unshare home dir
# unshare_ipc: bool unshare ipc
# unshare_netns: bool unshare netns
# unshare_process: bool unshare proc
# unshare_root: bool unshare root dir
# Expected env variables:
# None
# Outputs:
Expand All @@ -657,10 +680,6 @@ generate_create_command()
result_command="${result_command}
--hostname \"${container_hostname}\"
--name \"${container_name}\"
--privileged
--security-opt label=disable
--security-opt apparmor=unconfined
--pids-limit=-1
--user root:root"

if [ "${unshare_ipc}" -eq 0 ]; then
Expand Down Expand Up @@ -690,23 +709,24 @@ generate_create_command()
result_command="${result_command}
--label \"manager=distrobox\"
--label \"distrobox.unshare_groups=${unshare_groups}\"
--label \"distrobox.unshare_home=${unshare_home}\"
--label \"distrobox.unshare_root=${unshare_root}\"
--env \"SHELL=$(basename "${SHELL:-"/bin/bash"}")\"
--env \"HOME=${container_user_home}\"
--env \"container=${container_manager}\"
--env \"TERMINFO_DIRS=/usr/share/terminfo:/run/host/usr/share/terminfo\"
--env \"CONTAINER_ID=${container_name}\"
--volume /tmp:/tmp:rslave
--volume \"${distrobox_entrypoint_path}\":/usr/bin/entrypoint:ro
--volume \"${distrobox_export_path}\":/usr/bin/distrobox-export:ro
--volume \"${distrobox_hostexec_path}\":/usr/bin/distrobox-host-exec:ro
--volume \"${container_user_home}\":\"${container_user_home}\":rslave"
--volume \"${distrobox_hostexec_path}\":/usr/bin/distrobox-host-exec:ro"

# Due to breaking change in https://github.com/opencontainers/runc/commit/d4b670fca6d0ac606777376440ffe49686ce15f4
# now we cannot mount /:/run/host as before, as it will try to mount RO partitions as RW thus breaking things.
# This will ensure we will mount directories one-by-one thus avoiding this problem.
#
# This happens ONLY with podman+runc, docker and lilipod are unaffected, so let's do this only if we have podman AND runc.
if echo "${container_manager}" | grep -q "podman" && ${container_manager} info | grep -q runc; then
if [ "${unshare_root}" -eq 0 ] &&
echo "${container_manager}" | grep -q "podman" && ${container_manager} info | grep -q runc; then
for rootdir in /*; do

# Skip symlinks
Expand All @@ -727,11 +747,18 @@ generate_create_command()
result_command="${result_command}
--volume ${rootdir}:/run/host${rootdir}:rslave"
done
else
elif [ "${unshare_root}" -eq 0 ]; then
# We're either on podman+crun, docker or lilipod, let's keep old behaviour
result_command="${result_command}
--volume /:/run/host/:rslave"
fi

if [ "${unprivileged}" -eq 0 ]; then
result_command="${result_command}
--privileged
--security-opt label=disable
--security-opt apparmor=unconfined
--pids-limit=-1"
fi

if [ "${unshare_devsys}" -eq 0 ]; then
Expand All @@ -740,6 +767,12 @@ generate_create_command()
--volume /sys:/sys:rslave"
fi

if [ "${unshare_home}" -eq 0 ]; then
result_command="${result_command}
--env \"HOME=${container_user_home}\"
--volume \"${container_user_home}\":\"${container_user_home}\":rslave"
fi

# In case of initful containers, we implement a series of mountpoint in order
# for systemd to work properly inside a container.
# The following are a flag-based implementation of what podman's --systemd flag
Expand Down Expand Up @@ -864,7 +897,8 @@ generate_create_command()
# Mount also the /var/home dir on ostree based systems
# do this only if $HOME was not already set to /var/home/username
if [ "${container_user_home}" != "/var/home/${container_user_name}" ] &&
[ -d "/var/home/${container_user_name}" ]; then
[ -d "/var/home/${container_user_name}" ] &&
[ "${unshare_home}" -eq 0 ]; then

result_command="${result_command}
--volume \"/var/home/${container_user_name}\":\"/var/home/${container_user_name}\":rslave"
Expand All @@ -873,7 +907,8 @@ generate_create_command()
# Mount also the XDG_RUNTIME_DIR to ensure functionality of the apps.
# This is skipped in case of initful containers, so that a dedicated
# systemd user session can be used.
if [ -d "/run/user/${container_user_uid}" ] && [ "${init}" -eq 0 ]; then
if [ -d "/run/user/${container_user_uid}" ] && [ "${init}" -eq 0 ] &&
[ "${unshare_root}" -eq 0 ]; then
result_command="${result_command}
--volume /run/user/${container_user_uid}:/run/user/${container_user_uid}:rslave"
fi
Expand Down
11 changes: 10 additions & 1 deletion distrobox-enter
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ fi
# skip_workdir: bool skip workdir
# verbose: bool verbose
# unshare_groups
# unshare_home
# unshare_root
# distrobox_enter_path
# Expected env variables:
# PATH
Expand Down Expand Up @@ -427,8 +429,11 @@ generate_enter_command()
# pass distrobox-enter path, it will be used in the distrobox-export tool.
if [ "${skip_workdir}" -eq 0 ]; then
workdir="$(echo "${PWD:-${container_home:-"/"}}" | sed -e 's/"/\\\"/g')"
if [ -n "${workdir##*"${container_home}"*}" ]; then
if [ "${unshare_root:-0}" -eq 0 ] && [ -n "${workdir##*"${container_home}"*}" ]; then
workdir="/run/host${workdir}"
elif ! [ "${unshare_home:-0}" -eq 0 ]; then
# Workdir is unshared, we just enter $HOME of the container.
workdir="${container_home}"
Comment on lines +434 to +436
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fallback!

fi
else
# Skipping workdir we just enter $HOME of the container.
Expand Down Expand Up @@ -562,11 +567,15 @@ generate_enter_command()
container_home="${HOME}"
container_path="${PATH}"
unshare_groups=0
unshare_home=0
unshare_root=0
# Now inspect the container we're working with.
container_status="unknown"
eval "$(${container_manager} inspect --type container --format \
'container_status={{.State.Status}};
unshare_groups={{ index .Config.Labels "distrobox.unshare_groups" }};
unshare_home={{ index .Config.Labels "distrobox.unshare_home" }};
unshare_root={{ index .Config.Labels "distrobox.unshare_root" }};
{{range .Config.Env}}{{if slice . 0 5 | eq "HOME="}}container_home={{slice . 5 | printf "%q"}};{{end}}{{end}}
{{range .Config.Env}}{{if slice . 0 5 | eq "PATH="}}container_path={{slice . 5 | printf "%q"}}{{end}}{{end}}' \
"${container_name}")"
Expand Down
6 changes: 6 additions & 0 deletions distrobox-export
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ if [ ! -f /run/.containerenv ] && [ ! -f /.dockerenv ] && [ -z "${container:-}"
exit 126
fi

# Check if host dir is mounted in this container
if [ ! -d /run/host ]; then
printf >&2 "Cannot run in container with unshared host directory!\n"
exit 126
fi

# Check if we're in a rootful or rootless container.
if grep -q "rootless=0" /run/.containerenv 2> /dev/null; then
rootful="--root"
Expand Down
6 changes: 6 additions & 0 deletions distrobox-host-exec
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ if [ ! -f /run/.containerenv ] && [ ! -f /.dockerenv ] && [ -z "${container:-}"
exit 126
fi

# Check if host dir is mounted in this container
if [ ! -d /run/host ]; then
printf >&2 "Cannot run in container with unshared host directory!\n"
exit 126
fi

if [ -z "${host_command}" ]; then
host_command="${distrobox_host_exec_default_command}"
fi
Expand Down
8 changes: 5 additions & 3 deletions distrobox-init
Original file line number Diff line number Diff line change
Expand Up @@ -1423,12 +1423,14 @@ fi
#
# Podman supports a mount option to do this at creation time, but we're doing it
# here to support also other container rmanagers which does not support that flag
mount -t devpts devpts -o noexec,nosuid,newinstance,ptmxmode=0666,mode=0620,gid=tty /dev/pts/
mount --bind /dev/pts/ptmx /dev/ptmx
{
mount -t devpts devpts -o noexec,nosuid,newinstance,ptmxmode=0666,mode=0620,gid=tty /dev/pts/
mount --bind /dev/pts/ptmx /dev/ptmx
} || printf "Warning: Cannot mount devpts\n"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to have a warning there. Is there a particular reason, why you did not prepend it with "distrobox: ..." or why you don't print to stderr? Not sure how distrobox normally handles warnings.


# Change mount propagation to shared to make the environment more similar to a
# modern Linux system, e.g. with Systemd as PID 1.
mount --make-rshared /
mount --make-rshared / || printf "Warning: Cannot remount root as shared\n"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

###############################################################################

###############################################################################
Expand Down
3 changes: 3 additions & 0 deletions docs/usage/distrobox-assemble.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,12 @@ This is a list of available options with the corresponding type:
| nvidia | bool |
| pull | bool |
| root | bool |
| unprivileged | bool |
| unshare_home | bool |
| unshare_ipc | bool |
| unshare_netns | bool |
| unshare_process | bool |
| unshare_root | bool |
| unshare_devsys | bool |
| unshare_all | bool |

Expand Down
3 changes: 3 additions & 0 deletions docs/usage/distrobox-create.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@ graphical apps (X11/Wayland), and audio.
this will make host's processes not visible from within the container. (assumes --unshare-process)
may require additional packages depending on the container image: https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-init-system-inside-a-distrobox
--nvidia: try to integrate host's nVidia drivers in the guest
--unprivileged: do not drop security measures when creating a container
--unshare-devsys: do not share host devices and sysfs dirs from host
--unshare-groups: do not forward user's additional groups into the container
--unshare-home: do not mount host home directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Suggested change
--unshare-home: do not mount host home directory into the container
--unshare-home: do not mount host's home directory into the container

--unshare-ipc: do not share ipc namespace with host
--unshare-netns: do not share the net namespace with host
--unshare-process: do not share process namespace with host
--unshare-root: do not mount host root directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Suggested change
--unshare-root: do not mount host root directory into the container
--unshare-root: do not mount host's root directory into the container

--unshare-all: activate all the unshare flags below
--compatibility/-C: show list of compatible images
--help/-h: show this message
Expand Down
15 changes: 15 additions & 0 deletions man/man1/distrobox-assemble.1
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ T}@T{
bool
T}
T{
unprivileged
T}@T{
bool
T}
T{
unshare_home
T}@T{
bool
T}
T{
unshare_ipc
T}@T{
bool
Expand All @@ -251,6 +261,11 @@ T}@T{
bool
T}
T{
unshare_root
T}@T{
bool
T}
T{
unshare_devsys
T}@T{
bool
Expand Down
3 changes: 3 additions & 0 deletions man/man1/distrobox-create.1
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,14 @@ usb devices and graphical apps (X11/Wayland), and audio.
this will make host\[aq]s processes not visible from within the container. (assumes --unshare-process)
may require additional packages depending on the container image: https://github.com/89luca89/distrobox/blob/main/docs/useful_tips.md#using-init-system-inside-a-distrobox
--nvidia: try to integrate host\[aq]s nVidia drivers in the guest
--unprivileged: do not drop security measures when creating a container
--unshare-devsys: do not share host devices and sysfs dirs from host
--unshare-groups: do not forward user\[aq]s additional groups into the container
--unshare-home: do not mount host home directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Suggested change
--unshare-home: do not mount host home directory into the container
--unshare-home: do not mount host's home directory into the container

--unshare-ipc: do not share ipc namespace with host
--unshare-netns: do not share the net namespace with host
--unshare-process: do not share process namespace with host
--unshare-root: do not mount host root directory into the container
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Suggested change
--unshare-root: do not mount host root directory into the container
--unshare-root: do not mount host's root directory into the container

--unshare-all: activate all the unshare flags below
--compatibility/-C: show list of compatible images
--help/-h: show this message
Expand Down
Loading