[PATCH 4/5] Linux: Implement per-thread user and group IDs
Florian Weimer
fweimer@redhat.com
Tue Dec 9 17:31:43 GMT 2025
This commit adds the functions pthread_attr_setperthreadids_np and
pthread_attr_getperthreadids_np. Threads created with the new flag
will be exempted from the setxid broadcast. setuid and related
functions will only update the credentials for the current thread.
Multi-threaded file servers typically need this functionality and
call the system calls directly to implement this.
---
NEWS | 5 +
manual/threads.texi | 63 +-
nptl/Makefile | 5 +
nptl/Versions | 2 +
nptl/nptl_setxid.c | 20 +-
nptl/pthread_attr_getperthreadids_np.c | 32 ++
nptl/pthread_attr_setperthreadids_np.c | 39 ++
nptl/tst-pthread-perthreadids.c | 541 ++++++++++++++++++
sysdeps/nptl/internaltypes.h | 3 +-
sysdeps/nptl/pthread.h | 18 +
sysdeps/nptl/pthreadP.h | 8 +
sysdeps/nptl/setxid.h | 2 +-
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 2 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 2 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 2 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 2 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 2 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 2 +
sysdeps/unix/sysv/linux/hppa/libc.abilist | 2 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 2 +
.../sysv/linux/loongarch/lp64/libc.abilist | 2 +
.../sysv/linux/m68k/coldfire/libc.abilist | 2 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 2 +
.../sysv/linux/microblaze/be/libc.abilist | 2 +
.../sysv/linux/microblaze/le/libc.abilist | 2 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 2 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 2 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 2 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 2 +
sysdeps/unix/sysv/linux/or1k/libc.abilist | 2 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 2 +
.../powerpc/powerpc32/nofpu/libc.abilist | 2 +
.../linux/powerpc/powerpc64/be/libc.abilist | 2 +
.../linux/powerpc/powerpc64/le/libc.abilist | 2 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 2 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 2 +
.../unix/sysv/linux/s390/s390-32/libc.abilist | 2 +
.../unix/sysv/linux/s390/s390-64/libc.abilist | 2 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 2 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 2 +
.../sysv/linux/sparc/sparc32/libc.abilist | 2 +
.../sysv/linux/sparc/sparc64/libc.abilist | 2 +
.../unix/sysv/linux/x86_64/64/libc.abilist | 2 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 2 +
44 files changed, 789 insertions(+), 13 deletions(-)
create mode 100644 nptl/pthread_attr_getperthreadids_np.c
create mode 100644 nptl/pthread_attr_setperthreadids_np.c
create mode 100644 nptl/tst-pthread-perthreadids.c
diff --git a/NEWS b/NEWS
index 1bd9f8b795..740b9de0e8 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,11 @@ Major new features:
pthread_attr_setperthreadfs_np and pthread_attr_getperthreadfs_np have
been added in support of that.
+* On Linux, threads can now be created in such a way that they retain
+ per-thread user and group IDs. The functions
+ pthread_attr_setperthreadids_np and pthread_attr_getperthreadids_np have
+ been added in support of that.
+
Deprecated and removed features, and other changes affecting compatibility:
* Support for dumped heaps has been removed - malloc_set_state() now always
diff --git a/manual/threads.texi b/manual/threads.texi
index 8df694cc43..902cf5be00 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -1295,11 +1295,12 @@ This property in question is thread-specific.
The @code{PTHREAD_PER_THREAD_NP} flag is sticky, in the sense that all
threads created by a thread created with this flag have per-thread
-properties, even if they are created with the matching thread
-attribute set to the @code{PTHREAD_PER_PROCESS_NP} flag. If an
-application wants to create new threads sharing properties with the
-main thread, it should create a service thread early (perhaps from an
-ELF constructor) and create these threads using this service thread.
+properties of the requested kind, even if they are created with the
+matching thread attribute set to the @code{PTHREAD_PER_PROCESS_NP}
+flag. If an application wants to create new threads sharing
+properties with the main thread, it should create a service thread
+early (perhaps from an ELF constructor) and create these threads using
+this service thread.
Per-thread properties can be set and examined for an attribute using
the functions below.
@@ -1361,6 +1362,58 @@ Obtain the per-thread status of the file system properties in
This function is a GNU extension and specific to Linux.
@end deftypefun
+@deftypefun int pthread_attr_setperthreadids_np (pthread_attr_t *@var{attr}, int @var{scope})
+@standards{GNU, pthread.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Change whether the following properties related to file system access
+are made thread-specific when a new thread is created using the
+attribute @var{attr}:
+
+@itemize @bullet
+@item
+@cindex per-thread user ID
+@cindex thread-specific user ID
+real, effective and saved user ID (as returned by the
+@code{getresuid} function)
+
+@item
+@cindex per-thread group ID
+@cindex thread-specific group ID
+real, effective and saved group ID (as returned by the
+@code{getresgid} function)
+
+@item
+supplementary group list (as returned by the @code{getgroups}
+function)
+@end itemize
+
+This function returns zero on success. @var{scope} must be one of the
+constants @code{PTHREAD_PER_PROCESS_NP} or
+@code{PTHREAD_PER_THREAD_NP}, otherwise the function returns
+@code{EINVAL}.
+
+If @var{scope} is @code{PTHREAD_PER_THREAD_NP}, the attribute will
+cause the IDs listed above to be specific to the thread. The initial
+values of these IDs are copied from the creating thread, at thread
+creation time.
+
+If a thread that has been created with the
+@code{PTHREAD_PER_THREAD_NP} flag creates further threads, these
+threads are implicitly created with the @code{PTHREAD_PER_THREAD_NP}
+flag, ignoring the value of this thread creation attribute.
+
+This function is a GNU extension and specific to Linux.
+@end deftypefun
+
+@deftypefun int pthread_attr_getperthreadids_np (pthread_attr_t *restrict @var{attr}, int *restrict @var{scope})
+@standards{GNU, pthread.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Obtain the per-thread status of user and group IDs in @var{attr} and
+store it in the location @var{scope}.
+
+This function is a GNU extension and specific to Linux.
+@end deftypefun
+
@node Thread CPU Affinity
@subsubsection Thread CPU Affinity
diff --git a/nptl/Makefile b/nptl/Makefile
index 05c6c32a76..3d1848ebea 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -66,6 +66,7 @@ routines = \
pthread_attr_getguardsize \
pthread_attr_getinheritsched \
pthread_attr_getperthreadfs_np \
+ pthread_attr_getperthreadids_np \
pthread_attr_getschedparam \
pthread_attr_getschedpolicy \
pthread_attr_getscope \
@@ -79,6 +80,7 @@ routines = \
pthread_attr_setguardsize \
pthread_attr_setinheritsched \
pthread_attr_setperthreadfs_np \
+ pthread_attr_setperthreadids_np \
pthread_attr_setschedparam \
pthread_attr_setschedpolicy \
pthread_attr_setscope \
@@ -409,6 +411,9 @@ tests-time64 := \
# and then cause the make process to fail too, see bug 24537.
xtests += tst-eintr1
+# This thread calls various set*id functions.
+xtests += tst-pthread-perthreadids
+
test-srcs = tst-oddstacklimit
gen-as-const-headers = \
diff --git a/nptl/Versions b/nptl/Versions
index c4ff312468..c39faf7fda 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -384,6 +384,8 @@ libc {
GLIBC_2.43 {
pthread_attr_setperthreadfs_np;
pthread_attr_getperthreadfs_np;
+ pthread_attr_setperthreadids_np;
+ pthread_attr_getperthreadids_np;
}
GLIBC_PRIVATE {
__libc_alloca_cutoff;
diff --git a/nptl/nptl_setxid.c b/nptl/nptl_setxid.c
index 3da0d197c7..97caeddec3 100644
--- a/nptl/nptl_setxid.c
+++ b/nptl/nptl_setxid.c
@@ -22,6 +22,14 @@
#include <pthreadP.h>
#include <unistd.h>
+/* The current thread and threads with per-thread user and group IDs
+ are not part of the setxid broadcast. */
+static inline bool
+thread_excluded_from_setxid_broadcast (struct pthread *self, struct pthread *t)
+{
+ return t == self || (t->flags & ATTR_FLAG_PERTHREADIDS);
+}
+
/* Check for consistency across set*id system call results. The abort
should not happen as long as all privileges changes happen through
the glibc wrappers. ERROR must be 0 (no error) or an errno
@@ -189,7 +197,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_used))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
setxid_mark_thread (cmdp, t);
@@ -199,7 +207,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_user))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
setxid_mark_thread (cmdp, t);
@@ -215,7 +223,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_used))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
signalled += setxid_signal_thread (cmdp, t);
@@ -224,7 +232,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_user))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
signalled += setxid_signal_thread (cmdp, t);
@@ -245,7 +253,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_used))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
setxid_unmark_thread (cmdp, t);
@@ -254,7 +262,7 @@ __nptl_setxid (struct xid_command *cmdp)
list_for_each (runp, &GL (dl_stack_user))
{
struct pthread *t = list_entry (runp, struct pthread, list);
- if (t == self)
+ if (thread_excluded_from_setxid_broadcast (self, t))
continue;
setxid_unmark_thread (cmdp, t);
diff --git a/nptl/pthread_attr_getperthreadids_np.c b/nptl/pthread_attr_getperthreadids_np.c
new file mode 100644
index 0000000000..18f88f1f3e
--- /dev/null
+++ b/nptl/pthread_attr_getperthreadids_np.c
@@ -0,0 +1,32 @@
+/* Read the per-thread user/group IDs flag in thread attributes.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <internaltypes.h>
+
+int
+pthread_attr_getperthreadids_np (const pthread_attr_t *__restrict attr,
+ int *__restrict scope)
+{
+ struct pthread_attr *iattr = (struct pthread_attr *) attr;
+ if (iattr->flags & ATTR_FLAG_PERTHREADIDS)
+ *scope = PTHREAD_PER_THREAD_NP;
+ else
+ *scope = PTHREAD_PER_PROCESS_NP;
+ return 0;
+}
diff --git a/nptl/pthread_attr_setperthreadids_np.c b/nptl/pthread_attr_setperthreadids_np.c
new file mode 100644
index 0000000000..5385ab0bae
--- /dev/null
+++ b/nptl/pthread_attr_setperthreadids_np.c
@@ -0,0 +1,39 @@
+/* Change the per-thread user/group IDs flag in thread attributes.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <pthread.h>
+#include <internaltypes.h>
+#include <errno.h>
+
+int
+pthread_attr_setperthreadids_np (pthread_attr_t *attr, int scope)
+{
+ struct pthread_attr *iattr = (struct pthread_attr *) attr;
+ switch (scope)
+ {
+ case PTHREAD_PER_PROCESS_NP:
+ iattr->flags &= ~ATTR_FLAG_PERTHREADIDS;
+ return 0;
+ break;
+ case PTHREAD_PER_THREAD_NP:
+ iattr->flags |= ATTR_FLAG_PERTHREADIDS;
+ return 0;
+ default:
+ return EINVAL;
+ }
+}
diff --git a/nptl/tst-pthread-perthreadids.c b/nptl/tst-pthread-perthreadids.c
new file mode 100644
index 0000000000..05ed098944
--- /dev/null
+++ b/nptl/tst-pthread-perthreadids.c
@@ -0,0 +1,541 @@
+/* Test per-thread user and group IDs.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xthread.h>
+#include <support/xunistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Return true if the thread has per-thread file system attributes.
+ Note: This function calls pthread_getattr_np on THR, so the caller
+ has to ensure that the thread is still running (and not merely
+ joinable). */
+static bool
+perthread_flag (pthread_t thr)
+{
+ pthread_attr_t attr;
+ int ret = pthread_getattr_np (thr, &attr);
+ if (ret != 0)
+ {
+ errno = ret;
+ FAIL_EXIT1 ("pthread_getattr_np: %m");
+ }
+ int flag = -1;
+ pthread_attr_getperthreadids_np (&attr, &flag);
+ if (flag != PTHREAD_PER_THREAD_NP)
+ TEST_COMPARE (flag, PTHREAD_PER_PROCESS_NP);
+ xpthread_attr_destroy (&attr);
+ return flag == PTHREAD_PER_THREAD_NP;
+}
+
+/* Which set*id function to call. */
+enum operation
+{
+ /* No function is called, but the thread will observe changes made by
+ another thread. */
+ OP_NONE,
+
+ OP_SETUID,
+ OP_SETEUID,
+ OP_SETREUID,
+ OP_SETRESUID,
+ OP_SETGID,
+ OP_SETEGID,
+ OP_SETREGID,
+ OP_SETRESGID,
+ OP_SETGROUPS,
+};
+
+/* Convert the operation to a descriptive string. */
+static const char *
+operation_string (enum operation op)
+{
+ switch (op)
+ {
+ case OP_NONE:
+ return "<none>";
+ case OP_SETUID:
+ return "OP_SETUID";
+ case OP_SETEUID:
+ return "OP_SETEUID";
+ case OP_SETREUID:
+ return "OP_SETREUID";
+ case OP_SETRESUID:
+ return "OP_SETRESUID";
+ case OP_SETGID:
+ return "OP_SETGID";
+ case OP_SETEGID:
+ return "OP_SETEGID";
+ case OP_SETREGID:
+ return "OP_SETREGID";
+ case OP_SETRESGID:
+ return "OP_SETRESGID";
+ case OP_SETGROUPS:
+ return "OP_SETGROUPS";
+ }
+
+ FAIL_EXIT1 ("invalid operation: %d", (int) op);
+}
+
+/* One test case to perform. */
+struct test_case
+{
+ enum operation op;
+ int args[3];
+
+ /* Expected UIDs and GIDs are only used if the current thread has
+ made changes. */
+ uid_t expected_uid[3];
+ gid_t expected_gid[3];
+};
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic error "-Wmissing-field-initializers"
+static const struct test_case test_cases[] =
+ {
+ /* op args expected_gid expected_gid. */
+ { OP_NONE, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0} },
+
+ { OP_SETUID, { 1, 0, 0 }, { 1, 1, 1 }, { 0, 0, 0 } },
+ { OP_SETEUID, { 2, 0, 0 }, { 0, 2, 0 }, { 0, 0, 0 } },
+ { OP_SETREUID, { 3, 4, 0 }, { 3, 4, 4 }, { 0, 0, 0 } },
+ { OP_SETRESUID, { 3, 4, 5 }, { 3, 4, 5 }, { 0, 0, 0 } },
+
+ { OP_SETGID, { 6, 0, 0 }, { 0, 0, 0 }, { 6, 6, 6 } },
+ { OP_SETEGID, { 7, 0, 0 }, { 0, 0, 0 }, { 0, 7, 0 } },
+ { OP_SETREGID, { 8, 9, 0 }, { 0, 0, 0 }, { 8, 9, 9 } },
+ { OP_SETRESGID, { 10, 11, 12 }, { 0, 0, 0 }, { 10, 11, 12 } },
+
+ { OP_SETGROUPS, { -1, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } },
+ { OP_SETGROUPS, { 13, -1, 0 }, { 0, 0, 0 }, { 0, 0, 0 } },
+ { OP_SETGROUPS, { 13, 14, -1 }, { 0, 0, 0 }, { 0, 0, 0 } },
+ { OP_SETGROUPS, { 13, 14, 15 }, { 0, 0, 0 }, { 0, 0, 0 } },
+
+ /* Final round of checks. */
+ { OP_NONE, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } },
+ };
+#pragma GCC diagnostic pop
+
+/* Determine the number of supplementary groups in the test case. */
+static size_t
+supplemetary_count (const struct test_case *test)
+{
+ TEST_COMPARE (test->op, OP_SETGROUPS);
+ size_t count = 0;
+ while (count < array_length (test->args))
+ {
+ if (test->args[count] < 0)
+ break;
+ ++count;
+ }
+ return count;
+}
+
+/* Perform the actions in the test case. */
+static void
+test_case_run (const struct test_case *test)
+{
+ int ret = -1;
+ switch (test->op)
+ {
+ case OP_NONE:
+ return;
+
+ case OP_SETUID:
+ ret = setuid (test->args[0]);
+ break;
+ case OP_SETEUID:
+ ret = seteuid (test->args[0]);
+ break;
+ case OP_SETREUID:
+ ret = setreuid (test->args[0], test->args[1]);
+ break;
+ case OP_SETRESUID:
+ ret = setresuid (test->args[0], test->args[1], test->args[2]);
+ break;
+
+ case OP_SETGID:
+ ret = setgid (test->args[0]);
+ break;
+ case OP_SETEGID:
+ ret = setegid (test->args[0]);
+ break;
+ case OP_SETREGID:
+ ret = setregid (test->args[0], test->args[1]);
+ break;
+ case OP_SETRESGID:
+ ret = setresgid (test->args[0], test->args[1], test->args[2]);
+ break;
+
+ case OP_SETGROUPS:
+ {
+ gid_t groups[] = { test->args[0], test->args[1], test->args[2] };
+ ret = setgroups (supplemetary_count (test), groups);
+ }
+ }
+
+ if (ret != 0)
+ FAIL_EXIT1 ("%s (%d, %d, %d): %m (%d)",
+ operation_string (test->op),
+ test->args[0], test->args[1], test->args[2], errno);
+}
+
+/* Used to synchronize between threads changing UIDs/GIDs. */
+static pthread_barrier_t barrier;
+
+/* Used to avoid interleaving the checking phase between threads. */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Argument to the thread. */
+struct thread_argument
+{
+ size_t thread_index;
+
+ /* Do not actually perform the operation, only verify the result.
+ Used for threads participating in the setxid broadcast. */
+ bool suppress_operation;
+
+ /* Run the actual test in a newly created thread, with default
+ attributes. */
+ bool indirect;
+
+ /* Thread is created with per-thread attributes. */
+ bool perthread;
+};
+
+/* Prepare a heap-allocated thread argument which the started thread
+ should free. */
+static struct thread_argument *
+create_thread_argument (struct thread_argument arg)
+{
+ struct thread_argument *result = xmalloc (sizeof (*result));
+ *result = arg;
+ return result;
+}
+
+/* An actual test thread. CLOSURE is a pointer to struct
+ thread_argument, and perform the test according to this
+ information. */
+static void *
+threadfunc (void *closure)
+{
+ struct thread_argument *arg = closure;
+
+ TEST_COMPARE (perthread_flag (pthread_self ()), arg->perthread);
+
+ if (arg->indirect)
+ {
+ /* Only indirect once. */
+ arg->indirect = false;
+ /* Use the default attributes (NULL). This verifies that the
+ per-thread scope is sticky. */
+ return xpthread_join (xpthread_create (NULL, threadfunc, arg));
+ }
+
+ const struct test_case *expected = &test_cases[0];
+ gid_t expected_supplementary[3] = { -1, -1, -1 };
+ int expected_supplementary_count = 0;
+
+ /* (1) Wait until all threads have started up. */
+ xpthread_barrier_wait (&barrier);
+
+ for (size_t test_index = 0; test_index < array_length (test_cases);
+ ++test_index)
+ {
+ if (test_index == arg->thread_index)
+ {
+ if (test_verbose > 0)
+ {
+ if (arg->suppress_operation)
+ printf ("info: thread %zu suppressing operation\n",
+ test_index);
+ else
+ printf ("info: thread %zu performing operation\n",
+ test_index);
+ }
+ if (!arg->suppress_operation)
+ test_case_run (&test_cases[test_index]);
+
+ expected = &test_cases[test_index];
+ if (test_cases[test_index].op == OP_SETGROUPS)
+ {
+ expected_supplementary_count
+ = supplemetary_count (&test_cases[test_index]);
+ for (int i = 0; i < expected_supplementary_count; ++i)
+ expected_supplementary[i] = test_cases[test_index].args[i];
+ }
+ }
+
+ /* (2) Wait until all threads have run the requested test. */
+ xpthread_barrier_wait (&barrier);
+
+ xpthread_mutex_lock (&mutex);
+
+ if (test_verbose > 0)
+ printf ("info: checking phase for thread %zu, test %zu\n",
+ arg->thread_index, test_index);
+ uid_t actual_uid[3];
+ xgetresuid (&actual_uid[0], &actual_uid[1], &actual_uid[2]);
+ TEST_COMPARE (actual_uid[0], expected->expected_uid[0]);
+ TEST_COMPARE (actual_uid[1], expected->expected_uid[1]);
+ TEST_COMPARE (actual_uid[2], expected->expected_uid[2]);
+ gid_t actual_gid[3];
+ xgetresgid (&actual_gid[0], &actual_gid[1], &actual_gid[2]);
+ TEST_COMPARE (actual_gid[0], expected->expected_gid[0]);
+ TEST_COMPARE (actual_gid[1], expected->expected_gid[1]);
+ TEST_COMPARE (actual_gid[2], expected->expected_gid[2]);
+
+ gid_t actual_supplementary[3];
+ gid_t actual_supplementary_count
+ = getgroups (array_length (actual_supplementary),
+ actual_supplementary);
+ TEST_COMPARE (actual_supplementary_count, expected_supplementary_count);
+ if (actual_supplementary_count > 0)
+ TEST_COMPARE (actual_supplementary[0], expected_supplementary[0]);
+ if (actual_supplementary_count > 1)
+ TEST_COMPARE (actual_supplementary[1], expected_supplementary[1]);
+ if (actual_supplementary_count > 2)
+ TEST_COMPARE (actual_supplementary[2], expected_supplementary[2]);
+
+ xpthread_mutex_unlock (&mutex);
+
+ /* (3) Wait until all threads have finished checking their view
+ of the results. */
+ xpthread_barrier_wait (&barrier);
+ }
+
+ free (arg);
+ return NULL;
+}
+
+/* Used to create threads with per-thread user/group IDs. */
+static pthread_attr_t attr_perthreadids;
+
+/* Test which verifies that per-thread IDs are thread-specific. */
+static void
+check_perthread (bool indirect)
+{
+ if (test_verbose > 0)
+ printf ("info: testing per-thread IDs, %s indirection\n",
+ indirect ? "with" : "without");
+ TEST_VERIFY (!perthread_flag (pthread_self ()));
+
+ /* The main thread and another shared thread count as two extra
+ threads. */
+ xpthread_barrier_init (&barrier, NULL, array_length (test_cases) + 2);
+
+ pthread_t perthread_threads[array_length (test_cases)];
+ /* Use thread index zero with OP_NONE for checking only. */
+ pthread_t shared_thread
+ = xpthread_create (NULL, threadfunc,
+ create_thread_argument ((struct thread_argument) { }));
+ /* Thread is still runing because it waits on barrier. */
+ TEST_VERIFY (!perthread_flag (shared_thread));
+
+ for (size_t i = 0; i < array_length (test_cases); ++i)
+ {
+ struct thread_argument *arg
+ = create_thread_argument ((struct thread_argument) {
+ .thread_index = i, .indirect = indirect, .perthread = true });
+ perthread_threads[i]
+ = xpthread_create (&attr_perthreadids, threadfunc, arg);
+ /* Thread is still runing because it waits on barrier (or it is
+ blocked joining a thread which does). */
+ TEST_VERIFY (perthread_flag (perthread_threads[i]));
+ }
+ /* Use thread_index 0 with OP_NONE for checking that the main thread
+ is unchanged. (This also waits on the barrier.) */
+ threadfunc (create_thread_argument ((struct thread_argument) { }));
+ for (size_t i = 0; i < array_length (test_cases); ++i)
+ xpthread_join (perthread_threads[i]);
+ xpthread_join (shared_thread);
+
+ xpthread_barrier_destroy (&barrier);
+}
+
+/* Closure arguments to the subprocess. */
+struct subprocess_argument
+{
+ size_t broadcast_test_index;
+ bool broadcast_from_main;
+ bool indirect;
+};
+
+/* Setting the broadcast UID is destructive, so we need to run it in a
+ subprocess. */
+static void
+subprocess (void *closure)
+{
+ struct subprocess_argument *arg = closure;
+
+ if (test_verbose > 0)
+ printf ("info: testing broadcasting test case %zu,"
+ " %sbroadcasting from main, %s indirection\n",
+ arg->broadcast_test_index,
+ arg->broadcast_from_main ? "" : "not ",
+ arg->indirect ? "with" : "without");
+
+ /* Main thread and two other shared threads are extras. One
+ per-thread test is skipped, so there are two extra threads. */
+ xpthread_barrier_init (&barrier, NULL, array_length (test_cases) + 2);
+
+ pthread_t perthread_threads[array_length (test_cases)];
+ /* Use thread index zero for no-op checking. */
+ pthread_t shared_threads[2];
+ {
+ struct thread_argument thread_arg =
+ {
+ .thread_index = arg->broadcast_test_index,
+ .suppress_operation =arg->broadcast_from_main,
+ };
+ shared_threads[0]
+ = xpthread_create (NULL, threadfunc,
+ create_thread_argument (thread_arg));
+ }
+ {
+ struct thread_argument thread_arg =
+ {
+ .thread_index = arg->broadcast_test_index,
+ .suppress_operation = true,
+ };
+ shared_threads[1]
+ = xpthread_create (NULL, threadfunc,
+ create_thread_argument (thread_arg));
+ }
+
+ for (size_t i = 0; i < array_length (test_cases); ++i)
+ /* Skip the test which uses broadcasting; it does not use the
+ per-thread IDs. */
+ if (i != arg->broadcast_test_index)
+ {
+ struct thread_argument thread_arg =
+ {
+ .thread_index = i,
+ .indirect = arg->indirect,
+ .perthread = true,
+ };
+ perthread_threads[i]
+ = xpthread_create (&attr_perthreadids, threadfunc,
+ create_thread_argument (thread_arg));
+ }
+
+ /* Call threadfunc from the main thread. If not broadcasting from
+ main, only perform checking. */
+ {
+ struct thread_argument thread_arg =
+ {
+ .thread_index = arg->broadcast_test_index,
+ .suppress_operation = !arg->broadcast_from_main,
+ .indirect = arg->indirect,
+ };
+ threadfunc (create_thread_argument (thread_arg));
+ }
+ for (size_t i = 0; i < array_length (test_cases); ++i)
+ /* Skip the test which uses broadcasting. */
+ if (i != arg->broadcast_test_index)
+ xpthread_join (perthread_threads[i]);
+ xpthread_join (shared_threads[0]);
+ xpthread_join (shared_threads[1]);
+
+ xpthread_barrier_destroy (&barrier);
+}
+
+static int
+do_test (void)
+{
+ if (setuid (0) != 0)
+ FAIL_EXIT1 ("setuid (0): %m");
+ if (setgid (0) != 0)
+ FAIL_EXIT1 ("setgid (0): %m");
+ if (setgroups (0, NULL) != 0)
+ FAIL_EXIT1 ("setgroups (0, NULL): %m");
+
+ xpthread_attr_init (&attr_perthreadids);
+ {
+ /* Test: Default is PTHREAD_PER_PROCESS_NP. */
+ int scope = -1;
+ TEST_COMPARE (pthread_attr_getperthreadids_np (&attr_perthreadids, &scope),
+ 0);
+ TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
+
+ /* Test: The getter shows the effect of the setter. */
+ TEST_COMPARE (pthread_attr_setperthreadids_np (&attr_perthreadids,
+ PTHREAD_PER_THREAD_NP), 0);
+ scope = -1;
+ TEST_COMPARE (pthread_attr_getperthreadids_np (&attr_perthreadids, &scope),
+ 0);
+ TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
+
+ /* Test: Invalid scope values result in an error, without a
+ change. */
+ TEST_COMPARE (pthread_attr_setperthreadids_np (&attr_perthreadids, 2),
+ EINVAL);
+ scope = -1;
+ TEST_COMPARE (pthread_attr_getperthreadids_np (&attr_perthreadids, &scope),
+ 0);
+ TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
+ }
+
+ /* Test both the direct and indirect case. Direct is when test
+ threads are launched with a per-thread attribute. Indirect is
+ when a thread is first launched with the a per-thread attribute,
+ but the actual test runs in another sub-thread, created with a
+ NULL attribute. */
+ for (int indirect = 0; indirect < 2; ++indirect)
+ {
+ check_perthread (indirect);
+
+ /* Test two scenarios, one where set*id function is called from
+ the main thread, and other one where it is called from
+ another thread. */
+ for (int broadcast_from_main = 0; broadcast_from_main < 2;
+ ++broadcast_from_main)
+ /* Perform each of the test cases once, using a broadcast
+ set*id operation across multiple threads (those threads
+ which have per-process scope). */
+ for (size_t broadcast_test_index = 0;
+ broadcast_test_index < array_length (test_cases);
+ ++broadcast_test_index)
+ {
+ struct subprocess_argument arg =
+ {
+ .broadcast_test_index = broadcast_test_index,
+ .broadcast_from_main = broadcast_from_main,
+ .indirect = indirect,
+ };
+ support_isolate_in_subprocess (subprocess, &arg);
+ }
+ }
+
+ xpthread_attr_destroy (&attr_perthreadids);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
index f291421dc2..a7e6285b46 100644
--- a/sysdeps/nptl/internaltypes.h
+++ b/sysdeps/nptl/internaltypes.h
@@ -52,6 +52,7 @@ struct pthread_attr
#define ATTR_FLAG_POLICY_SET 0x0040
#define ATTR_FLAG_DO_RSEQ 0x0080
#define ATTR_FLAG_PERTHREADFS 0x0100
+#define ATTR_FLAG_PERTHREADIDS 0x0200
/* These flags are not copied from the thread attribute at
pthread_create time. */
@@ -62,7 +63,7 @@ struct pthread_attr
pthread_create even if they are not specified in the thread
attribute. */
#define ATTR_FLAGS_INHERITED \
- ATTR_FLAG_PERTHREADFS
+ (ATTR_FLAG_PERTHREADFS | ATTR_FLAG_PERTHREADIDS)
/* Used to allocate a pthread_attr_t object which is also accessed
internally. */
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index d2280ddc73..f249444acb 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -427,6 +427,24 @@ int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
int *__restrict __scope)
__THROW __nonnull ((1, 2));
+/* Change the property in *ATTR which indicates whether the thread has
+ its own user and group IDs. By default, when the real, effective,
+ or saved user or group ID is changed by a thread, this affects the
+ entire process. If a thread is created with this flag set to true,
+ then changing the IDs within that thread will only affect that
+ thread, and user and group ID changes in other threads (whether
+ they have enabled this flag or not) do not affect it. If a thread
+ has been created with this flag, threads created by it will also
+ have their own, private user and group IDs. */
+int pthread_attr_setperthreadids_np (pthread_attr_t *__attr, int __scope)
+ __THROW __nonnull ((1));
+
+/* Get the per-thread/per-process scope of user and group IDs from
+ *ATTR and store it in *SCOPE. */
+int pthread_attr_getperthreadids_np (const pthread_attr_t *__restrict __attr,
+ int *__restrict __scope)
+ __THROW __nonnull ((1, 2));
+
/* Get the default attributes used by pthread_create in this process. */
extern int pthread_getattr_default_np (pthread_attr_t *__attr)
__THROW __nonnull ((1));
diff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h
index 4f649267b3..899aabe10b 100644
--- a/sysdeps/nptl/pthreadP.h
+++ b/sysdeps/nptl/pthreadP.h
@@ -694,6 +694,14 @@ check_stacksize_attr (size_t st)
return EINVAL;
}
+/* Return true if the current thread has per-thread user and group
+ IDS. */
+static inline bool
+nptl_current_thread_has_separate_ids (void)
+{
+ return THREAD_SELF->flags & ATTR_FLAG_PERTHREADIDS;
+}
+
#define ASSERT_TYPE_SIZE(type, size) \
_Static_assert (sizeof (type) == size, \
"sizeof (" #type ") != " #size)
diff --git a/sysdeps/nptl/setxid.h b/sysdeps/nptl/setxid.h
index b1ef6ba0a1..113f3965bf 100644
--- a/sysdeps/nptl/setxid.h
+++ b/sysdeps/nptl/setxid.h
@@ -29,7 +29,7 @@
#define INLINE_SETXID_SYSCALL(name, nr, args...) \
({ \
int __result; \
- if (!SINGLE_THREAD_P) \
+ if (!SINGLE_THREAD_P && !nptl_current_thread_has_separate_ids ()) \
{ \
struct xid_command __cmd; \
__cmd.syscall_no = __NR_##name; \
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index abc893d3c2..3765780293 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2775,5 +2775,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 08ac8d8e1b..c4a09e889a 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3122,7 +3122,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 69f616cead..f1a6f708b9 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2536,5 +2536,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 9d1678320e..df7b436bdb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2828,7 +2828,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 4f3b5affe9..86504cf679 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2825,7 +2825,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 4775926d0d..614fcb6d22 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2812,5 +2812,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index d3b8ac7de6..06cfb5abc1 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2849,7 +2849,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 7bf6d848df..f671d3861d 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3032,7 +3032,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index 4438857731..d59b092fda 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2296,5 +2296,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 1ec5185e2a..fe9e65fefa 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2808,7 +2808,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index d091f52f10..8baa152f32 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2975,7 +2975,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index eda99f79cc..450519cdb6 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2861,5 +2861,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 28d85c9a69..1c31ad4aef 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2858,5 +2858,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 52c206e514..928cb8eb72 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2938,7 +2938,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index fa6b7532bd..461ccf23d5 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2936,7 +2936,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index c2a0b18359..9817b9074d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2944,7 +2944,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 8c0e99fb18..331915f9d7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2846,7 +2846,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index 1158bb10d6..7cd7e25f7d 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2286,5 +2286,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index bf9faed11f..58f5df6288 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3165,7 +3165,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7dbe21ba65..535afe8021 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3210,7 +3210,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 8e8a179363..2446a762af 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2919,7 +2919,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 04fa4568bb..dee01554a9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2995,5 +2995,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 78d4f1f22f..7b2b47e530 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2539,5 +2539,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index ae0f2ccac9..92191a7c77 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2739,5 +2739,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 7b7c81a68b..3c19286585 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -3163,7 +3163,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 7c81be27f4..3b351b93a1 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2956,7 +2956,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index f04f22b538..a460714b52 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2855,7 +2855,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index ec831f0ad5..333179ee41 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2852,7 +2852,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 4f40e294fe..b7a38f1682 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3186,7 +3186,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index da128a940a..35ee2aed47 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2822,7 +2822,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 3f32a83378..443fbd58ee 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2771,7 +2771,9 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8105eaadba..34267354b7 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2790,5 +2790,7 @@ GLIBC_2.43 memset_explicit F
GLIBC_2.43 mseal F
GLIBC_2.43 openat2 F
GLIBC_2.43 pthread_attr_getperthreadfs_np F
+GLIBC_2.43 pthread_attr_getperthreadids_np F
GLIBC_2.43 pthread_attr_setperthreadfs_np F
+GLIBC_2.43 pthread_attr_setperthreadids_np F
GLIBC_2.43 umaxabs F
--
2.52.0
More information about the Libc-alpha
mailing list