This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Linux: Implement per-thread user and group IDs


On 6/28/19 2:54 PM, Florian Weimer wrote:
> 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.

OK.

> Multi-threaded file servers typically need this functionality and
> call the system calls directly to implement this.

OK.

> (Build-tested on all architectures with build-many-glibcs.py.
> Run-time-tested on x86-64, by running the new xtest as root.  I still
> need to implement the inheritance test Carlos requested.  Due to the
> similarities, I plan to write one separate test for both kinds of
> properties.)

Right, the test for per-process is missing, we have only test for
per-thread inheritance, and null attr default, but not per-process
inheritance. I assume you'll fix it like you are going to fix the
other-thread fs test case?

The other thing I was thinking about is: Should a thread created
with per-thread uid/gid block SIGSETXID permanently from startup?
This way there can be no accident that the function sighandler_setxid
is called? If you don't like that then at least some belt-and-suspenders
code in sighandler_setxid to assert that a thread per-thread uid/gid
will not have this handler ever called? Even better... do both! :-)

> 2019-06-28  Florian Weimer  <fweimer@redhat.com>
> 
> 	Linux: Implement per-thread user and group IDs.
> 	* manual/threads.texi (Enabling Per-Thread Properties): Document
> 	pthread_attr_setperthreadids_np, pthread_attr_getperthreadids_np.
> 	* sysdeps/nptl/pthread.h (pthread_attr_setperthreadids_np)
> 	(pthread_attr_getperthreadids_np): Declare.
> 	* nptl/Makefile (routines): Add pthread_attr_setperthreadids_np,
> 	pthread_attr_getperthreadids_np.
> 	* nptl/Versions (GLIBC_2.29): Export
> 	pthread_attr_setperthreadids_np, pthread_attr_getperthreadids_np.
> 	* nptl/allocatestack.c (thread_excluded_from_setxid_broadcast):
> 	New function.
> 	(__nptl_setxid): Use it.
> 	* nptl/pthreadP.h (nptl_current_thread_has_separate_ids): New
> 	function.
> 	* susdeps/nptl/setxid.h (INLINE_SETXID_SYSCALL): Check
> 	nptl_current_thread_has_separate_ids before setxid broadcast.
> 	* nptl/pthread_attr_setperthreadids_np.c: New file
> 	* nptl/pthread_attr_getperthreadids_np.c: Likewise.
> 	* sysdeps/nptl/internaltypes.h (ATTR_FLAG_PERTHREADIDS)
> 	(ATTR_FLAGS_IGNORED_ATTR, ATTR_FLAGS_INHERITED): New macros.
> 	* nptl/pthread_create.c (__pthread_create_2_1): Use
> 	ATTR_FLAGS_IGNORED_ATTR and ATTR_FLAGS_INHERITED to compute the
> 	flags for the new thread.
> 	* nptl/tst-pthread-perthreadids.c: New file.
> 	* support/Makefile (libsupport-routines): Add xgetresgid,
> 	xgetresuid.
> 	* support/xgetresgid.c: New file.
> 	* support/xsetresgid.c: Likewise.
> 	* support/xunistd.h (xgetresuid, xgetresgid): Declare.
> 	* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add
> 	pthread_attr_getperthreadids_np, pthread_attr_setperthreadids_np.
> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> 	(GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
> 	Likewise.
> 
> diff --git a/NEWS b/NEWS
> index e63b69b930..83bd54b5e8 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -45,6 +45,12 @@ Major new features:
>    pthread_attr_setperthreadfs_np and pthread_attr_getperthreadfs_np have
>    been added in support of that.
>  
> +* Likewise, on Linux, threads can now be created in such a way that they

s/Likewise, on/On/g

> +  retain per-thread user and group IDs.  (This has always been the way how
> +  the Linux kernel implements threads.)  The functions

Drop the parenthetical.

> +  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:
>  
>  * The copy_file_range function fails with ENOSYS if the kernel does not
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 60c15a8d15..c3003c1f94 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -698,11 +698,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.
>  

OK.

>  Per-thread properties can be set and examined for an attribute using
>  the functions below.
> @@ -764,6 +765,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_setperthreadid_np (pthread_attr_t *@var{attr}, int @var{scope})

Typo. s/pthread_attr_setperthreadid_np/pthread_attr_setperthreadids_np/g

> +@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)

