[bug#77288,1/6] syscalls: Add ‘unshare’.

Message ID cebcab1f748134ca795992b946fff23cbe66cecc.1743007256.git.ludo@gnu.org
State New
Headers
Series Rootless guix-daemon on Guix System |

Commit Message

Ludovic Courtès March 26, 2025, 4:51 p.m. UTC
  * guix/build/syscalls.scm (unshare): New procedure.

Change-Id: I344273b8bdeaa9366334e6e20ee7efc37eb6c8f7
---
 guix/build/syscalls.scm | 18 ++++++++++++++++++
 tests/syscalls.scm      |  9 +++++++++
 2 files changed, 27 insertions(+)
  

Patch

diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 42232fc7f1..cf09cae3a4 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -145,6 +145,7 @@  (define-module (guix build syscalls)
             CLONE_NEWPID
             CLONE_NEWNET
             clone
+            unshare
             setns
 
             kexec-load-file
@@ -1213,6 +1214,23 @@  (define clone
                    (list err))
             ret)))))
 
+(define unshare
+  (let ((proc (syscall->procedure int "unshare" (list int))))
+    (lambda (flags)
+      "Disassociate the current process from parts of its execution context
+according to FLAGS, which must be a logical or of CLONE_NEW* constants.
+
+Note that CLONE_NEWUSER requires that the calling process be single-threaded,
+which is possible if and only if libgc is running a single marker thread; this
+can be achieved by setting the GC_MARKERS environment variable to 1.  If the
+calling process is multi-threaded, this throws to 'system-error' with EINVAL."
+      (let-values (((ret err)
+                    (without-automatic-finalization (proc flags))))
+        (unless (zero? ret)
+          (throw 'system-error "unshare" "~a: ~A"
+                 (list flags (strerror err))
+                 (list err)))))))
+
 (define setns
   ;; Some systems may be using an old (pre-2.14) version of glibc where there
   ;; is no 'setns' function available.
diff --git a/tests/syscalls.scm b/tests/syscalls.scm
index d2848879d7..879c3e4f25 100644
--- a/tests/syscalls.scm
+++ b/tests/syscalls.scm
@@ -149,6 +149,15 @@  (define perform-container-tests?
             ((_ . status)
              (= 42 (status:exit-val status))))))))
 
+(test-equal "unshare"
+  EPERM
+  ;; Unless running as root, (unshare CLONE_NEWNS) returns EPERM.
+  (catch 'system-error
+    (lambda ()
+      (unshare CLONE_NEWNS))
+    (lambda args
+      (system-error-errno args))))
+
 (unless perform-container-tests?
   (test-skip 1))
 (test-assert "setns"