[PATCH] nptl: Isolate tst-setuid-eagain RLIMIT_SIGPENDING accounting in a user namespace
Adhemerval Zanella
adhemerval.zanella@linaro.org
Mon Sep 21 19:33:57 GMT 2026
The test now moves itself to a new user namespace before creating any
thread. The kernel compares the limit against the counter of the task's
own user namespace (the parent namespaces are only checked against the
limit captured when the namespace was created), so only the signals queued
by the test are accounted. The original user ID is mapped so setresuid
still operates on a valid ID. If a user namespace cannot be created, the
test prints a warning and runs as before.
It improves the test reliability with check-parallel.
Checked on x86_64-linux-gnu, with a helper process holding queued realtime
signals and dequeuing one every 300 ms: the test fails on every run
without this change and passes with it.
---
nptl/tst-setuid-eagain.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/nptl/tst-setuid-eagain.c b/nptl/tst-setuid-eagain.c
index bc942485a6d..c856dd4257b 100644
--- a/nptl/tst-setuid-eagain.c
+++ b/nptl/tst-setuid-eagain.c
@@ -30,15 +30,19 @@
the queue drains. */
#include <errno.h>
+#include <fcntl.h>
#include <pthread.h>
+#include <sched.h>
#include <semaphore.h>
#include <signal.h>
+#include <stdio.h>
#include <sys/resource.h>
#include <time.h>
#include <unistd.h>
#include <support/check.h>
#include <support/xthread.h>
+#include <support/xunistd.h>
/* How long to wait for the (no-op) setxid to complete before concluding it
is correctly blocking on the full queue. It should not return until the
@@ -72,9 +76,44 @@ setxid_thread (void *closure)
return NULL;
}
+/* The RLIMIT_SIGPENDING accounting is shared by all the processes of the same
+ real user ID within a user namespace. If another process of the same user
+ dequeues one of its pending signals while the setxid is expected to block,
+ a tgkill succeeds and the setxid returns early.
+ Move the test to a new user namespace so the accounting only covers the
+ signals queued by the test itself. It must be called while the process is
+ still single-threaded. */
+static bool
+isolate_sigpending (void)
+{
+#ifdef CLONE_NEWUSER
+ uid_t uid = getuid ();
+ if (unshare (CLONE_NEWUSER) != 0)
+ return false;
+
+ /* Map the original user ID, so the setresuid operates on a valid ID. */
+ char buf[64];
+ int len = snprintf (buf, sizeof (buf), "%llu %llu 1\n",
+ (unsigned long long int) uid,
+ (unsigned long long int) uid);
+ TEST_VERIFY_EXIT (len > 0 && len < sizeof (buf));
+ int fd = xopen ("/proc/self/uid_map", O_WRONLY, 0);
+ xwrite (fd, buf, len);
+ xclose (fd);
+ return true;
+#else
+ return false;
+#endif
+}
+
static int
do_test (void)
{
+ if (!isolate_sigpending ())
+ printf ("warning: could not create a user namespace (%m); the test "
+ "might fail spuriously if other processes of the same user "
+ "dequeue realtime signals\n");
+
TEST_COMPARE (sem_init (&setxid_done, 0, 0), 0);
TEST_COMPARE (sem_init (&worker_exit, 0, 0), 0);
xpthread_barrier_init (&start_barrier, NULL, 3);
--
2.53.0
More information about the Libc-alpha
mailing list