OK.

> +
> +@item
> +@cindex per-thread group ID
> +@cindex thread-specific group ID
> +real, effective and saved group ID (as returned by the
> +@code{getresgid} function)

OK.

> +
> +@item
> +supplementary group list (as returned by the @code{getgroups}
> +function)

OK.

> +@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}.

OK.

> +
> +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.
> +

OK.

> +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.

OK.

> +
> +This function is a GNU extension and specific to Linux.
> +@end deftypefun

OK.

> +
> +@deftypefun int pthread_attr_getperthreadid_np (pthread_attr_t *restrict @var{attr}, int *restrict @var{scope})

Typo. s/pthread_attr_getperthreadid_np/pthread_attr_getperthreadids_np/g

> +@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

OK.

> +
>  @c FIXME these are undocumented:
>  @c pthread_atfork
>  @c pthread_attr_destroy
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 1374838339..52913cc2f0 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -31,7 +31,8 @@ routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
>  	   libc-cleanup libc_pthread_init libc_multiple_threads \
>  	   register-atfork pthread_atfork pthread_self thrd_current \
>  	   thrd_equal thrd_sleep thrd_yield \
> -	   pthread_attr_setperthreadfs_np pthread_attr_getperthreadfs_np
> +	   pthread_attr_setperthreadfs_np pthread_attr_getperthreadfs_np \
> +	   pthread_attr_setperthreadids_np pthread_attr_getperthreadids_np

OK.

>  shared-only-routines = forward
>  static-only-routines = pthread_atfork
>  
> @@ -337,6 +338,9 @@ xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \
>  # 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

OK.

