summaryrefslogtreecommitdiff
path: root/gnu/tests
diff options
context:
space:
mode:
authorGiacomo Leidi <therewasa@fishinthecalculator.me>2026-06-07 23:45:09 +0200
committerGiacomo Leidi <therewasa@fishinthecalculator.me>2026-06-15 11:38:46 +0200
commit518129e1130f6cc6e128af0729d678e94b7dfefd (patch)
tree4fbfbc76fc6348c753802c2dcd6a4b5c7e7fbefc /gnu/tests
parent1fa2e6739e6d37d5b4234dc065222c29309a1da8 (diff)
linux-container: Remount / recursively as MS_PRIVATE, immediately after entering the new mount namespace.
Apply the same workaround that runc, crun, and buildah apply unconditionally: immediately after entering the new mount namespace, remount / recursively as MS_PRIVATE. Concretely, the call we will make in Guile mirrors the verbatim C call already present in crun at https://github.com/containers/crun/blob/99a8512ef50c5af1b8cfff28eacddf870220ca9f/src/libcrun/linux.c#L4677: ret = mount (NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL); and the Go equivalents in: - runc (defaults to MS_SLAVE for reasons documented in its pivotRoot): https://github.com/opencontainers/runc/blob/a7e766484c38be1f0cf9b7d960c9324316cb7204/libcontainer/rootfs_linux.go#L1106 - buildah (expands to mount("", "/", "none", MS_REC|MS_PRIVATE, "")): https://github.com/podman-container-tools/buildah/blob/769d311d739dd4bbde496a9480879ce6aadaa1e0/bind/mount.go#L41 Our implementation: 1. Detaches the container's mount namespace from the host's propagation peer group, so subsequent mount/umount events inside the container do not propagate to the host. 2. Makes the kernel's pivot_root(2) preconditions satisfied: both new_root (the tmpfs we then create) and its parent (/) have propagation type MS_PRIVATE. 3. Should have no effect on processes outside the new mount namespace. The host's / retains whatever propagation type it had. mount-file-systems is only invoked from run-container when both 'mnt namespace is requested and root != "/", so we are guaranteed to be inside a fresh mount namespace at this point and that the remount only affects this namespace. The remount must happen before the tmpfs is created. Once the tmpfs exists as a child of the (shared) host /, fixing only the host / does not retroactively change the propagation type the tmpfs already inherited. Doing the remount first means every subsequent mount this function performs inherits MS_PRIVATE from its parent. * guix/build/syscalls.scm (MS_PRIVATE): New variable. * gnu/build/linux-container.scm (mount-file-systems): Remount / recursively as MS_PRIVATE, immediately after entering the new mount namespace. * gnu/services/containers.scm (%miniflux-create-admin-credentials, %rootless-podman-os-with-least-authority-wrapper, run-rootless-podman-test-with-least-authority-wrapper): New bindings. (%test-rootless-podman-with-least-authority-wrapper): New regression test making sure the rootless-podman-service-type does not break again least-authority-wrapper bases services. Fixes: https://codeberg.org/guix/guix/issues/3233 Merges: https://codeberg.org/guix/guix/pulls/9140
Diffstat (limited to 'gnu/tests')
-rw-r--r--gnu/tests/containers.scm97
1 files changed, 96 insertions, 1 deletions
diff --git a/gnu/tests/containers.scm b/gnu/tests/containers.scm
index 6fb7d6d5463..6b7dd7f355f 100644
--- a/gnu/tests/containers.scm
+++ b/gnu/tests/containers.scm
@@ -1,5 +1,5 @@
1;;; GNU Guix --- Functional package management for GNU 1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2024, 2025 Giacomo Leidi <therewasa@fishinthecalculator.me> 2;;; Copyright © 2024-2026 Giacomo Leidi <therewasa@fishinthecalculator.me>
3;;; 3;;;
4;;; This file is part of GNU Guix. 4;;; This file is part of GNU Guix.
5;;; 5;;;
@@ -22,16 +22,19 @@
22 #:use-module (guix build-system trivial) 22 #:use-module (guix build-system trivial)
23 #:use-module (gnu packages bash) 23 #:use-module (gnu packages bash)
24 #:use-module (gnu packages containers) 24 #:use-module (gnu packages containers)
25 #:use-module (gnu packages databases)
25 #:use-module (gnu packages guile) 26 #:use-module (gnu packages guile)
26 #:use-module (gnu packages guile-xyz) 27 #:use-module (gnu packages guile-xyz)
27 #:use-module (gnu services) 28 #:use-module (gnu services)
28 #:use-module (gnu services containers) 29 #:use-module (gnu services containers)
30 #:use-module (gnu services databases)
29 #:use-module (gnu services desktop) 31 #:use-module (gnu services desktop)
30 #:use-module ((gnu services docker) 32 #:use-module ((gnu services docker)
31 #:select (containerd-service-type 33 #:select (containerd-service-type
32 docker-service-type)) 34 docker-service-type))
33 #:use-module (gnu services dbus) 35 #:use-module (gnu services dbus)
34 #:use-module (gnu services networking) 36 #:use-module (gnu services networking)
37 #:use-module (gnu services web)
35 #:use-module (gnu system) 38 #:use-module (gnu system)
36 #:use-module (gnu system accounts) 39 #:use-module (gnu system accounts)
37 #:use-module (gnu system vm) 40 #:use-module (gnu system vm)
@@ -43,6 +46,7 @@
43 #:use-module ((guix scripts pack) #:prefix pack:) 46 #:use-module ((guix scripts pack) #:prefix pack:)
44 #:use-module (guix store) 47 #:use-module (guix store)
45 #:export (%test-rootless-podman 48 #:export (%test-rootless-podman
49 %test-rootless-podman-with-least-authority-wrapper
46 %test-oci-service-rootless-podman 50 %test-oci-service-rootless-podman
47 %test-oci-service-docker)) 51 %test-oci-service-docker))
48 52
@@ -69,6 +73,42 @@
69 (supplementary-groups '("wheel" "netdev" "cgroup" 73 (supplementary-groups '("wheel" "netdev" "cgroup"
70 "audio" "video"))))))) 74 "audio" "video")))))))
71 75
76(define %miniflux-create-admin-credentials
77 #~(begin
78 (mkdir "/var/miniflux")
79 (call-with-output-file "/var/miniflux/admin-username"
80 (lambda (port)
81 (display "test" port)))
82 (call-with-output-file "/var/miniflux/admin-password"
83 (lambda (port)
84 (display "testpassword" port)))))
85
86;; A separate operating-system definition is necessary to test the interactions
87;; between rootless podman and least-authority-wrapper backed services, miniflux
88;; in this case. For the purpose of the test, any service using it should be
89;; fine though.
90(define %rootless-podman-os-with-least-authority-wrapper
91 (simple-operating-system
92 (service rootless-podman-service-type
93 (rootless-podman-configuration
94 (subgids
95 (list (subid-range (name "alice"))))
96 (subuids
97 (list (subid-range (name "alice"))))))
98 (service dhcpcd-service-type)
99 (service dbus-root-service-type)
100 (service polkit-service-type)
101 (service elogind-service-type)
102 (simple-service 'create-miniflux-admin-credentials
103 activation-service-type
104 %miniflux-create-admin-credentials)
105 (service postgresql-service-type
106 (postgresql-configuration
107 (postgresql postgresql)))
108 (service miniflux-service-type
109 (miniflux-configuration
110 (listen-address "/var/run/miniflux/miniflux.sock")))))
111
72(define (run-rootless-podman-test oci-tarball) 112(define (run-rootless-podman-test oci-tarball)
73 113
74 (define os 114 (define os
@@ -345,12 +385,67 @@ standard output device and then enters a new line.")
345 #:localstatedir? #t))) 385 #:localstatedir? #t)))
346 (run-rootless-podman-test tarball))) 386 (run-rootless-podman-test tarball)))
347 387
388(define (run-rootless-podman-test-with-least-authority-wrapper)
389
390 (define os
391 (marionette-operating-system
392 %rootless-podman-os-with-least-authority-wrapper
393 #:imported-modules '((gnu services herd)
394 (guix combinators))))
395
396 (define vm
397 (virtual-machine
398 (operating-system os)
399 (volatile? #t)
400 (memory-size 1024)
401 (disk-image-size (* 3000 (expt 2 20)))
402 (port-forwardings '())))
403
404 (define test
405 (with-imported-modules '((gnu build marionette)
406 (gnu services herd))
407 #~(begin
408 (use-modules (srfi srfi-11) (srfi srfi-64)
409 (gnu build marionette))
410
411 (define marionette
412 ;; Relax timeout to accommodate older systems and
413 ;; allow for pulling the image.
414 (make-marionette (list #$vm) #:timeout 60))
415
416 (test-runner-current (system-test-runner #$output))
417
418 (test-begin "rootless-podman-with-least-authority-wrapper")
419
420 (test-assert "services start correctly"
421 (marionette-eval
422 '(begin
423 (use-modules (gnu services herd))
424 (wait-for-service 'file-system-/sys/fs/cgroup)
425 (wait-for-service 'miniflux))
426 marionette))
427
428 (test-assert "Check miniflux socket file is created"
429 (wait-for-unix-socket "/var/run/miniflux/miniflux.sock" marionette))
430
431 (test-end))))
432 (gexp->derivation "rootless-podman-with-least-authority-wrapper-test" test))
433
348(define %test-rootless-podman 434(define %test-rootless-podman
349 (system-test 435 (system-test
350 (name "rootless-podman") 436 (name "rootless-podman")
351 (description "Test rootless Podman service.") 437 (description "Test rootless Podman service.")
352 (value (build-tarball&run-rootless-podman-test)))) 438 (value (build-tarball&run-rootless-podman-test))))
353 439
440(define %test-rootless-podman-with-least-authority-wrapper
441 (system-test
442 (name "rootless-podman-with-least-authority-wrapper")
443 (description "Test rootless Podman service, making sure services based on
444least-authority-wrapper keep working. See
445https://codeberg.org/guix/guix/issues/3233 for an example of how it has broken
446in the past.")
447 (value (run-rootless-podman-test-with-least-authority-wrapper))))
448
354(define %guile-oci-image 449(define %guile-oci-image
355 (oci-image 450 (oci-image
356 (repository "guile") 451 (repository "guile")