--mount now accepts <host-path>:<guest-path> (Docker-style). When the
guest path is omitted, the host path is used. Non-absolute guest paths
are resolved against the image WORKINGDIR, which is written to
/slim/workdir at build time and read by slim-init.sh at boot.
Changes:
- qemu.rs: Parse host:guest spec, pass guest path (not host path) on
the kernel cmdline as slim.mount=<tag>:<base64(guest_path)>
- inject.rs: Accept working_dir param, write /slim/workdir into rootfs
- build.rs: Pass config.working_dir to inject()
- slim-init.sh: Read /slim/workdir, resolve relative guest paths
against it before mounting
- test.sh: Test host:guest absolute paths (multi-mount) and relative
guest path resolved against WORKINGDIR
Addresses PR #9 review comment from @hulthe.
QEMU QemuOpts splits on commas; escape literal commas in the host
path as ,, per QEMU convention to prevent option injection and
boot failures on paths containing commas.
Fix U5: extract b64dec() helper in slim-init.sh
Deduplicate the 3-line base64 fallback decode block used by both
the slim.mount and slim.cmd handlers into a single b64dec() function.
Fix U6: add multi-mount test case
test_mount now passes two --mount flags and asserts both slim0
and slim1 9p tags appear, covering the multi-mount tag-generation
path.
Add support for sharing host directories into the VM via QEMU 9p
(virtio-9p). The --mount flag can be repeated; each host directory
appears at the same absolute path inside the VM.
Design:
- QEMU: each --mount gets a short 9p tag (slim0, slim1, …) via
-virtfs local,path=…,mount_tag=slimN,security_model=mapped-xattr.
Tags are kept short because 9p mount_tag has a ~31-byte limit.
- Kernel cmdline: the full destination path is passed as
slim.mount=<tag>:<base64(path)> so the init script knows where to
mount each tag. Base64 avoids issues with spaces/special chars.
- slim-init.sh: after networking, parse slim.mount= entries, mkdir -p
the destination, and mount -t 9p <tag> <dest> -o trans=virtio,version=9p2000.L
Tests verify: 9p share detection via sysfs mount_tag, 9p entry in
mount output, file content accessible at the expected path, and clean
VM exit.
Add support for the Dockerfile USER directive so that the container's
CMD/ENTRYPOINT runs as the configured user instead of root.
Changes:
- inject.rs: Add user field to Config struct, write /slim/user at
build time
- build.rs: Pass config.user through to inject()
- slim-init.sh: Read /slim/user and drop privileges via su before
executing the command. Numeric uids are resolved to usernames via
/etc/passwd (BusyBox su does not accept numeric args). When dropping
privileges, run as a child (not exec) so PID 1 stays root and can
poweroff after the command exits.
- test.sh: Add test_user verifying build-time CMD and --cmd override
both run as the configured user
Closes#7
The user-supplied image/name argument was interpolated unsanitized into
registry/{name}/initrd, so a name containing '../' (e.g. 'slim run
../../.ssh/authorized_keys') escaped the XDG data dir and let slim
create directories and read/write files at attacker-chosen locations.
validate_image_name now rejects empty names, '.', '..' and anything
outside [A-Za-z0-9._:-] at the registry_dir chokepoint used by both
build and run, plus a defense-in-depth containment check that the
resolved path stays under the registry root.
Fixes sec-2 from the code review.
- build: the rootless overlay mount only exists inside podman unshare's
user namespace; run the vmlinuz check/copy and the find|cpio pipeline
there, streaming cpio's stdout to the parent for gzipping (also drops
the initrd.tmp round-trip and excludes vmlinuz from the archive)
- build: unmount the image on all code paths, not just success
- run: treat timeout's exit 124 as the expected smoke-test timeout and
error on any other non-zero status (a missing qemu binary no longer
reports success)
Fixes bug-1, bug-2, bug-3 from the code review.