> +
>  test-srcs = tst-oddstacklimit
>  
>  # Test expected to fail on most targets (except x86_64) due to bug
> diff --git a/nptl/Versions b/nptl/Versions
> index 817fec04f3..bedc73878e 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -35,6 +35,8 @@ libc {
>    GLIBC_2.30 {
>      pthread_attr_setperthreadfs_np;
>      pthread_attr_getperthreadfs_np;
> +    pthread_attr_setperthreadids_np;
> +    pthread_attr_getperthreadids_np;

OK.

>    }
>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
> diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
> index fcbc46f0d7..9d238a001b 100644
> --- a/nptl/allocatestack.c
> +++ b/nptl/allocatestack.c
> @@ -1067,6 +1067,14 @@ __nptl_setxid_error (struct xid_command *cmdp, int error)
>    while (atomic_compare_and_exchange_bool_acq (&cmdp->error, error, -1));
>  }
>  
> +/* 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);
> +}

OK. Nice refactor.

> +
>  int
>  attribute_hidden
>  __nptl_setxid (struct xid_command *cmdp)
> @@ -1080,13 +1088,14 @@ __nptl_setxid (struct xid_command *cmdp)
>    cmdp->error = -1;
>  
>    struct pthread *self = THREAD_SELF;
> +  assert (!nptl_current_thread_has_separate_ids ());

OK.

>  
>    /* Iterate over the list with system-allocated threads first.  */
>    list_t *runp;
>    list_for_each (runp, &stack_used)
>      {
>        struct pthread *t = list_entry (runp, struct pthread, list);
> -      if (t == self)
> +      if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	continue;
>  
>        setxid_mark_thread (cmdp, t);
> @@ -1096,7 +1105,7 @@ __nptl_setxid (struct xid_command *cmdp)
>    list_for_each (runp, &__stack_user)
>      {
>        struct pthread *t = list_entry (runp, struct pthread, list);
> -      if (t == self)
> +      if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	continue;
>  
>        setxid_mark_thread (cmdp, t);
> @@ -1112,7 +1121,7 @@ __nptl_setxid (struct xid_command *cmdp)
>        list_for_each (runp, &stack_used)
>  	{
>  	  struct pthread *t = list_entry (runp, struct pthread, list);
> -	  if (t == self)
> +	  if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	    continue;
>  
>  	  signalled += setxid_signal_thread (cmdp, t);
> @@ -1121,7 +1130,7 @@ __nptl_setxid (struct xid_command *cmdp)
>        list_for_each (runp, &__stack_user)
>  	{
>  	  struct pthread *t = list_entry (runp, struct pthread, list);
> -	  if (t == self)
> +	  if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	    continue;
>  
>  	  signalled += setxid_signal_thread (cmdp, t);
> @@ -1142,7 +1151,7 @@ __nptl_setxid (struct xid_command *cmdp)
>    list_for_each (runp, &stack_used)
>      {
>        struct pthread *t = list_entry (runp, struct pthread, list);
> -      if (t == self)
> +      if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	continue;
>  
>        setxid_unmark_thread (cmdp, t);
> @@ -1151,7 +1160,7 @@ __nptl_setxid (struct xid_command *cmdp)
>    list_for_each (runp, &__stack_user)
>      {
>        struct pthread *t = list_entry (runp, struct pthread, list);
> -      if (t == self)
> +      if (thread_excluded_from_setxid_broadcast (self, t))

OK.

>  	continue;
>  
>        setxid_unmark_thread (cmdp, t);
> diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h
> index 66527d8f2d..719bae5173 100644
> --- a/nptl/pthreadP.h
> +++ b/nptl/pthreadP.h
> @@ -598,6 +598,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;
> +}

OK.

> +
>  #define ASSERT_TYPE_SIZE(type, size) 					\
>    _Static_assert (sizeof (type) == size,				\
>  		  "sizeof (" #type ") != " #size)
> 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) 2019 Free Software Foundation, Inc.

OK.

> +   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;

OK. Thanks for fixing this up to match the per-thread-fs changes!

> +  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) 2019 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;
> +    }
> +}

OK.

> diff --git a/nptl/tst-pthread-perthreadids.c b/nptl/tst-pthread-perthreadids.c
> new file mode 100644
> index 0000000000..c3d04f5156
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadids.c
> @@ -0,0 +1,510 @@
> +/* Test per-thread user and group IDs.
> +   Copyright (C) 2019 Free Software Foundation, Inc.

OK.

> +   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 IDs.  */
> +static bool
> +perthread_flag (pthread_t thr)
> +{
> +  pthread_attr_t attr;
> +  int ret = pthread_getattr_np (thr, &attr);

OK.

> +  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;

OK.

> +}
> +
> +/* Which set*id function to call.  */
> +enum operation
> +{
> + OP_NONE,
> + OP_SETUID,
> + OP_SETEUID,
> + OP_SETREUID,
> + OP_SETRESUID,
> + OP_SETGID,
> + OP_SETEGID,
> + OP_SETREGID,
> + OP_SETRESGID,
> + OP_SETGROUPS,
> +};

OK.

> +
> +/* Convert the operation to a descriptive string.  */
> +static const char *
> +operation_string (enum operation op)
> +{
> +  switch (op)

OK, implementation of *_SETXID_SYSCALL is:

sysdeps/unix/sysv/linux/setresgid.c
sysdeps/unix/sysv/linux/setgroups.c
sysdeps/unix/sysv/linux/setuid.c
sysdeps/unix/sysv/linux/setresuid.c
sysdeps/unix/sysv/linux/setreuid.c
sysdeps/unix/sysv/linux/setegid.c
sysdeps/unix/sysv/linux/setgid.c
sysdeps/unix/sysv/linux/setregid.c
sysdeps/unix/sysv/linux/seteuid.c

Confirmed all covered.

> +    {
> +    case OP_NONE:
> +      return "<none>";

OK.

> +    case OP_SETUID:
> +      return "OP_SETUID";

OK.

> +    case OP_SETEUID:
> +      return "OP_SETEUID";

OK.

> +    case OP_SETREUID:
> +      return "OP_SETREUID";

OK.

> +    case OP_SETRESUID:
> +      return "OP_SETRESUID";

OK.

> +    case OP_SETGID:
> +      return "OP_SETGID";

OK.

> +    case OP_SETEGID:
> +      return "OP_SETEGID";

OK.

> +    case OP_SETREGID:
> +      return "OP_SETREGID";

OK.

> +    case OP_SETRESGID:
> +      return "OP_SETRESGID";

OK.

> +    case OP_SETGROUPS:
> +      return "OP_SETGROUPS";

OK.

> +    }
> +
> +  FAIL_EXIT1 ("invalid operation: %d", (int) op);
> +}

OK.

> +
> +/* 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];
> +};

OK.

> +
> +static const struct test_case test_cases[] =
> +  {
> +   { OP_NONE, { 0, }, { 0, 0, 0}, {0, 0, 0} },
> +
> +   { OP_SETUID, { 1, }, { 1, 1, 1 }, { 0, } },
> +   { OP_SETEUID, { 2, }, { 0, 2, }, { 0, } },
> +   { OP_SETREUID, { 3, 4, }, { 3, 4, 4 }, { 0, } },
> +   { OP_SETRESUID, { 3, 4, 5 }, { 3, 4, 5 }, { 0, } },
> +
> +   { OP_SETGID, { 6, }, { 0, }, { 6, 6, 6 } },
> +   { OP_SETEGID, { 7, }, { 0, }, { 0, 7, } },
> +   { OP_SETREGID, { 8, 9, }, { 0, }, { 8, 9, 9 } },
> +   { OP_SETRESGID, { 10, 11, 12 }, { 0, }, { 10, 11, 12 } },
> +
> +   { OP_SETGROUPS, { -1, }, { 0, }, { 0, } },
> +   { OP_SETGROUPS, { 13, -1 }, { 0, }, { 0, } },
> +   { OP_SETGROUPS, { 13, 14, -1 }, { 0, }, { 0, } },
> +   { OP_SETGROUPS, { 13, 14, 15 }, { 0, }, { 0, } },
> +
> +   /* Final round of checks.  */
> +   { OP_NONE, { 0, }, { 0, }, {0, } },

I find it more difficult to read and edit when elements of the
struct are elided. Could you please fill them all in?

> +  };
> +
> +/* 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;
> +}

OK.

> +
> +/* 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;

OK.

> +
> +    case OP_SETGROUPS:
> +      {
> +        gid_t groups[] = { test->args[0], test->args[1], test->args[2] };
> +        ret = setgroups (supplemetary_count (test), groups);

OK.

> +      }
> +    }
> +
> +  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;

OK.

> +
> +/* 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;
> +};

OK.

> +
> +/* 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;
> +}

OK.

> +
> +/* 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.  */
> +      pthread_t thr = xpthread_create (NULL, threadfunc, arg);
> +      TEST_COMPARE (perthread_flag (thr), arg->perthread);
> +      return xpthread_join (thr);
> +    }
> +
> +  const struct test_case *expected = &test_cases[0];
> +  gid_t expected_supplementary[3] = { -1, -1, -1 };
> +  int expected_supplementary_count = 0;
> +
> +  xpthread_barrier_wait (&barrier);

