test: make boot mode work in unprivileged containers

In a mount namespace owned by a non-initial user namespace, the kernel
only allows mounting a fresh proc or sysfs if the namespace already
contains a fully visible mount of the same filesystem type
(mount_too_revealing()). systemd-nspawn's pivoted root contains no such
mount, so booting the test container inside an unprivileged container
(e.g. a containerized CI runner) fails with EPERM when mounting /proc.

When running in a non-initial user namespace, satisfy the check by
binding a read-only instance of each into the container under /work.
Skipping the binds on regular privileged runs keeps the container
isolated from the host's proc and sysfs. Binding non-recursively keeps
foreign submounts (e.g. lxcfs overmounts) out, which would spoil full
visibility where they end up locked, and which read-only would not
cover.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>
This commit is contained in:
Paul Meyer
2026-08-27 10:00:30 +02:00
parent 4d6cea8de6
commit 3904661440
@@ -365,6 +365,15 @@ def process_coverage(args: argparse.Namespace, summary: Summary, name: str, jour
print(f'Wrote coverage report for {name} to {output}', file=sys.stderr)
def in_userns() -> bool:
# The initial user namespace has a well-known inode number (USER_NS_INIT_INO, linux/nsfs.h).
# Without kernel support for user namespaces, ours can only be the initial one.
try:
return os.stat('/proc/self/ns/user').st_ino != 0xEFFFFFFD
except OSError:
return False
def coco_host_type() -> Optional[str]:
try:
if Path('/sys/module/kvm_intel/parameters/tdx').read_text().strip() == 'Y':
@@ -706,7 +715,26 @@ def main() -> None:
*(['--runtime-build-sources=no', '--register=no'] if not sys.stdin.isatty() else []),
'vm' if vm else 'boot',
*(
['--', '--capability=CAP_BPF', f'--suppress-sync={"yes" if args.suppress_sync else "no"}', *vm_images_args, *coco_boot_args]
[
'--',
'--capability=CAP_BPF',
f'--suppress-sync={"yes" if args.suppress_sync else "no"}',
# In a non-initial user namespace the kernel only allows mounting a fresh proc or
# sysfs if the mount namespace already contains a fully visible mount of the same
# filesystem type (mount_too_revealing()), which nspawn's pivoted root doesn't.
# Satisfy the check with read-only binds, but only when actually confined, as
# they expose the outer proc and sysfs to the container. Bind non-recursively:
# carried-along submounts (e.g. lxcfs overmounts of container runtimes) would
# spoil full visibility wherever they end up locked, and --bind-ro wouldn't make
# them read-only either.
*(
['--bind-ro=/proc:/work/proc:norbind', '--bind-ro=/sys:/work/sys:norbind']
if in_userns()
else []
),
*vm_images_args,
*coco_boot_args,
]
if not vm
else []
),