nsresource: allow multiple userns from the same process in parallel

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.
This commit is contained in:
Lennart Poettering
2025-11-06 10:46:58 +01:00
parent 14d9f58823
commit aae054e1ab

View File

@@ -15,30 +15,44 @@
#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;
}