All of these barrier waits should have notes about what they are
synchronizing with, and which point if possible, thta way a future
editor can know what they are wiating for. Perhaps numbering them
with comments might help here.

I realized late that I had the same problem while reviewing the
other test case and it only occurred to me that we should just
comment the phases.

> +
> +  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];
> +            }
> +        }
> +
> +      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);
> +
> +      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 ()));
> +
> +  /* Main thread and another shared thread are extras.  */
> +  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_thread
> +    = xpthread_create (NULL, threadfunc,
> +                       create_thread_argument ((struct thread_argument) { }));
> +  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);
> +      TEST_VERIFY (perthread_flag (perthread_threads[i]));
> +    }
> +  /* Use thread index zero for no-op checking.  */
> +  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.  */

^^^ This comment needs clarification. Is it trying to rationalize why it's
array_length (test_cases) + 2?

> +  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.  */

What is 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.  */
> +    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));
> +      }
> +
> +  /* Use thread index zero for no-op 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);
> +  }
> +

This needs a block comment explaining what it is doing and why.

> +  for (int indirect = 0; indirect < 2; ++indirect)
> +    {
> +      check_perthread (indirect);
> +
> +      for (int broadcast_from_main = 0; broadcast_from_main < 2;
> +           ++broadcast_from_main)
> +        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/support/Makefile b/support/Makefile
> index 774b0a692a..1ded323015 100644
> --- a/support/Makefile
> +++ b/support/Makefile
> @@ -94,6 +94,8 @@ libsupport-routines = \
>    xfopen \
>    xfork \
>    xftruncate \
> +  xgetresgid \
> +  xgetresuid \

OK.

>    xgetsockname \
>    xlisten \
>    xlseek \
> diff --git a/support/xgetresgid.c b/support/xgetresgid.c
> new file mode 100644
> index 0000000000..22990fa633
> --- /dev/null
> +++ b/support/xgetresgid.c
> @@ -0,0 +1,27 @@
> +/* getresgid with error checking.

OK.

> +   Copyright (C) 2019 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 <support/check.h>
> +#include <support/xunistd.h>
> +
> +void
> +xgetresgid (gid_t *real, gid_t *effective, gid_t *saved)
> +{
> +  if (getresgid (real, effective, saved) != 0)
> +    FAIL_EXIT1 ("getresgid: %m");
> +}

OK.

> diff --git a/support/xgetresuid.c b/support/xgetresuid.c
> new file mode 100644
> index 0000000000..b0cd4e938f
> --- /dev/null
> +++ b/support/xgetresuid.c
> @@ -0,0 +1,27 @@
> +/* getresuid with error checking.
> +   Copyright (C) 2019 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 <support/check.h>
> +#include <support/xunistd.h>
> +
> +void
> +xgetresuid (uid_t *real, uid_t *effective, uid_t *saved)
> +{
> +  if (getresuid (real, effective, saved) != 0)
> +    FAIL_EXIT1 ("getresuid: %m");
> +}

OK.

> diff --git a/support/xunistd.h b/support/xunistd.h
> index b470d99be1..2ad2e9a55c 100644
> --- a/support/xunistd.h
> +++ b/support/xunistd.h
> @@ -46,6 +46,8 @@ long xsysconf (int name);
>  long long xlseek (int fd, long long offset, int whence);
>  void xftruncate (int fd, long long length);
>  void xsymlink (const char *target, const char *linkpath);
> +void xgetresuid (uid_t *, uid_t *, uid_t *);
> +void xgetresgid (gid_t *, gid_t *, gid_t *);

OK.

>  
>  /* Equivalent of "mkdir -p".  */
>  void xmkdirp (const char *, mode_t);
> diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
> index 5ad56908b5..0e8b2b3f65 100644
> --- a/sysdeps/nptl/internaltypes.h
> +++ b/sysdeps/nptl/internaltypes.h
> @@ -49,6 +49,7 @@ struct pthread_attr
>  #define ATTR_FLAG_SCHED_SET		0x0020
>  #define ATTR_FLAG_POLICY_SET		0x0040
>  #define ATTR_FLAG_PERTHREADFS		0x0080
> +#define ATTR_FLAG_PERTHREADIDS		0x0100

