Skip to content

Commit

Permalink
WIP: Symlink /usr
Browse files Browse the repository at this point in the history
  • Loading branch information
apyrgio committed Jan 23, 2025
1 parent ac6931f commit 06fe63b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 13 deletions.
71 changes: 62 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

ARG DEBIAN_IMAGE_DATE=20250113

FROM debian:bookworm-${DEBIAN_IMAGE_DATE}-slim
FROM debian:bookworm-${DEBIAN_IMAGE_DATE}-slim as dangerzone-image

ARG GVISOR_ARCHIVE_DATE=20250113
ARG DEBIAN_ARCHIVE_DATE=20250120
Expand Down Expand Up @@ -64,18 +64,71 @@ RUN touch /opt/dangerzone/dangerzone/__init__.py
# Copy only the Python code, and not any produced .pyc files.
COPY conversion/*.py /opt/dangerzone/dangerzone/conversion/

# Let the entrypoint script write the OCI config for the inner container under
# /config.json.
RUN touch /config.json
RUN chown dangerzone:dangerzone /config.json

# Switch to the dangerzone user for the rest of the script.
USER dangerzone

# Create a directory that will be used by gVisor as the place where it will
# store the state of its containers.
RUN mkdir /home/dangerzone/.containers

# XXX: Create a new root hierarchy, that will be used in the final container
# image:
#
# /bin -> usr/bin
# /lib -> usr/lib
# /lib64 -> usr/lib64
# /root
# /run
# /tmp
# /usr -> /home/dangerzone/dangerzone-image/rootfs/usr/
#
# We have to create this hierarchy beforehand because we want to use the same
# /usr for both the inner and outer container. The problem though is that /usr
# is very sensitive, and you can't manipulate in a live system. That is, I
# haven't found a way to do the following, or something equivalent:
#
# rm -r /usr && ln -s /home/dangerzone/dangerzone-image/rootfs/usr/ /usr
#
# So, we prefer to create the symlinks here instead, and create the image
# manually in the next steps.
RUN mkdir /new_root
RUN mkdir /new_root/root /new_root/run /new_root/tmp
RUN chmod 777 /new_root/tmp
RUN ln -s /home/dangerzone/dangerzone-image/rootfs/usr/ /new_root/usr
RUN ln -s usr/bin /new_root/bin
RUN ln -s usr/lib /new_root/lib
RUN ln -s usr/lib64 /new_root/lib64
RUN ln -s usr/sbin /new_root/sbin

# Intermediate layer

FROM debian:bookworm-${DEBIAN_IMAGE_DATE}-slim as debian-utils

## Final image

FROM scratch

# Copy the filesystem hierarchy that we created in the previous layer, so that
# /usr can be a symlink.
COPY --from=dangerzone-image /new_root/ /

# Copy some files that are necessary to use the outer container image, e.g., in
# order to run `apt`. We _could_ avoid doing this, but the space cost is very
# small.
COPY --from=dangerzone-image /etc/ /etc/
COPY --from=debian-utils /var/ /var/

# Copy the bare minimum to run Dangerzone in the inner container image.
COPY --from=dangerzone-image /etc/ /home/dangerzone/dangerzone-image/rootfs/etc/
COPY --from=dangerzone-image /usr/ /home/dangerzone/dangerzone-image/rootfs/usr/
COPY --from=dangerzone-image /opt/ /home/dangerzone/dangerzone-image/rootfs/opt/
RUN ln -s usr/bin /home/dangerzone/dangerzone-image/rootfs/bin
RUN ln -s usr/lib /home/dangerzone/dangerzone-image/rootfs/lib
RUN ln -s usr/lib64 /home/dangerzone/dangerzone-image/rootfs/lib64

# Allow our entrypoint script to make changes in the following folders.
RUN chown dangerzone:dangerzone /home/dangerzone /home/dangerzone/dangerzone-image/

# Switch to the dangerzone user for the rest of the script.
USER dangerzone

COPY container_helpers/entrypoint.py /

ENTRYPOINT ["/entrypoint.py"]
8 changes: 4 additions & 4 deletions dangerzone/container_helpers/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ def log(message: str, *values: typing.Any) -> None:
{"type": "RLIMIT_NOFILE", "hard": 4096, "soft": 4096},
],
},
"root": {"path": "/", "readonly": True},
"root": {"path": "rootfs", "readonly": True},
"hostname": "dangerzone",
"mounts": [
# Mask almost every system directory of the outer container, by mounting tmpfs
# on top of them. This is done to avoid leaking any sensitive information,
# either mounted by Podman/Docker, or when gVisor runs, since we reuse the same
# rootfs. We basically mask everything except for `/usr`, `/bin`, `/lib`,
# and `/etc`.
# `/etc`, and `/opt`.
#
# Note that we set `--root /home/dangerzone/.containers` for the directory where
# gVisor will create files at runtime, which means that in principle, we are
Expand Down Expand Up @@ -219,7 +219,7 @@ def log(message: str, *values: typing.Any) -> None:
json.dump(oci_config, sys.stderr, indent=2, sort_keys=True)
# json.dump doesn't print a trailing newline, so print one here:
log("")
with open("/config.json", "w") as oci_config_out:
with open("/home/dangerzone/dangerzone-image/config.json", "w") as oci_config_out:
json.dump(oci_config, oci_config_out, indent=2, sort_keys=True)

# Run gVisor.
Expand All @@ -236,7 +236,7 @@ def log(message: str, *values: typing.Any) -> None:
runsc_argv += ["--debug=true", "--alsologtostderr=true"]
if os.environ.get("RUNSC_FLAGS"):
runsc_argv += [x for x in shlex.split(os.environ.get("RUNSC_FLAGS", "")) if x]
runsc_argv += ["run", "--bundle=/", "dangerzone"]
runsc_argv += ["run", "--bundle=/home/dangerzone/dangerzone-image", "dangerzone"]
log(
"Running gVisor with command line: {}", " ".join(shlex.quote(s) for s in runsc_argv)
)
Expand Down

0 comments on commit 06fe63b

Please sign in to comment.