Skip to content

Commit 45ba547

Browse files
committed
feat(vm): support shared folder mounts
Signed-off-by: hasnatelias <eliashasnat@outlook.jp>
1 parent 71c3cd9 commit 45ba547

15 files changed

Lines changed: 835 additions & 6 deletions

File tree

‎crates/openshell-core/src/driver_mounts.rs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@ pub fn path_is_or_under(path: &Path, parent: &Path) -> bool {
220220
path == parent || path.starts_with(parent)
221221
}
222222

223-
fn paths_overlap(left: &Path, right: &Path) -> bool {
223+
/// Return true when either path is the other or contains it.
224+
pub fn paths_overlap(left: &Path, right: &Path) -> bool {
224225
path_is_or_under(left, right) || path_is_or_under(right, left)
225226
}
226227

‎crates/openshell-driver-vm/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ Select the VM driver with `--compute-driver vm`, `OPENSHELL_COMPUTE_DRIVER=vm`,
174174
| `proxy_connect_by_hostname` | unset | Send hostnames rather than validated IPs in CONNECT. Last resort for proxies whose ACLs reject IP CONNECT targets. |
175175
| `proxy_ca_bundle` | unset | Gateway-host PEM CA bundle trusted for the corporate proxy and TLS-intercepted server certificates. The driver validates it and stages it at a fixed non-secret guest path in the protected overlay. Requires `https_proxy`. |
176176
| `provider_spiffe_workload_api_tcp_endpoint` | unset | Explicit guest-reachable `tcp:IP:port` SPIFFE Workload API listener for provider token exchange. It requires `provider_spiffe_allow_guest_tcp = true`; a host UNIX socket is never silently exposed to a VM guest. |
177+
| `enable_bind_mounts` | `false` | Allow per-sandbox `driver_config.vm.mounts` host directory shares (libkrun virtiofs only). The driver writes a `tag\ttarget\tmode` manifest to `/.openshell/mounts.manifest` in the overlay, and guest init mounts each share after `/sandbox` ownership fixups. Rejected while resource admission is enabled. |
177178
178179
The proxy settings are operator-owned and deployment-level: they are not accepted through `template.driver_config.vm`, and the driver passes them only to native host control. Every present-but-invalid value is fatal at gateway or sandbox startup rather than degrading to a direct dial.
179180

‎crates/openshell-driver-vm/runtime/kernel/openshell.kconfig‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ CONFIG_VIRTIO_BLK=y
1515
CONFIG_EXT4_FS=y
1616
CONFIG_EXT4_USE_FOR_EXT2=y
1717

18+
# Host-directory sharing via virtiofs (used for VM driver bind mounts).
19+
CONFIG_FUSE_FS=y
20+
CONFIG_VIRTIO_FS=y
21+
1822
# Cgroups used for process supervision and resource limits.
1923
CONFIG_CGROUPS=y
2024
CONFIG_CGROUP_DEVICE=y

‎crates/openshell-driver-vm/scripts/openshell-vm-sandbox-init.sh‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,73 @@ run_openshell_init_dropins() {
544544
done < <(LC_ALL=C sort -u "$manifest")
545545
}
546546

547+
# Create a virtiofs mount point under ROOT_PREFIX without following symlinks,
548+
# so an image cannot redirect a validated target onto another guest path.
549+
# Directories created under /sandbox are handed to the sandbox user.
550+
prepare_virtiofs_target() {
551+
local target="$1" owner="$2"
552+
local path="${ROOT_PREFIX:-}" component
553+
local -a components
554+
IFS=/ read -r -a components <<<"${target#/}"
555+
for component in "${components[@]}"; do
556+
[ -n "$component" ] || continue
557+
path="${path}/${component}"
558+
if [ -L "$path" ]; then
559+
ts >&2 "FATAL: virtiofs mount target ${target} traverses symlink ${path#"${ROOT_PREFIX:-}"}"
560+
exit 1
561+
fi
562+
if [ ! -e "$path" ]; then
563+
if ! mkdir "$path"; then
564+
ts >&2 "FATAL: failed to create virtiofs mount point ${target}"
565+
exit 1
566+
fi
567+
case "${path#"${ROOT_PREFIX:-}"}" in
568+
/sandbox/*)
569+
if ! chown "$owner" "$path"; then
570+
ts >&2 "FATAL: failed to hand virtiofs mount point parent ${path#"${ROOT_PREFIX:-}"} to ${owner}"
571+
exit 1
572+
fi
573+
;;
574+
esac
575+
elif [ ! -d "$path" ]; then
576+
ts >&2 "FATAL: virtiofs mount target ${target} is not a directory"
577+
exit 1
578+
fi
579+
done
580+
printf '%s\n' "$path"
581+
}
582+
583+
# Runs after every /sandbox ownership fixup and the root-run init drop-ins so
584+
# nothing in init walks into host-backed shares.
585+
mount_virtiofs_shares() {
586+
local manifest
587+
manifest="$(root_path /.openshell/mounts.manifest)"
588+
[ -f "$manifest" ] || return 0
589+
590+
ts "mounting virtiofs shares"
591+
local tag target mode mount_opts guest_target owner
592+
owner="$(sandbox_owner)"
593+
while IFS=$'\t' read -r tag target mode; do
594+
[ -n "$tag" ] || continue
595+
case "$mode" in
596+
ro) mount_opts="-o ro" ;;
597+
rw) mount_opts="" ;;
598+
*)
599+
ts "FATAL: unknown virtiofs mount mode '${mode}' for tag ${tag}"
600+
exit 1
601+
;;
602+
esac
603+
guest_target="$(prepare_virtiofs_target "$target" "$owner")" || exit 1
604+
# shellcheck disable=SC2086
605+
if mount -t virtiofs $mount_opts "$tag" "$guest_target"; then
606+
ts " mounted virtiofs ${tag} -> ${target} (${mode})"
607+
else
608+
ts "FATAL: failed to mount virtiofs ${tag} at ${target}"
609+
exit 1
610+
fi
611+
done < "$manifest"
612+
}
613+
547614
run_post_overlay_setup() {
548615
# Source QEMU-injected environment variables if present. The file lives in
549616
# the overlay upperdir so the cached bootstrap rootfs remains immutable.
@@ -617,6 +684,8 @@ fi
617684

618685
run_openshell_init_dropins
619686

687+
mount_virtiofs_shares
688+
620689
if [ -n "${OPENSHELL_SANDBOX_ID:-}" ]; then
621690
ts "OPENSHELL_SANDBOX_ID=${OPENSHELL_SANDBOX_ID}"
622691
fi

0 commit comments

Comments
 (0)