OK.

>  
>  /* These flags are not copied from the thread attribute at
>     pthread_create time.  */
> @@ -59,7 +60,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)

OK.

>  
>  
>  /* Mutex attribute data structure.  */
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 37073e3ce7..9ea312cf41 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -430,6 +430,24 @@ int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
>  				    int *__restrict __scope)
>    __THROW __nonnull ((1, 2));
>  
> +/* Control the flag in ATTR 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));

OK.

> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */
> +int pthread_attr_getperthreadids_np (const pthread_attr_t *__restrict __attr,
> +				     int *__restrict __scope)

OK.

> +  __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/setxid.h b/sysdeps/nptl/setxid.h
> index 20bf66a5df..bc955e73bb 100644
> --- a/sysdeps/nptl/setxid.h
> +++ b/sysdeps/nptl/setxid.h
> @@ -32,7 +32,8 @@
>  # define INLINE_SETXID_SYSCALL(name, nr, args...) \
>    ({									\
>      int __result;							\
> -    if (__builtin_expect (__libc_pthread_functions_init, 0))		\
> +    if (__libc_pthread_functions_init					\
> +	&& !nptl_current_thread_has_separate_ids ())			\

OK.

>        {									\
>  	struct xid_command __cmd;					\
>  	__cmd.syscall_no = __NR_##name;					\
> @@ -48,7 +49,8 @@
>    ({									\
>      extern __typeof (__nptl_setxid) __nptl_setxid __attribute__((weak));\
>      int __result;							\
> -    if (__glibc_unlikely (__nptl_setxid	!= NULL))			      \
> +    if (__nptl_setxid != NULL						\
> +	&& !nptl_current_thread_has_separate_ids ())			\

OK.

>        {									\
>  	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 2635e16f5e..03507783d3 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2144,6 +2144,8 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 12227b9800..0e24e9a39d 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2219,7 +2219,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index 6d09148e1d..d69e1acdfa 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -129,7 +129,9 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 5ee091972b..cf2fe8fb5e 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2088,6 +2088,8 @@ GLIBC_2.29 xprt_unregister F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 844eaf539b..2ebaff4e7b 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2040,7 +2040,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
> index b80c84c0b7..d8ff0c58f3 100644
> --- a/sysdeps/unix/sysv/linux/hppa/pthread.h
> +++ b/sysdeps/unix/sysv/linux/hppa/pthread.h
> @@ -407,6 +407,24 @@ int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
>  				    int *__restrict __scope)
>    __THROW __nonnull ((1, 2));
>  
> +/* Control the flag in ATTR 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.  */
> +void pthread_attr_setperthreadids_np (pthread_attr_t *__attr, int __scope)
> +  __THROW __nonnull ((1));

OK.

> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */

Wrong comment.

> +int pthread_attr_getperthreadids_np (const pthread_attr_t *__restrict __attr,
> +				     int *__restrict __scope)
> +  __THROW __nonnull ((1, 2));
> +

OK.

>  /* 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/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index efd8cb1685..6a84bb91af 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2206,7 +2206,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 7f34f4d1e6..3e5144c493 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2072,7 +2072,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index 34d5f6c91a..63f830cee8 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -130,7 +130,9 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _Exit F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 71882c6e23..b90e15cf69 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2149,7 +2149,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index 4f605fa67a..99516e20f7 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2136,6 +2136,8 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 62790b0a64..207448d9fc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2123,7 +2123,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index eb2ae61601..e87edbde57 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2121,7 +2121,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 9cf1462270..6f68c19ffc 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2129,7 +2129,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index d116e7180e..35376c4083 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2123,7 +2123,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index 0e8d5bfcc7..957efe283c 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2177,6 +2177,8 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 16e66c2fa4..594f3c7888 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2179,7 +2179,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index fff0295a63..1db7320d13 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2212,7 +2212,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 808f021335..85965392d2 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2042,7 +2042,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index a894bc49be..25872a4d1b 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2246,6 +2246,8 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index e220b0fd0c..36a6548695 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2106,6 +2106,8 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 1567d2ff1d..1ab615c10d 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2174,7 +2174,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index f9d88d588e..8a0c4ad926 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2078,7 +2078,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index affd74df4c..80df6c75ac 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -2044,7 +2044,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index c12cc83bb2..6308f6055c 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2168,7 +2168,9 @@ GLIBC_2.30 __nldbl_warnx F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 _IO_fprintf F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 37c9dff44c..6b73de3257 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2095,7 +2095,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 71b7cc4ff9..6f24765088 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2053,7 +2053,9 @@ GLIBC_2.3.4 xdr_u_quad_t F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
>  GLIBC_2.4 __confstr_chk F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 573fc2e01c..bc2ad25346 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2152,6 +2152,8 @@ GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
>  GLIBC_2.30 getdents64 F
>  GLIBC_2.30 gettid F
>  GLIBC_2.30 pthread_attr_getperthreadfs_np F
> +GLIBC_2.30 pthread_attr_getperthreadids_np F
>  GLIBC_2.30 pthread_attr_setperthreadfs_np F
> +GLIBC_2.30 pthread_attr_setperthreadids_np F
>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> 

OK. Just version updates.

-- 
Cheers,
Carlos.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]