Reuse the same rootfs for the inner and outer container

Remove the need to copy the Dangerzone container image (used by the
inner container) within a wrapper gVisor image (used by the outer
container). Instead, use the root of the container filesystem for both
containers. We can do this safely because we don't mount any secrets to
the container, and because gVisor offers a read-only view of the
underlying filesystem

Fixes #1048
This commit is contained in:
Alex Pyrgiotis 2025-01-13 16:29:33 +02:00
parent e29837cb43
commit 935396565c
No known key found for this signature in database
GPG key ID: B6C15EBA0357C9AA
3 changed files with 12 additions and 20 deletions

View file

@ -36,7 +36,7 @@ RUN mkdir /libreoffice_ext && cd libreoffice_ext \
########################################### ###########################################
# Dangerzone image # Dangerzone image
FROM alpine:latest AS dangerzone-image FROM alpine:latest
# Install dependencies # Install dependencies
RUN apk --no-cache -U upgrade && \ RUN apk --no-cache -U upgrade && \
@ -66,14 +66,6 @@ COPY conversion /opt/dangerzone/dangerzone/conversion
RUN addgroup -g 1000 dangerzone && \ RUN addgroup -g 1000 dangerzone && \
adduser -u 1000 -s /bin/true -G dangerzone -h /home/dangerzone -D dangerzone adduser -u 1000 -s /bin/true -G dangerzone -h /home/dangerzone -D dangerzone
###########################################
# gVisor wrapper image
FROM alpine:latest
RUN apk --no-cache -U upgrade && \
apk --no-cache add python3
RUN GVISOR_URL="https://storage.googleapis.com/gvisor/releases/release/latest/$(uname -m)"; \ RUN GVISOR_URL="https://storage.googleapis.com/gvisor/releases/release/latest/$(uname -m)"; \
wget "${GVISOR_URL}/runsc" "${GVISOR_URL}/runsc.sha512" && \ wget "${GVISOR_URL}/runsc" "${GVISOR_URL}/runsc.sha512" && \
sha512sum -c runsc.sha512 && \ sha512sum -c runsc.sha512 && \
@ -81,18 +73,12 @@ RUN GVISOR_URL="https://storage.googleapis.com/gvisor/releases/release/latest/$(
chmod 555 runsc && \ chmod 555 runsc && \
mv runsc /usr/bin/ mv runsc /usr/bin/
# Add the unprivileged `dangerzone` user. RUN touch /config.json
RUN addgroup dangerzone && \ RUN chown dangerzone:dangerzone /config.json
adduser -s /bin/true -G dangerzone -h /home/dangerzone -D dangerzone
# Switch to the dangerzone user for the rest of the script. # Switch to the dangerzone user for the rest of the script.
USER dangerzone USER dangerzone
# Copy the Dangerzone image, as created by the previous steps, into the home
# directory of the `dangerzone` user.
RUN mkdir /home/dangerzone/dangerzone-image
COPY --from=dangerzone-image / /home/dangerzone/dangerzone-image/rootfs
# Create a directory that will be used by gVisor as the place where it will # Create a directory that will be used by gVisor as the place where it will
# store the state of its containers. # store the state of its containers.
RUN mkdir /home/dangerzone/.containers RUN mkdir /home/dangerzone/.containers

View file

@ -56,7 +56,7 @@ oci_config: dict[str, typing.Any] = {
{"type": "RLIMIT_NOFILE", "hard": 4096, "soft": 4096}, {"type": "RLIMIT_NOFILE", "hard": 4096, "soft": 4096},
], ],
}, },
"root": {"path": "rootfs", "readonly": True}, "root": {"path": "/", "readonly": True},
"hostname": "dangerzone", "hostname": "dangerzone",
"mounts": [ "mounts": [
{ {
@ -133,7 +133,7 @@ if os.environ.get("RUNSC_DEBUG"):
json.dump(oci_config, sys.stderr, indent=2, sort_keys=True) json.dump(oci_config, sys.stderr, indent=2, sort_keys=True)
# json.dump doesn't print a trailing newline, so print one here: # json.dump doesn't print a trailing newline, so print one here:
log("") log("")
with open("/home/dangerzone/dangerzone-image/config.json", "w") as oci_config_out: with open("/config.json", "w") as oci_config_out:
json.dump(oci_config, oci_config_out, indent=2, sort_keys=True) json.dump(oci_config, oci_config_out, indent=2, sort_keys=True)
# Run gVisor. # Run gVisor.
@ -150,7 +150,7 @@ if os.environ.get("RUNSC_DEBUG"):
runsc_argv += ["--debug=true", "--alsologtostderr=true"] runsc_argv += ["--debug=true", "--alsologtostderr=true"]
if os.environ.get("RUNSC_FLAGS"): if os.environ.get("RUNSC_FLAGS"):
runsc_argv += [x for x in shlex.split(os.environ.get("RUNSC_FLAGS", "")) if x] runsc_argv += [x for x in shlex.split(os.environ.get("RUNSC_FLAGS", "")) if x]
runsc_argv += ["run", "--bundle=/home/dangerzone/dangerzone-image", "dangerzone"] runsc_argv += ["run", "--bundle=/", "dangerzone"]
log( log(
"Running gVisor with command line: {}", " ".join(shlex.quote(s) for s in runsc_argv) "Running gVisor with command line: {}", " ".join(shlex.quote(s) for s in runsc_argv)
) )

View file

@ -1,5 +1,11 @@
# gVisor integration # gVisor integration
> [!NOTE]
> **Update on 2025-01-13:** There is no longer a copied container image under
> `/home/dangerzone/dangerzone-image/rootfs`. We now reuse the same container
> image both for the inner and outer container. See
> [#1048](https://github.com/freedomofpress/dangerzone/issues/1048).
Dangerzone has relied on the container runtime available in each supported Dangerzone has relied on the container runtime available in each supported
operating system (Docker Desktop on Windows / macOS, Podman on Linux) to isolate operating system (Docker Desktop on Windows / macOS, Podman on Linux) to isolate
the host from the sanitization process. The problem with this type of isolation the host from the sanitization process. The problem with this type of isolation