New privileged helper at /usr/local/libexec/left4me/left4me-overlay (Python, system /usr/bin/python3, stdlib only) takes only the instance name, parses instance.env for L4D2_LOWERDIRS, validates each lowerdir against an allowlist (installation/, overlays/, global_overlay_cache/, workshop_cache/), refuses upperdirs tainted with user.fuseoverlayfs.* xattrs from the prior fuse era, and execs `nsenter --mount=/proc/1/ns/mnt -- mount -t overlay ...` so the resulting mount lives in the host namespace. Mirrors the existing left4me-systemctl / left4me-journalctl pattern; sudoers entry is verb-constrained. KernelOverlayFSMounter implements the existing OverlayMounter ABC, deriving the instance name from the merged path. No call sites use it yet — that's the next commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
53 lines
1.7 KiB
Python
53 lines
1.7 KiB
Python
from pathlib import Path
|
|
from typing import Callable
|
|
|
|
from l4d2host.fs.base import OverlayMounter
|
|
from l4d2host.process import run_command
|
|
|
|
|
|
HELPER_PATH = "/usr/local/libexec/left4me/left4me-overlay"
|
|
|
|
|
|
class KernelOverlayFSMounter(OverlayMounter):
|
|
# Delegates the actual mount/umount syscalls to the privileged
|
|
# left4me-overlay helper. The helper takes only the instance name and
|
|
# rederives lowerdirs/upper/work/merged from disk; the OverlayMounter
|
|
# ABC accepts those args for compatibility, so we extract the name
|
|
# from the merged path's parent directory.
|
|
def mount(
|
|
self,
|
|
*,
|
|
lowerdirs: str,
|
|
upperdir: Path,
|
|
workdir: Path,
|
|
merged: Path,
|
|
on_stdout: Callable[[str], None] | None = None,
|
|
on_stderr: Callable[[str], None] | None = None,
|
|
passthrough: bool = False,
|
|
should_cancel: Callable[[], bool] | None = None,
|
|
) -> None:
|
|
del lowerdirs, upperdir, workdir
|
|
run_command(
|
|
["sudo", "-n", HELPER_PATH, "mount", merged.parent.name],
|
|
on_stdout=on_stdout,
|
|
on_stderr=on_stderr,
|
|
passthrough=passthrough,
|
|
should_cancel=should_cancel,
|
|
)
|
|
|
|
def unmount(
|
|
self,
|
|
*,
|
|
merged: Path,
|
|
on_stdout: Callable[[str], None] | None = None,
|
|
on_stderr: Callable[[str], None] | None = None,
|
|
passthrough: bool = False,
|
|
should_cancel: Callable[[], bool] | None = None,
|
|
) -> None:
|
|
run_command(
|
|
["sudo", "-n", HELPER_PATH, "umount", merged.parent.name],
|
|
on_stdout=on_stdout,
|
|
on_stderr=on_stderr,
|
|
passthrough=passthrough,
|
|
should_cancel=should_cancel,
|
|
)
|