]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nsresource: allow multiple userns from the same process in parallel
authorLennart Poettering <lennart@poettering.net>
Thu, 6 Nov 2025 09:46:58 +0000 (10:46 +0100)
committerLennart Poettering <lennart@poettering.net>
Sat, 8 Nov 2025 17:32:37 +0000 (18:32 +0100)
When generating a name for a transient userns automatically we so far
just included our PID to make it unique. That doens't really work if
multiple userns shall be kept in parallel by a single process. Let's hence
include a counter as well.

src/shared/nsresource.c

index a5d1ee7034f1cd318afc6601b67629757fb39145..eef72e631bcf6a8a2f7ee9ebdc688390885a0264 100644 (file)
 #include "process-util.h"
 #include "string-util.h"
 
+/* Maximum namespace name length */
+#define NAMESPACE_NAME_MAX 16U
+
+/* So the namespace name should be 16 chars at max (because we want that it is usable in usernames, which
+ * have a limit of 31 chars effectively, and the nsresourced service wants to prefix/suffix some bits). But
+ * it also should be unique if we are called multiple times in a row. Hence we take the "comm" name (which is
+ * 15 chars), and suffix it with the PID and a counter, possibly overriding the end. */
+assert_cc(TASK_COMM_LEN == NAMESPACE_NAME_MAX);
+
 static int make_pid_name(char **ret) {
         char comm[TASK_COMM_LEN];
+        static uint64_t counter = 0;
 
         assert(ret);
 
         if (prctl(PR_GET_NAME, comm) < 0)
                 return -errno;
 
-        /* So the namespace name should be 16 chars at max (because we want that it is usable in usernames,
-         * which have a limit of 31 chars effectively, and the nsresourced service wants to prefix/suffix
-         * some bits). But it also should be unique if we are called multiple times in a row. Hence we take
-         * the "comm" name (which is 15 chars), and suffix it with the PID, possibly overriding the end. */
-        assert_cc(TASK_COMM_LEN == 15 + 1);
-
         char spid[DECIMAL_STR_MAX(pid_t)];
         xsprintf(spid, PID_FMT, getpid_cached());
 
-        assert(strlen(spid) <= 16);
-        strshorten(comm, 16 - strlen(spid));
+        /* Include a counter in the name, so that we can allocate multiple namespaces per process, with
+         * unique names. For the first namespace we suppress the suffix */
+        char scounter[sizeof(counter) * 2 + 1];
+        if (counter == 0)
+                scounter[0] = 0;
+        else
+                xsprintf(scounter, "%" PRIx64, counter);
+        counter++;
 
-        _cleanup_free_ char *s = strjoin(comm, spid);
+        strshorten(comm, LESS_BY(NAMESPACE_NAME_MAX, strlen(spid) + strlen(scounter)));
+
+        _cleanup_free_ char *s = strjoin(comm, spid, scounter);
         if (!s)
                 return -ENOMEM;
 
+        strshorten(s, NAMESPACE_NAME_MAX);
+
         *ret = TAKE_PTR(s);
         return 0;
 }