Backport GLIBC_2.35 libc symbols incl. _dl_find_object (RHEL-93320)

Resolves: RHEL-93320
This commit is contained in:
Benjamin Herrenschmidt 2025-07-14 13:03:09 +10:00
parent 60b7e5744e
commit bec6dd40c6
21 changed files with 8544 additions and 1 deletions

781
glibc-RHEL-93320-1.patch Normal file
View File

@ -0,0 +1,781 @@
commit 44829b3ddb64e99e37343a0f25b2c082387d31a5
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date: Thu Oct 21 15:54:57 2021 -0500
String: Add support for __memcmpeq() ABI on all targets
No bug.
This commit adds support for __memcmpeq() as a new ABI for all
targets. In this commit __memcmpeq() is implemented only as an alias
to the corresponding targets memcmp() implementation. __memcmpeq() is
added as a new symbol starting with GLIBC_2.35 and defined in string.h
with comments explaining its behavior. Basic tests that it is callable
and works where added in string/tester.c
As discussed in the proposal "Add new ABI '__memcmpeq()' to libc"
__memcmpeq() is essentially a reserved namespace for bcmp(). The means
is shares the same specifications as memcmp() except the return value
for non-equal byte sequences is any non-zero value. This is less
strict than memcmp()'s return value specification and can be better
optimized when a boolean return is all that is needed.
__memcmpeq() is meant to only be called by compilers if they can prove
that the return value of a memcmp() call is only used for its boolean
value.
All tests in string/tester.c passed. As well build succeeds on
x86_64-linux-gnu target.
diff --git a/string/Versions b/string/Versions
index 298ecd401aa49fd5..864c4cf7a4bda473 100644
--- a/string/Versions
+++ b/string/Versions
@@ -89,4 +89,7 @@ libc {
sigdescr_np; sigabbrev_np;
strerrordesc_np; strerrorname_np;
}
+ GLIBC_2.35 {
+ __memcmpeq;
+ }
}
diff --git a/string/memcmp.c b/string/memcmp.c
index 9b46d7a905c8b788..eac411253050c0e7 100644
--- a/string/memcmp.c
+++ b/string/memcmp.c
@@ -359,3 +359,6 @@ libc_hidden_builtin_def(memcmp)
# undef bcmp
weak_alias (memcmp, bcmp)
#endif
+
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
diff --git a/string/string.h b/string/string.h
index 8dcafb4ac4952853..639e2f56818f16b6 100644
--- a/string/string.h
+++ b/string/string.h
@@ -64,6 +64,22 @@ extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
extern int memcmp (const void *__s1, const void *__s2, size_t __n)
__THROW __attribute_pure__ __nonnull ((1, 2));
+/* Compare N bytes of S1 and S2. Return zero if S1 and S2 are equal.
+ Return some non-zero value otherwise.
+
+ Essentially __memcmpeq has the exact same semantics as memcmp
+ except the return value is less constrained. memcmp is always a
+ correct implementation of __memcmpeq. As well !!memcmp, -memcmp,
+ or bcmp are correct implementations.
+
+ __memcmpeq is meant to be used by compilers when memcmp return is
+ only used for its bolean value.
+
+ __memcmpeq is declared only for use by compilers. Programs should
+ continue to use memcmp. */
+extern int __memcmpeq (const void *__s1, const void *__s2, size_t __n)
+ __THROW __attribute_pure__ __nonnull ((1, 2));
+
/* Search N bytes of S for C. */
#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
extern "C++"
diff --git a/string/tester.c b/string/tester.c
index 778160ae6ecd648e..605b3f00f97ae854 100644
--- a/string/tester.c
+++ b/string/tester.c
@@ -1449,6 +1449,19 @@ test_bcmp (void)
check(bcmp("abc", "def", 0) == 0, 8); /* Zero count. */
}
+static void
+test_memcmpeq (void)
+{
+ it = "__memcmpeq";
+ check (__memcmpeq ("a", "a", 1) == 0, 1); /* Identity. */
+ check (__memcmpeq ("abc", "abc", 3) == 0, 2); /* Multicharacter. */
+ check (__memcmpeq ("abcd", "abce", 4) != 0, 3); /* Honestly unequal. */
+ check (__memcmpeq ("abce", "abcd", 4) != 0, 4);
+ check (__memcmpeq ("alph", "beta", 4) != 0, 5);
+ check (__memcmpeq ("abce", "abcd", 3) == 0, 6); /* Count limited. */
+ check (__memcmpeq ("abc", "def", 0) == 0, 8); /* Zero count. */
+}
+
static void
test_strerror (void)
{
@@ -1611,6 +1624,9 @@ main (void)
/* bcmp - somewhat like memcmp. */
test_bcmp ();
+ /* __memcmpeq - somewhat like memcmp. */
+ test_memcmpeq ();
+
/* strndup. */
test_strndup ();
diff --git a/sysdeps/aarch64/memcmp.S b/sysdeps/aarch64/memcmp.S
index c1937f6f5c103a6f..37f37b91914c518b 100644
--- a/sysdeps/aarch64/memcmp.S
+++ b/sysdeps/aarch64/memcmp.S
@@ -177,4 +177,6 @@ L(ret_0):
END (memcmp)
#undef bcmp
weak_alias (memcmp, bcmp)
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/csky/abiv2/memcmp.S b/sysdeps/csky/abiv2/memcmp.S
index 1560387618799d0e..2a4ae577b024277d 100644
--- a/sysdeps/csky/abiv2/memcmp.S
+++ b/sysdeps/csky/abiv2/memcmp.S
@@ -138,5 +138,6 @@ ENTRY (memcmp)
br .L_s1_aligned
END (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
libc_hidden_def (memcmp)
.weak memcmp
diff --git a/sysdeps/i386/i686/memcmp.S b/sysdeps/i386/i686/memcmp.S
index b26b124fada2048f..90266d904b52368a 100644
--- a/sysdeps/i386/i686/memcmp.S
+++ b/sysdeps/i386/i686/memcmp.S
@@ -405,4 +405,6 @@ L(table_32bytes) :
#undef bcmp
weak_alias (memcmp, bcmp)
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/i386/i686/multiarch/memcmp-ia32.S b/sysdeps/i386/i686/multiarch/memcmp-ia32.S
index 5f6658b89a0d1d77..a5b5c3d3491f2e5a 100644
--- a/sysdeps/i386/i686/multiarch/memcmp-ia32.S
+++ b/sysdeps/i386/i686/multiarch/memcmp-ia32.S
@@ -30,6 +30,9 @@
# undef weak_alias
# define weak_alias(original, alias)
+
+# undef strong_alias
+# define strong_alias(original, alias)
#endif
#include <sysdeps/i386/i686/memcmp.S>
diff --git a/sysdeps/i386/i686/multiarch/memcmp.c b/sysdeps/i386/i686/multiarch/memcmp.c
index 6e058a885775135c..3b2815edbc4d9d54 100644
--- a/sysdeps/i386/i686/multiarch/memcmp.c
+++ b/sysdeps/i386/i686/multiarch/memcmp.c
@@ -29,4 +29,5 @@
libc_ifunc_redirected (__redirect_memcmp, memcmp, IFUNC_SELECTOR ());
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
#endif
diff --git a/sysdeps/i386/memcmp.S b/sysdeps/i386/memcmp.S
index 1f212b0f6de8cde9..02473c2c0c827ba2 100644
--- a/sysdeps/i386/memcmp.S
+++ b/sysdeps/i386/memcmp.S
@@ -70,4 +70,6 @@ END (memcmp)
#undef bcmp
weak_alias (memcmp, bcmp)
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/ia64/memcmp.S b/sysdeps/ia64/memcmp.S
index 98570f4e364464ec..e9c3b645c742d34b 100644
--- a/sysdeps/ia64/memcmp.S
+++ b/sysdeps/ia64/memcmp.S
@@ -161,4 +161,5 @@ ENTRY(memcmp)
END(memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index c5da10a0cd0140e4..e849d6fa35456b4b 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2285,6 +2285,7 @@ GLIBC_2.34 res_send F
GLIBC_2.34 shm_open F
GLIBC_2.34 shm_unlink F
GLIBC_2.34 timespec_getres F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/powerpc/powerpc32/405/memcmp.S b/sysdeps/powerpc/powerpc32/405/memcmp.S
index 6a6a54d90f93e751..c2836040a7783fb2 100644
--- a/sysdeps/powerpc/powerpc32/405/memcmp.S
+++ b/sysdeps/powerpc/powerpc32/405/memcmp.S
@@ -126,3 +126,4 @@ L(st2):
END (memcmp)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp,bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc32/power4/memcmp.S b/sysdeps/powerpc/powerpc32/power4/memcmp.S
index 814d2f211d95992e..f58e34aba5c2d3dc 100644
--- a/sysdeps/powerpc/powerpc32/power4/memcmp.S
+++ b/sysdeps/powerpc/powerpc32/power4/memcmp.S
@@ -1373,3 +1373,4 @@ END (memcmp)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-power7.S b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-power7.S
index 8a929b2b443a8aff..b17d0e43b77e532d 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-power7.S
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-power7.S
@@ -38,4 +38,7 @@
#undef weak_alias
#define weak_alias(a, b)
+#undef strong_alias
+#define strong_alias(a, b)
+
#include <sysdeps/powerpc/powerpc32/power7/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-ppc32.S b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-ppc32.S
index 317523b7435b8553..893b6cac9cd7e0cc 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-ppc32.S
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/memcmp-ppc32.S
@@ -40,6 +40,10 @@
# undef weak_alias
# define weak_alias(a, b) \
.weak b ; b = __memcmp_ppc
+
+# undef strong_alias
+# define strong_alias(a, b) \
+ .globl b ; b = __memcmp_ppc
#endif
#include <sysdeps/powerpc/powerpc32/power4/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc32/power7/memcmp.S b/sysdeps/powerpc/powerpc32/power7/memcmp.S
index 8a19953e2d0e8dbc..f8deb4e32cfcce9f 100644
--- a/sysdeps/powerpc/powerpc32/power7/memcmp.S
+++ b/sysdeps/powerpc/powerpc32/power7/memcmp.S
@@ -1373,3 +1373,4 @@ END (memcmp)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc64/le/power10/memcmp.S b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S
index 52f244e7e77cbdf9..f81c73a29c7f65e5 100644
--- a/sysdeps/powerpc/powerpc64/le/power10/memcmp.S
+++ b/sysdeps/powerpc/powerpc64/le/power10/memcmp.S
@@ -177,3 +177,4 @@ L(tail8):
END (MEMCMP)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S
index 73a0debd4a811d8e..22399f143d089b13 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power10.S
@@ -22,5 +22,7 @@
#define libc_hidden_builtin_def(name)
#undef weak_alias
#define weak_alias(name,alias)
+#undef strong_alias
+#define strong_alias(name,alias)
#include <sysdeps/powerpc/powerpc64/le/power10/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power4.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power4.S
index d2b6c2f934e38001..fe68912a3b347916 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power4.S
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power4.S
@@ -22,5 +22,7 @@
#define libc_hidden_builtin_def(name)
#undef weak_alias
#define weak_alias(name,alias)
+#undef strong_alias
+#define strong_alias(name,alias)
#include <sysdeps/powerpc/powerpc64/power4/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power7.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power7.S
index 8671e930f093cbdb..5739471a7d1a4f65 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power7.S
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power7.S
@@ -22,5 +22,7 @@
#define libc_hidden_builtin_def(name)
#undef weak_alias
#define weak_alias(name,alias)
+#undef strong_alias
+#define strong_alias(name,alias)
#include <sysdeps/powerpc/powerpc64/power7/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power8.S b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power8.S
index eb2273d468478add..e6a93e88c616961e 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp-power8.S
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-power8.S
@@ -22,5 +22,7 @@
#define libc_hidden_builtin_def(name)
#undef weak_alias
#define weak_alias(name,alias)
+#undef strong_alias
+#define strong_alias(name,alias)
#include <sysdeps/powerpc/powerpc64/power8/memcmp.S>
diff --git a/sysdeps/powerpc/powerpc64/multiarch/memcmp-ppc64.c b/sysdeps/powerpc/powerpc64/multiarch/memcmp-ppc64.c
index 1f9f219971fdbbd9..2bc5fa50d701c0c3 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/memcmp-ppc64.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/memcmp-ppc64.c
@@ -22,6 +22,10 @@
#define weak_alias(name, aliasname) \
extern __typeof (__memcmp_ppc) aliasname \
__attribute__ ((weak, alias ("__memcmp_ppc")));
+#undef strong_alias
+#define strong_alias(name, aliasname) \
+ extern __typeof (__memcmp_ppc) aliasname \
+ __attribute__ ((alias ("__memcmp_ppc")));
#if IS_IN (libc) && defined(SHARED)
# undef libc_hidden_builtin_def
# define libc_hidden_builtin_def(name) \
diff --git a/sysdeps/powerpc/powerpc64/power4/memcmp.S b/sysdeps/powerpc/powerpc64/power4/memcmp.S
index dc1be3a0d8d80d35..cc82be115ff2bd8e 100644
--- a/sysdeps/powerpc/powerpc64/power4/memcmp.S
+++ b/sysdeps/powerpc/powerpc64/power4/memcmp.S
@@ -1374,3 +1374,4 @@ L(duzeroLength):
END (MEMCMP)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc64/power7/memcmp.S b/sysdeps/powerpc/powerpc64/power7/memcmp.S
index bc034a55bc18f520..3044f7ede95ca9bd 100644
--- a/sysdeps/powerpc/powerpc64/power7/memcmp.S
+++ b/sysdeps/powerpc/powerpc64/power7/memcmp.S
@@ -1059,3 +1059,4 @@ L(duzeroLength):
END (MEMCMP)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/powerpc/powerpc64/power8/memcmp.S b/sysdeps/powerpc/powerpc64/power8/memcmp.S
index b676b09a9b33c643..0c6a154502719064 100644
--- a/sysdeps/powerpc/powerpc64/power8/memcmp.S
+++ b/sysdeps/powerpc/powerpc64/power8/memcmp.S
@@ -1442,3 +1442,4 @@ L(duzeroLength):
END (MEMCMP)
libc_hidden_builtin_def (memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
diff --git a/sysdeps/s390/memcmp-z900.S b/sysdeps/s390/memcmp-z900.S
index 995d52e47d713623..d625bf90dd7250ee 100644
--- a/sysdeps/s390/memcmp-z900.S
+++ b/sysdeps/s390/memcmp-z900.S
@@ -164,6 +164,7 @@ END(MEMCMP_Z196)
Otherwise see sysdeps/s390/memcmp.c. */
strong_alias (MEMCMP_DEFAULT, memcmp)
weak_alias (memcmp, bcmp)
+strong_alias (memcmp, __memcmpeq)
#endif
#if defined SHARED && IS_IN (libc)
diff --git a/sysdeps/s390/memcmp.c b/sysdeps/s390/memcmp.c
index 0b4e9da71784fda3..52c20af77229d92f 100644
--- a/sysdeps/s390/memcmp.c
+++ b/sysdeps/s390/memcmp.c
@@ -46,4 +46,5 @@ s390_libc_ifunc_expr (__redirect_memcmp, memcmp,
})
)
weak_alias (memcmp, bcmp);
+strong_alias (memcmp, __memcmpeq)
#endif
diff --git a/sysdeps/sparc/sparc64/memcmp.S b/sysdeps/sparc/sparc64/memcmp.S
index 0935d31fec61e0c4..ded0fab090763336 100644
--- a/sysdeps/sparc/sparc64/memcmp.S
+++ b/sysdeps/sparc/sparc64/memcmp.S
@@ -139,4 +139,6 @@ END(memcmp)
#undef bcmp
weak_alias (memcmp, bcmp)
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 21a2e50a884c3d64..f227ae6ceec97c73 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2612,3 +2612,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index a201fd69bacc3281..0ccc3fc73ecc0e4d 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2709,6 +2709,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 261143693778ba9f..fd80704787f4ef41 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2373,3 +2373,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index a426241965d56df9..2ae6c58b8ad6fc01 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -491,6 +491,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 02f80418cc40ac06..fcfd1e8594d80aa1 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -488,6 +488,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index b7676eb372398daf..ba034b85414a2b55 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2647,3 +2647,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index f6965c9d9594910a..b7460bec8ace47c2 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2596,6 +2596,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 2e7603d9ed6728e2..a4dc341dededdc3b 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2780,6 +2780,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index dd3a56d3fef14600..94b222dbc7ffbb81 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2547,6 +2547,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index c1e0ea9c102a69d1..12fd3b63103c3e6e 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -492,6 +492,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 93161048ca26b91b..4d2296007ab1d922 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2723,6 +2723,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 0aaeec8a2707da2a..a223278a3d4a33d8 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2696,3 +2696,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index bec5f456c9756e83..780a4f5b0bf5518c 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2693,3 +2693,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 97d2127f7828312a..cd65136062a6a876 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2688,6 +2688,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 acb0756c11995d34..b5b9902db56a4c79 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2686,6 +2686,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 ebc21dde1eca0d6b..57593d5f94a184f1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2694,6 +2694,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 c68f7e3c6cc8baa7..e944d76bed0bfe06 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2598,6 +2598,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e5b6834f147f1edc..8af5a3a90dfe4089 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2735,3 +2735,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 132707c8ad52832b..3a0213b39f8f7abd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2750,6 +2750,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 0af2be31a0f4ff91..f57df0234b8bdee3 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2783,6 +2783,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index cf864632d0cc3438..259a0cfc5126ca9e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2506,6 +2506,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index d566d675d00c881b..126541daf152e1ad 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2808,3 +2808,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index c9a7eacb32ebe277..05df4d13d2c35ad1 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2375,3 +2375,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 8299131cb2ce932e..8e349cbff8cc0507 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2575,3 +2575,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index c3fe78f77fd11c78..e9de402766af0d8a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2748,6 +2748,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 83e542aa8c2563fa..1a010c745d78a07e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2543,6 +2543,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index dc502f683336ad37..22ce530975944ff6 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2603,6 +2603,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index cba1abb55621ca74..960df07b83bd2cbf 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2600,6 +2600,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index d4a516fb47518e12..eedb376f3dfeb8fb 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2743,6 +2743,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 6268875ba37ac0d4..86e0c92bef9255ab 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2570,6 +2570,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 095e914b73705601..5e59d90623c2bcba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2521,6 +2521,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 dd910f7fe934f260..94412dc134af283a 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2627,3 +2627,4 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __memcmpeq F
diff --git a/sysdeps/x86_64/memcmp.S b/sysdeps/x86_64/memcmp.S
index a9266494635ad2dd..1c217935edb18210 100644
--- a/sysdeps/x86_64/memcmp.S
+++ b/sysdeps/x86_64/memcmp.S
@@ -359,4 +359,6 @@ END(memcmp)
#undef bcmp
weak_alias (memcmp, bcmp)
+#undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
libc_hidden_builtin_def (memcmp)
diff --git a/sysdeps/x86_64/multiarch/memcmp-sse2.S b/sysdeps/x86_64/multiarch/memcmp-sse2.S
index b135fa2d4084b6d0..af737c5e6c65e9b2 100644
--- a/sysdeps/x86_64/multiarch/memcmp-sse2.S
+++ b/sysdeps/x86_64/multiarch/memcmp-sse2.S
@@ -26,6 +26,9 @@
# undef weak_alias
# define weak_alias(ignored1, ignored2)
+
+# undef strong_alias
+# define strong_alias(ignored1, ignored2)
#endif
#include <sysdeps/x86_64/memcmp.S>
diff --git a/sysdeps/x86_64/multiarch/memcmp.c b/sysdeps/x86_64/multiarch/memcmp.c
index fe725f35639793c2..4a3aad2c9c4a58fd 100644
--- a/sysdeps/x86_64/multiarch/memcmp.c
+++ b/sysdeps/x86_64/multiarch/memcmp.c
@@ -29,6 +29,8 @@
libc_ifunc_redirected (__redirect_memcmp, memcmp, IFUNC_SELECTOR ());
# undef bcmp
weak_alias (memcmp, bcmp)
+# undef __memcmpeq
+strong_alias (memcmp, __memcmpeq)
# ifdef SHARED
__hidden_ver1 (memcmp, __GI_memcmp, __redirect_memcmp)

35
glibc-RHEL-93320-10.patch Normal file
View File

@ -0,0 +1,35 @@
commit 4a41fc3cd9cea9223ea4f13f9c766a1e149a0ccc
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Apr 13 14:18:28 2022 +0200
elf: Fix memory leak in _dl_find_object_update (bug 29062)
The count can be zero if an object has already been loaded as
an indirect dependency (so that l_searchlist.r_list in its link
map is still NULL) is promoted to global scope via RTLD_GLOBAL.
Fixes commit 5d28a8962dc ("elf: Add _dl_find_object function").
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 2952c651ff26db04..f4484e69c226a0a5 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -788,6 +788,9 @@ _dl_find_object_update (struct link_map *new_map)
for (struct link_map *l = new_map; l != NULL; l = l->l_next)
/* Skip proxy maps and already-processed maps. */
count += l == l->l_real && !l->l_find_object_processed;
+ if (count == 0)
+ return true;
+
struct link_map **map_array = malloc (count * sizeof (*map_array));
if (map_array == NULL)
return false;
@@ -797,8 +800,6 @@ _dl_find_object_update (struct link_map *new_map)
if (l == l->l_real && !l->l_find_object_processed)
map_array[i++] = l;
}
- if (count == 0)
- return true;
_dl_find_object_link_map_sort (map_array, count);
bool ok = _dl_find_object_update_1 (map_array, count);

55
glibc-RHEL-93320-11.patch Normal file
View File

@ -0,0 +1,55 @@
commit 2a5b4f7a715921a232f67f6810268c6cd6aa0af2
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 8 12:08:48 2022 +0200
elf: Rename tst-audit26 to tst-audit28
tst-audit26 and tst-audit27 are already used by aarch64.
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 90365b164b8061d891a640a3ae477a6500753291)
diff --git a/elf/Makefile b/elf/Makefile
index e1e6107c277f5f76..7382cf6dd498ce8a 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -395,7 +395,7 @@ tests += \
tst-audit24d \
tst-audit25a \
tst-audit25b \
- tst-audit26 \
+ tst-audit28 \
tst-auditmany \
tst-auxobj \
tst-auxobj-dlopen \
@@ -782,7 +782,7 @@ modules-names = \
tst-auditmod24c \
tst-auditmod24d \
tst-auditmod25 \
- tst-auditmod26 \
+ tst-auditmod28 \
tst-auxvalmod \
tst-big-note-lib \
tst-deep1mod1 \
@@ -2347,9 +2347,9 @@ $(objpfx)tst-audit25b: $(objpfx)tst-audit25mod1.so \
LDFLAGS-tst-audit25b = -Wl,-z,now
tst-audit25b-ARGS = -- $(host-test-program-cmd)
-$(objpfx)tst-audit26.out: $(objpfx)tst-auditmod26.so
-$(objpfx)tst-auditmod26.so: $(libsupport)
-tst-audit26-ENV = LD_AUDIT=$(objpfx)tst-auditmod26.so
+$(objpfx)tst-audit28.out: $(objpfx)tst-auditmod28.so
+$(objpfx)tst-auditmod28.so: $(libsupport)
+tst-audit28-ENV = LD_AUDIT=$(objpfx)tst-auditmod28.so
# tst-sonamemove links against an older implementation of the library.
LDFLAGS-tst-sonamemove-linkmod1.so = \
diff --git a/elf/tst-audit26.c b/elf/tst-audit28.c
similarity index 100%
rename from elf/tst-audit26.c
rename to elf/tst-audit28.c
diff --git a/elf/tst-auditmod26.c b/elf/tst-auditmod28.c
similarity index 100%
rename from elf/tst-auditmod26.c
rename to elf/tst-auditmod28.c

51
glibc-RHEL-93320-12.patch Normal file
View File

@ -0,0 +1,51 @@
commit 1bcfe0f732066ae5336b252295591ebe7e51c301
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 7 10:11:26 2023 +0200
elf: _dl_find_object may return 1 during early startup (bug 30515)
Success is reported with a 0 return value, and failure is -1.
Enhance the kitchen sink test elf/tst-audit28 to cover
_dl_find_object as well.
Fixes commit 5d28a8962dcb ("elf: Add _dl_find_object function")
and bug 30515.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index f4484e69c226a0a5..83a03fbd7c83c6be 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -46,7 +46,7 @@ _dl_find_object_slow (void *pc, struct dl_find_object *result)
struct dl_find_object_internal internal;
_dl_find_object_from_map (l, &internal);
_dl_find_object_to_external (&internal, result);
- return 1;
+ return 0;
}
/* Object not found. */
diff --git a/elf/tst-auditmod28.c b/elf/tst-auditmod28.c
index db7ba95abec20f53..9e0a122c389535d0 100644
--- a/elf/tst-auditmod28.c
+++ b/elf/tst-auditmod28.c
@@ -71,6 +71,17 @@ la_version (unsigned int current)
TEST_VERIFY (dladdr1 (&_exit, &info, &extra_info, RTLD_DL_LINKMAP) != 0);
TEST_VERIFY (extra_info == handle);
+ /* Check _dl_find_object. */
+ struct dl_find_object dlfo;
+ TEST_COMPARE (_dl_find_object (__builtin_return_address (0), &dlfo), 0);
+ /* "ld.so" is seen with --enable-hardcoded-path-in-tests. */
+ if (strcmp (basename (dlfo.dlfo_link_map->l_name), "ld.so") != 0)
+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LD_SO);
+ TEST_COMPARE (_dl_find_object (dlsym (handle, "environ"), &dlfo), 0);
+ TEST_COMPARE_STRING (basename (dlfo.dlfo_link_map->l_name), LIBC_SO);
+ TEST_COMPARE (_dl_find_object ((void *) 1, &dlfo), -1);
+ TEST_COMPARE (_dl_find_object ((void *) -1, &dlfo), -1);
+
/* Verify that dlmopen creates a new namespace. */
void *dlmopen_handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
TEST_VERIFY (dlmopen_handle != handle);

58
glibc-RHEL-93320-13.patch Normal file
View File

@ -0,0 +1,58 @@
commit 6c915c73d08028987232f6dc718f218c61113240
Author: Aurelien Jarno <aurelien@aurel32.net>
Date: Sun Nov 10 10:50:34 2024 +0100
elf: handle addition overflow in _dl_find_object_update_1 [BZ #32245]
The remaining_to_add variable can be 0 if (current_used + count) wraps,
This is caught by GCC 14+ on hppa, which determines from there that
target_seg could be be NULL when remaining_to_add is zero, which in
turns causes a -Wstringop-overflow warning:
In file included from ../include/atomic.h:49,
from dl-find_object.c:20:
In function '_dlfo_update_init_seg',
inlined from '_dl_find_object_update_1' at dl-find_object.c:689:30,
inlined from '_dl_find_object_update' at dl-find_object.c:805:13:
../sysdeps/unix/sysv/linux/hppa/atomic-machine.h:44:4: error: '__atomic_store_4' writing 4 bytes into a region of size 0 overflows the destination [-Werror=stringop-overflow=]
44 | __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dl-find_object.c:644:3: note: in expansion of macro 'atomic_store_relaxed'
644 | atomic_store_relaxed (&seg->size, new_seg_size);
| ^~~~~~~~~~~~~~~~~~~~
In function '_dl_find_object_update':
cc1: note: destination object is likely at address zero
In practice, this is not possible as it represent counts of link maps.
Link maps have sizes larger than 1 byte, so the sum of any two link map
counts will always fit within a size_t without wrapping around.
This patch therefore adds a check on remaining_to_add == 0 and tell GCC
that this can not happen using __builtin_unreachable.
Thanks to Andreas Schwab for the investigation.
Closes: BZ #32245
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Tested-by: John David Anglin <dave.anglin@bell.net>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 83a03fbd7c83c6be..56894ca24a510b07 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -661,6 +661,14 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
= _dlfo_loaded_mappings[!active_idx];
size_t remaining_to_add = current_used + count;
+ /* remaining_to_add can be 0 if (current_used + count) wraps, but in practice
+ this is not possible as it represent counts of link maps. Link maps have
+ sizes larger than 1 byte, so the sum of any two link map counts will
+ always fit within a size_t without wrapping around. This check ensures
+ that target_seg is not erroneously considered potentially NULL by GCC. */
+ if (remaining_to_add == 0)
+ __builtin_unreachable ();
+
/* Ensure that the new segment chain has enough space. */
{
size_t new_allocated

812
glibc-RHEL-93320-14.patch Normal file
View File

@ -0,0 +1,812 @@
commit 5f3a7ebc358fdcbafcab4f1bf4067120fb519dfc
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Jan 12 11:31:53 2022 -0300
Linux: Add epoll_pwait2 (BZ #27359)
It is similar to epoll_wait, with the difference the timeout has
nanosecond resoluting by using struct timespec instead of int.
Although Linux interface only provides 64 bit time_t support, old
32 bit interface is also provided (so keep in sync with current
practice and to no force opt-in on 64 bit time_t).
Checked on x86_64-linux-gnu and i686-linux-gnu.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
Conflicts:
sysdeps/unix/sysv/linux/Makefile
Updated for layout change
sysdeps/unix/sysv/linux/or1k/libc.abilist
Omitted
diff --git a/include/sys/epoll.h b/include/sys/epoll.h
index 86e0a54e62a5628b..8049381a269956ce 100644
--- a/include/sys/epoll.h
+++ b/include/sys/epoll.h
@@ -4,6 +4,14 @@
# ifndef _ISOMAC
libc_hidden_proto (epoll_pwait)
+#if __TIMESIZE == 64
+# define __epoll_pwait2_time64 epoll_pwait2
+#else
+extern int __epoll_pwait2_time64 (int fd, struct epoll_event *ev, int maxev,
+ const struct __timespec64 *tmo,
+ const sigset_t *s);
+libc_hidden_proto (__epoll_pwait2_time64)
+#endif
# endif /* !_ISOMAC */
#endif
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 94eb2665b27371a4..61a40e31bacdbc22 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -55,7 +55,7 @@ endif
ifeq ($(subdir),misc)
sysdep_routines += adjtimex clone umount umount2 readahead sysctl \
- setfsuid setfsgid epoll_pwait signalfd \
+ setfsuid setfsgid epoll_pwait epoll_pwait2 signalfd \
eventfd eventfd_read eventfd_write prlimit \
personality epoll_wait tee vmsplice splice \
open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
@@ -131,6 +131,7 @@ tests += tst-clone tst-clone2 tst-clone3 tst-fanotify tst-personality \
tst-clock_adjtime tst-adjtimex tst-ntp_adjtime tst-ntp_gettime \
tst-ntp_gettimex tst-sigtimedwait tst-misalign-clone \
tst-close_range \
+ tst-epoll \
tst-prctl \
tst-scm_rights \
tst-getauxval \
@@ -160,6 +161,7 @@ endif
tests-time64 += \
tst-adjtimex-time64 \
tst-clock_adjtime-time64 \
+ tst-epoll-time64 \
tst-ntp_adjtime-time64 \
tst-ntp_gettime-time64 \
tst-ntp_gettimex-time64 \
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index 3f8809a1581f27d0..ded087f30ea953fc 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -293,6 +293,12 @@ libc {
%endif
close_range;
}
+ GLIBC_2.35 {
+%ifdef TIME64_NON_DEFAULT
+ __epoll_pwait2_time64;
+%endif
+ epoll_pwait2;
+ }
GLIBC_PRIVATE {
# functions used in other libraries
__syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index fed942ed4b9ef469..c1a5ee90e6d4c63e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2614,3 +2614,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 28679327043ff0f2..1a30d0666bb76f41 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2711,6 +2711,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 239db7bab0a18a87..e5dfdab357c72440 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2375,3 +2375,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index bc79dcfe8ab4c723..4d3fd872788ba1f0 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -491,8 +491,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 614607fd6baa8c6f..009dc9da14ee5eed 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -488,8 +488,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 2b61543f0dd47034..df8da506cde36eeb 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2647,5 +2647,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/epoll_pwait2.c b/sysdeps/unix/sysv/linux/epoll_pwait2.c
new file mode 100644
index 0000000000000000..e38a1b2349edb040
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/epoll_pwait2.c
@@ -0,0 +1,44 @@
+/* Implementation of epoll_pwait2 syscall wrapper.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <sys/epoll.h>
+#include <sysdep.h>
+
+int
+__epoll_pwait2_time64 (int fd, struct epoll_event *ev, int maxev,
+ const struct __timespec64 *tmo, const sigset_t *s)
+{
+ /* The syscall only supports 64-bit time_t. */
+ return SYSCALL_CANCEL (epoll_pwait2, fd, ev, maxev, tmo, s, __NSIG_BYTES);
+}
+#if __TIMESIZE != 64
+libc_hidden_def (__epoll_pwait2_time64)
+
+int
+epoll_pwait2 (int fd, struct epoll_event *ev, int maxev,
+ const struct timespec *tmo, const sigset_t *s)
+{
+ struct __timespec64 tmo64, *ptmo64 = NULL;
+ if (tmo != NULL)
+ {
+ tmo64 = valid_timespec_to_timespec64 (*tmo);
+ ptmo64 = &tmo64;
+ }
+ return __epoll_pwait2_time64 (fd, ev, maxev, ptmo64, s);
+}
+#endif
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 6b3cb1adb40c0a01..7ea1b017d05cc1fb 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2596,8 +2596,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 7f608c1b64454bff..99ccf354b3d1a762 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2780,8 +2780,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 865deec43f99a036..201542d1e76daa60 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2549,6 +2549,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index a172d746328ddeeb..32fd72a78df65bd8 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -492,8 +492,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 174e9c7739f966ac..d26f0ae6c2475984 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2723,8 +2723,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index d042be1369b7d264..520ca0882d8d720b 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2696,5 +2696,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 332da62de23b88b8..9162c3139661b2c9 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2693,5 +2693,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 2d6ec0d0e8f3c797..656fdbdcaa70dad6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2688,8 +2688,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 6c5befa72bb5602b..5f0b90d318030622 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2686,8 +2686,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 5fb24c97e1e6f05d..9f4891fc08d71521 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2694,8 +2694,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 f4f29fc15ee8f1a2..f1b0644bc33ba065 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2600,6 +2600,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 2e7300cd0512ad78..1cf88e38b943eeb9 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2735,5 +2735,7 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 129a2f16a7b731d3..9692335d106f9400 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2750,8 +2750,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7e232267791057a3..7da0ed59f2ccb080 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2783,8 +2783,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 6f97392b7030ee95..72cf6851988a7b91 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2508,6 +2508,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 29058a041a9cdba1..ee7f67f4d09ba7ae 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2810,3 +2810,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index d2924766d2f33039..b8c0854508ec8714 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2377,3 +2377,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index b770e05da3ae0350..90f331fc0bc06278 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2577,3 +2577,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index bed3433a2b75d3b4..ded5e3c0ce4da82c 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2748,8 +2748,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 4f1a143da504d98c..4b262992540d18d6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2545,6 +2545,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 92c8dec8ec28c54a..8bfd716fd238a35b 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2603,8 +2603,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 263da58cb7dada2c..47fd204d84ea2432 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2600,8 +2600,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 0171efe7db109153..9b82f15109ca4b1a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2743,8 +2743,10 @@ GLIBC_2.34 tss_create F
GLIBC_2.34 tss_delete F
GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
+GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 7f8d45f362e63584..94caf012a7e9cada 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2572,6 +2572,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sys/epoll.h b/sysdeps/unix/sysv/linux/sys/epoll.h
index b6751f66971b82ca..5eb611da1bfd802f 100644
--- a/sysdeps/unix/sysv/linux/sys/epoll.h
+++ b/sysdeps/unix/sysv/linux/sys/epoll.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <bits/types/sigset_t.h>
+#include <bits/types/struct_timespec.h>
/* Get the platform-dependent flags. */
#include <bits/epoll.h>
@@ -133,6 +134,26 @@ extern int epoll_pwait (int __epfd, struct epoll_event *__events,
int __maxevents, int __timeout,
const __sigset_t *__ss);
+/* Same as epoll_pwait, but the timeout as a timespec.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+#ifndef __USE_TIME_BITS64
+extern int epoll_pwait2 (int __epfd, struct epoll_event *__events,
+ int __maxevents, const struct timespec *__timeout,
+ const __sigset_t *__ss);
+#else
+# ifdef __REDIRECT
+extern int __REDIRECT (epoll_pwait2, (int __epfd, struct epoll_event *__ev,
+ int __maxevs,
+ const struct timespec *__timeout,
+ const __sigset_t *__ss),
+ __epoll_pwait2_time64);
+# else
+# define epoll_pwait2 __epoll_pwait2_time64
+# endif
+#endif
+
__END_DECLS
#endif /* sys/epoll.h */
diff --git a/sysdeps/unix/sysv/linux/tst-epoll-time64.c b/sysdeps/unix/sysv/linux/tst-epoll-time64.c
new file mode 100644
index 0000000000000000..2e0236792e460ce0
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-epoll-time64.c
@@ -0,0 +1 @@
+#include "tst-epoll.c"
diff --git a/sysdeps/unix/sysv/linux/tst-epoll.c b/sysdeps/unix/sysv/linux/tst-epoll.c
new file mode 100644
index 0000000000000000..3ef6ca9fbd3c5a2b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-epoll.c
@@ -0,0 +1,211 @@
+/* Basic tests for Linux epoll_* wrappers.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <intprops.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xsignal.h>
+#include <support/xunistd.h>
+#include <support/xtime.h>
+#include <stdlib.h>
+#include <sys/epoll.h>
+
+/* The test focus on checking if the timeout argument is correctly handled
+ by glibc wrappers. */
+
+static void
+handler (int sig)
+{
+}
+
+typedef int (*epoll_wait_check_t) (int, struct epoll_event *, int,
+ int, const sigset_t *);
+
+static void
+test_epoll_basic (epoll_wait_check_t epoll_wait_check)
+{
+ {
+ sigset_t ss_usr1;
+ sigemptyset (&ss_usr1);
+ sigaddset (&ss_usr1, SIGUSR1);
+ TEST_COMPARE (sigprocmask (SIG_BLOCK, &ss_usr1, NULL), 0);
+ }
+
+ int fds[2][2];
+ xpipe (fds[0]);
+ xpipe (fds[1]);
+
+ sigset_t ss;
+ TEST_COMPARE (sigprocmask (SIG_SETMASK, NULL, &ss), 0);
+ sigdelset (&ss, SIGUSR1);
+
+ int efd = epoll_create1 (0);
+ TEST_VERIFY_EXIT (efd != -1);
+
+ struct epoll_event event;
+
+ event.data.fd = fds[1][0];
+ event.events = EPOLLIN | EPOLLET;
+ TEST_COMPARE (epoll_ctl (efd, EPOLL_CTL_ADD, fds[1][0], &event), 0);
+
+ pid_t parent = getpid ();
+ pid_t p = xfork ();
+ if (p == 0)
+ {
+ xclose (fds[0][1]);
+ xclose (fds[1][0]);
+
+ event.data.fd = fds[0][0];
+ event.events = EPOLLIN | EPOLLET;
+ TEST_COMPARE (epoll_ctl (efd, EPOLL_CTL_ADD, fds[0][0], &event), 0);
+
+ int e;
+ do
+ {
+ if (getppid () != parent)
+ FAIL_EXIT1 ("getppid()=%d != parent=%d", getppid(), parent);
+
+ errno = 0;
+ e = epoll_wait_check (efd, &event, 1, 500, &ss);
+ }
+ while (e == 0);
+
+ TEST_COMPARE (e, -1);
+ TEST_COMPARE (errno, EINTR);
+
+ TEMP_FAILURE_RETRY (write (fds[1][1], "foo", 3));
+
+ exit (0);
+ }
+
+ xclose (fds[0][0]);
+ xclose (fds[1][1]);
+
+ /* Wait some time so child is blocked on the syscall. */
+ nanosleep (&(struct timespec) {0, 10000000}, NULL);
+ TEST_COMPARE (kill (p, SIGUSR1), 0);
+
+ int e = epoll_wait_check (efd, &event, 1, 500000000, &ss);
+ TEST_COMPARE (e, 1);
+ TEST_VERIFY (event.events & EPOLLIN);
+
+ xclose (fds[0][1]);
+ xclose (fds[1][0]);
+ xclose (efd);
+}
+
+
+static void
+test_epoll_large_timeout (epoll_wait_check_t epoll_wait_check)
+{
+ timer_t t = support_create_timer (0, 100000000, true, NULL);
+
+ int fds[2];
+ xpipe (fds);
+
+ fd_set rfds;
+ FD_ZERO (&rfds);
+ FD_SET (fds[0], &rfds);
+
+ sigset_t ss;
+ TEST_COMPARE (sigprocmask (SIG_SETMASK, NULL, &ss), 0);
+ sigdelset (&ss, SIGALRM);
+
+ int efd = epoll_create1 (0);
+ TEST_VERIFY_EXIT (efd != -1);
+
+ struct epoll_event event;
+ event.data.fd = fds[0];
+ event.events = EPOLLIN | EPOLLET;
+ TEST_COMPARE (epoll_ctl (efd, EPOLL_CTL_ADD, fds[0], &event), 0);
+
+ int tmo = TYPE_MAXIMUM (int);
+ TEST_COMPARE (epoll_wait_check (efd, &event, 1, tmo, &ss), -1);
+ TEST_VERIFY (errno == EINTR || errno == EOVERFLOW);
+
+ TEST_COMPARE (epoll_wait_check (efd, &event, 1, -1, &ss), -1);
+ TEST_VERIFY (errno == EINTR || errno == EOVERFLOW);
+
+ support_delete_timer (t);
+
+ xclose (fds[0]);
+ xclose (fds[1]);
+ xclose (efd);
+}
+
+
+static int
+epoll_wait_check (int epfd, struct epoll_event *ev, int maxev, int tmo,
+ const sigset_t *ss)
+{
+ sigset_t orig;
+ TEST_COMPARE (sigprocmask (SIG_SETMASK, ss, &orig), 0);
+ int r = epoll_wait (epfd, ev, maxev, tmo);
+ TEST_COMPARE (sigprocmask (SIG_SETMASK, &orig, NULL), 0);
+ return r;
+}
+
+static int
+epoll_pwait_check (int epfd, struct epoll_event *ev, int maxev, int tmo,
+ const sigset_t *ss)
+{
+ return epoll_pwait (epfd, ev, maxev, tmo, ss);
+}
+
+static int
+epoll_pwait2_check (int epfd, struct epoll_event *ev, int maxev, int tmo,
+ const sigset_t *ss)
+{
+ time_t s = tmo == -1 ? TYPE_MAXIMUM (time_t) : tmo / 1000;
+ long int ns = tmo == -1 ? 0 : (tmo % 1000) * 1000000;
+ return epoll_pwait2 (epfd, ev, maxev, &(struct timespec) { s, ns }, ss);
+}
+
+static int
+do_test (void)
+{
+ {
+ struct sigaction sa;
+ sa.sa_handler = handler;
+ sa.sa_flags = 0;
+ sigemptyset (&sa.sa_mask);
+ xsigaction (SIGUSR1, &sa, NULL);
+
+ sa.sa_handler = SIG_IGN;
+ xsigaction (SIGCHLD, &sa, NULL);
+ }
+
+ int r = epoll_pwait2 (-1, NULL, 0, NULL, NULL);
+ TEST_COMPARE (r, -1);
+ bool pwait2_supported = errno != ENOSYS;
+
+ test_epoll_basic (epoll_wait_check);
+ test_epoll_basic (epoll_pwait_check);
+ if (pwait2_supported)
+ test_epoll_basic (epoll_pwait2_check);
+
+ test_epoll_large_timeout (epoll_wait_check);
+ test_epoll_large_timeout (epoll_pwait_check);
+ if (pwait2_supported)
+ test_epoll_large_timeout (epoll_pwait2_check);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index c2f1a8ecc6d04dcf..140e9e8c1ce7dd37 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2523,6 +2523,7 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 8b43acf1005f1790..04d13ce27e3747f5 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2629,3 +2629,4 @@ GLIBC_2.34 tss_get F
GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 epoll_pwait2 F

35
glibc-RHEL-93320-15.patch Normal file
View File

@ -0,0 +1,35 @@
commit cc5372806a4bf34cb5c9038d1716b5ea6202abd0
Author: Alejandro Colomar <alx.manpages@gmail.com>
Date: Wed May 31 22:44:22 2023 +0200
Fix invalid use of NULL in epoll_pwait2(2) test
epoll_pwait2(2)'s second argument should be nonnull. We're going to add
__nonnull to the prototype, so let's fix the test accordingly. We can
use a dummy variable to avoid passing NULL.
Reported-by: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
diff --git a/sysdeps/unix/sysv/linux/tst-epoll.c b/sysdeps/unix/sysv/linux/tst-epoll.c
index 3ef6ca9fbd3c5a2b..c31d4793115acc7d 100644
--- a/sysdeps/unix/sysv/linux/tst-epoll.c
+++ b/sysdeps/unix/sysv/linux/tst-epoll.c
@@ -180,6 +180,8 @@ epoll_pwait2_check (int epfd, struct epoll_event *ev, int maxev, int tmo,
static int
do_test (void)
{
+ struct epoll_event ev;
+
{
struct sigaction sa;
sa.sa_handler = handler;
@@ -191,7 +193,7 @@ do_test (void)
xsigaction (SIGCHLD, &sa, NULL);
}
- int r = epoll_pwait2 (-1, NULL, 0, NULL, NULL);
+ int r = epoll_pwait2 (-1, &ev, 0, NULL, NULL);
TEST_COMPARE (r, -1);
bool pwait2_supported = errno != ENOSYS;

891
glibc-RHEL-93320-16.patch Normal file
View File

@ -0,0 +1,891 @@
commit 342cc934a3bf74ac618e2318d738f22ac93257ba
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Jun 14 14:41:31 2021 -0300
posix: Add terminal control setting support for posix_spawn
Currently there is no proper way to set the controlling terminal through
posix_spawn in race free manner [1]. This forces shell implementations
to keep using fork+exec when launching background process groups,
even when using posix_spawn yields better performance.
This patch adds a new GNU extension so the creating process can
configure the created process terminal group. This is done with a new
flag, POSIX_SPAWN_TCSETPGROUP, along with two new attribute functions:
posix_spawnattr_tcsetpgrp_np, and posix_spawnattr_tcgetpgrp_np.
The function sets a new attribute, spawn-tcgroupfd, that references to
the controlling terminal.
The controlling terminal is set after the spawn-pgroup attribute, and
uses the spawn-tcgroupfd along with current creating process group
(so it is composable with POSIX_SPAWN_SETPGROUP).
To create a process and set the controlling terminal, one can use the
following sequence:
posix_spawnattr_t attr;
posix_spawnattr_init (&attr);
posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP);
posix_spawnattr_tcsetpgrp_np (&attr, tcfd);
If the idea is also to create a new process groups:
posix_spawnattr_t attr;
posix_spawnattr_init (&attr);
posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP
| POSIX_SPAWN_SETPGROUP);
posix_spawnattr_tcsetpgrp_np (&attr, tcfd);
posix_spawnattr_setpgroup (&attr, 0);
The controlling terminal file descriptor is ignored if the new flag is
not set.
This interface is slight different than the one provided by QNX [2],
which only provides the POSIX_SPAWN_TCSETPGROUP flag. The QNX
documentation does not specify how the controlling terminal is obtained
nor how it iteracts with POSIX_SPAWN_SETPGROUP. Since a glibc
implementation is library based, it is more straightforward and avoid
requires additional file descriptor operations to request the caller
to setup the controlling terminal file descriptor (and it also allows
a bit less error handling by posix_spawn).
Checked on x86_64-linux-gnu and i686-linux-gnu.
[1] https://github.com/ksh93/ksh/issues/79
[2] https://www.qnx.com/developers/docs/7.0.0/index.html#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
posix/Makefile
Updated for layout change
sysdeps/unix/sysv/linux/or1k/libc.abilist
Omitted
diff --git a/include/unistd.h b/include/unistd.h
index 5824485629793ccb..a5f6a5ca673a07cf 100644
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -173,6 +173,8 @@ extern int __truncate (const char *path, __off_t __length);
extern void *__sbrk (intptr_t __delta);
libc_hidden_proto (__sbrk)
+extern int __tcsetpgrp (int fd, __pid_t pgrp);
+libc_hidden_proto (__tcsetpgrp)
/* This variable is set nonzero at startup if the process's effective
IDs differ from its real IDs, or it is otherwise indicated that
diff --git a/posix/Makefile b/posix/Makefile
index 4c32a088a73723c7..8cd6963029585e3d 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -64,6 +64,7 @@ routines := \
spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
+ spawnattr_tcgetpgrp spawnattr_tcsetpgrp \
posix_madvise \
get_child_max sched_cpucount sched_cpualloc sched_cpufree \
streams-compat \
@@ -111,7 +112,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \
tst-sched_getaffinity \
tst-cpuset-dynamic \
tst-cpuset-static \
-
+ tst-spawn6
# Test for the glob symbol version that was replaced in glibc 2.27.
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
@@ -292,6 +293,7 @@ tst-execvpe5-ARGS = -- $(host-test-program-cmd)
tst-spawn-ARGS = -- $(host-test-program-cmd)
tst-spawn-static-ARGS = $(tst-spawn-ARGS)
tst-spawn5-ARGS = -- $(host-test-program-cmd)
+tst-spawn6-ARGS = -- $(host-test-program-cmd)
tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir
tst-chmod-ARGS = $(objdir)
tst-vfork3-ARGS = --test-dir=$(objpfx)
diff --git a/posix/Versions b/posix/Versions
index a78792135fb6a707..e4f4f649b0f21e85 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -156,6 +156,10 @@ libc {
execveat;
posix_spawn_file_actions_addclosefrom_np;
}
+ GLIBC_2.35 {
+ posix_spawnattr_tcgetpgrp_np;
+ posix_spawnattr_tcsetpgrp_np;
+ }
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
__nanosleep_nocancel; __pause_nocancel;
diff --git a/posix/spawn.h b/posix/spawn.h
index 990d8a6ba28855ae..742d4cb6257907b5 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -34,7 +34,8 @@ typedef struct
sigset_t __ss;
struct sched_param __sp;
int __policy;
- int __pad[16];
+ int __ctty_fd;
+ int __pad[15];
} posix_spawnattr_t;
@@ -59,6 +60,7 @@ typedef struct
#ifdef __USE_GNU
# define POSIX_SPAWN_USEVFORK 0x40
# define POSIX_SPAWN_SETSID 0x80
+# define POSIX_SPAWN_TCSETPGROUP 0x100
#endif
@@ -166,6 +168,18 @@ extern int posix_spawnattr_setschedparam (posix_spawnattr_t *__restrict __attr,
__restrict __schedparam)
__THROW __nonnull ((1, 2));
+#ifdef __USE_GNU
+/* Make the spawned process the foreground process group on the terminal
+ associated with FD (which must be a controlling terminal, and still be
+ associated with its session). */
+extern int posix_spawnattr_tcsetpgrp_np (posix_spawnattr_t *__attr, int fd)
+ __THROW __nonnull ((1));
+
+/* Return the associated terminal FD in the attribute structure. */
+extern int posix_spawnattr_tcgetpgrp_np (const posix_spawnattr_t *
+ __restrict __attr, int *fd)
+ __THROW __nonnull ((1, 2));
+#endif
/* Initialize data structure for file attribute for `spawn' call. */
extern int posix_spawn_file_actions_init (posix_spawn_file_actions_t *
diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c
index 2b033a50fc08180f..95f521d04d71aca2 100644
--- a/posix/spawnattr_setflags.c
+++ b/posix/spawnattr_setflags.c
@@ -26,7 +26,8 @@
| POSIX_SPAWN_SETSCHEDPARAM \
| POSIX_SPAWN_SETSCHEDULER \
| POSIX_SPAWN_SETSID \
- | POSIX_SPAWN_USEVFORK)
+ | POSIX_SPAWN_USEVFORK \
+ | POSIX_SPAWN_TCSETPGROUP)
/* Store flags in the attribute structure. */
int
diff --git a/posix/spawnattr_tcgetpgrp.c b/posix/spawnattr_tcgetpgrp.c
new file mode 100644
index 0000000000000000..8db33e447498ce7d
--- /dev/null
+++ b/posix/spawnattr_tcgetpgrp.c
@@ -0,0 +1,26 @@
+/* Get the controlling terminal option.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <spawn.h>
+
+int
+posix_spawnattr_tcgetpgrp_np (const posix_spawnattr_t *attr, int *fd)
+{
+ *fd = attr->__ctty_fd;
+ return 0;
+}
diff --git a/posix/spawnattr_tcsetpgrp.c b/posix/spawnattr_tcsetpgrp.c
new file mode 100644
index 0000000000000000..c3b2ea2718e2a1f3
--- /dev/null
+++ b/posix/spawnattr_tcsetpgrp.c
@@ -0,0 +1,26 @@
+/* Set the controlling terminal option.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <spawn.h>
+
+int
+posix_spawnattr_tcsetpgrp_np (posix_spawnattr_t *attr, int fd)
+{
+ attr->__ctty_fd = fd;
+ return 0;
+}
diff --git a/posix/tst-spawn6.c b/posix/tst-spawn6.c
new file mode 100644
index 0000000000000000..5f95bd1938a69552
--- /dev/null
+++ b/posix/tst-spawn6.c
@@ -0,0 +1,175 @@
+/* Check posix_spawn set controlling terminal extension.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <intprops.h>
+#include <paths.h>
+#include <spawn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/wait.h>
+
+static int
+handle_restart (const char *argv1)
+{
+ int fd = xopen (_PATH_TTY, O_RDONLY, 0600);
+
+ /* If process group is not changed (POSIX_SPAWN_SETPGROUP), then check
+ the creating process one, otherwise check against the process group
+ itself. */
+ pid_t pgrp;
+ if (strcmp (argv1, "setgrpr") != 0)
+ TEST_COMPARE (sscanf (argv1, "%d", &pgrp), 1);
+ else
+ {
+ pgrp = getpgrp ();
+ /* Check if a new process group was actually created. */
+ pid_t ppid = getppid ();
+ pid_t pgid = getpgid (ppid);
+ TEST_VERIFY (pgid != pgrp);
+ }
+
+ TEST_COMPARE (tcgetpgrp (fd), pgrp);
+
+ xclose (fd);
+ return 0;
+}
+
+static int restart;
+#define CMDLINE_OPTIONS \
+ { "restart", no_argument, &restart, 1 },
+
+static void
+run_subprogram (int argc, char *argv[], const posix_spawnattr_t *attr,
+ int exp_err)
+{
+ short int flags;
+ TEST_COMPARE (posix_spawnattr_getflags (attr, &flags), 0);
+ bool setpgrp = flags & POSIX_SPAWN_SETPGROUP;
+
+ char *spargv[9];
+ char pgrp[INT_STRLEN_BOUND (pid_t)];
+
+ int i = 0;
+ for (; i < argc - 1; i++)
+ spargv[i] = argv[i + 1];
+ spargv[i++] = (char *) "--direct";
+ spargv[i++] = (char *) "--restart";
+ if (setpgrp)
+ spargv[i++] = (char *) "setgrpr";
+ else
+ {
+ snprintf (pgrp, sizeof pgrp, "%d", getpgrp ());
+ spargv[i++] = pgrp;
+ }
+ spargv[i] = NULL;
+ TEST_VERIFY_EXIT (i < array_length (spargv));
+
+ pid_t pid;
+ TEST_COMPARE (posix_spawn (&pid, argv[1], NULL, attr, spargv, environ),
+ exp_err);
+ if (exp_err != 0)
+ return;
+
+ int status;
+ TEST_COMPARE (xwaitpid (pid, &status, WUNTRACED), pid);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_VERIFY (!WIFSTOPPED (status));
+ TEST_VERIFY (!WIFSIGNALED (status));
+ TEST_COMPARE (WEXITSTATUS (status), 0);
+}
+
+static int
+do_test (int argc, char *argv[])
+{
+ /* We must have either:
+ - four parameters left if called initially:
+ + path to ld.so optional
+ + "--library-path" optional
+ + the library path optional
+ + the application name
+ - six parameters left if called through re-execution:
+ + --setgrpr optional
+ */
+
+ if (restart)
+ return handle_restart (argv[1]);
+
+ int tcfd = xopen (_PATH_TTY, O_RDONLY, 0600);
+
+ /* Check getters and setters. */
+ {
+ posix_spawnattr_t attr;
+ TEST_COMPARE (posix_spawnattr_init (&attr), 0);
+ TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+
+ int fd;
+ TEST_COMPARE (posix_spawnattr_tcgetpgrp_np (&attr, &fd), 0);
+ TEST_COMPARE (tcfd, fd);
+ }
+
+ /* Check setting the controlling terminal without changing the group. */
+ {
+ posix_spawnattr_t attr;
+ TEST_COMPARE (posix_spawnattr_init (&attr), 0);
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP),
+ 0);
+ TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+
+ run_subprogram (argc, argv, &attr, 0);
+ }
+
+ /* Check setting both the controlling terminal and the create a new process
+ group. */
+ {
+ posix_spawnattr_t attr;
+ TEST_COMPARE (posix_spawnattr_init (&attr), 0);
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP
+ | POSIX_SPAWN_SETPGROUP),
+ 0);
+ TEST_COMPARE (posix_spawnattr_setpgroup (&attr, 0), 0);
+ TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+
+ run_subprogram (argc, argv, &attr, 0);
+ }
+
+ /* Trying to set the controlling terminal after a setsid incurs in a ENOTTY
+ from tcsetpgrp. */
+ {
+ posix_spawnattr_t attr;
+ TEST_COMPARE (posix_spawnattr_init (&attr), 0);
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP
+ | POSIX_SPAWN_SETSID), 0);
+ TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+
+ run_subprogram (argc, argv, &attr, ENOTTY);
+ }
+
+ xclose (tcfd);
+
+ return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 060e389bbbd2d1de..4d71181643c19b0d 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -390,6 +390,19 @@ retry:
if (!err && (flags & POSIX_SPAWN_SETPGROUP) != 0)
err = __proc_setpgrp (proc, new_pid, attrp->__pgrp);
+ /* Set the controlling terminal. */
+ if (!err && (flags & POSIX_SPAWN_TCSETPGROUP) != 0)
+ {
+ pid_t pgrp;
+ /* Check if it is possible to avoid an extra syscall. */
+ if ((attrp->__flags & POSIX_SPAWN_SETPGROUP) != 0 && attrp->__pgrp != 0)
+ pgrp = attrp->__pgrp;
+ else
+ err = __proc_getpgrp (proc, new_pid, &pgrp);
+ if (!err)
+ err = __tcsetpgrp (attrp->__ctty_fd, pgrp);
+ }
+
/* Set the effective user and group IDs. */
if (!err && (flags & POSIX_SPAWN_RESETIDS) != 0)
{
diff --git a/sysdeps/unix/bsd/tcsetpgrp.c b/sysdeps/unix/bsd/tcsetpgrp.c
index 98c88db3ae879a17..3930b4f674172195 100644
--- a/sysdeps/unix/bsd/tcsetpgrp.c
+++ b/sysdeps/unix/bsd/tcsetpgrp.c
@@ -22,7 +22,9 @@
/* Set the foreground process group ID of FD set PGRP_ID. */
int
-tcsetpgrp (int fd, pid_t pgrp_id)
+__tcsetpgrp (int fd, pid_t pgrp_id)
{
return __ioctl (fd, TIOCSPGRP, &pgrp_id);
}
+weak_alias (__tcsetpgrp, tcsetpgrp)
+libc_hidden_def (__tcsetpgrp)
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index c1a5ee90e6d4c63e..9dd574d9e2a7b541 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2615,3 +2615,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 1a30d0666bb76f41..f66704877eb43052 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2712,6 +2712,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index e5dfdab357c72440..97aa3da1ad15a459 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2376,3 +2376,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 4d3fd872788ba1f0..18f4364856980df6 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -495,6 +495,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 009dc9da14ee5eed..2c12c020b1f2f320 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -492,6 +492,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index df8da506cde36eeb..7f28516feb9b3ce0 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2651,3 +2651,5 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 7ea1b017d05cc1fb..9776f20763a46963 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2600,6 +2600,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 99ccf354b3d1a762..96b50d0a9bd68a19 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2784,6 +2784,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 201542d1e76daa60..9b2eebfbf1b91f06 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2550,6 +2550,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 32fd72a78df65bd8..71cd35488e3b60ab 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -496,6 +496,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index d26f0ae6c2475984..ced01a501dd816a6 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2727,6 +2727,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 520ca0882d8d720b..5406c01f1de62803 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2700,3 +2700,5 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 9162c3139661b2c9..53b8ade4c3c16c9f 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2697,3 +2697,5 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 656fdbdcaa70dad6..919973ea46866c8a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2692,6 +2692,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 5f0b90d318030622..cf5a8dc1208d1f45 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2690,6 +2690,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 9f4891fc08d71521..003c3bd0a6bb0595 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2698,6 +2698,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 f1b0644bc33ba065..73629c2f21aed4a3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2601,6 +2601,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 1cf88e38b943eeb9..9e8645ebc0a996a7 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2739,3 +2739,5 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 9692335d106f9400..3d1ba9887c327899 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2754,6 +2754,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 7da0ed59f2ccb080..d979a3b93b98cc5a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2787,6 +2787,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 72cf6851988a7b91..44688e52cf99e9fc 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2509,6 +2509,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index ee7f67f4d09ba7ae..40682711eb73fb12 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2811,3 +2811,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index b8c0854508ec8714..e239d626b32e03ba 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2378,3 +2378,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 90f331fc0bc06278..ab0c4e70927d3dc0 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2578,3 +2578,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index ded5e3c0ce4da82c..74e3a4651f215344 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2752,6 +2752,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 4b262992540d18d6..e5553f06b205f0cf 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2546,6 +2546,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 8bfd716fd238a35b..9662041cd4c5df83 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2607,6 +2607,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 47fd204d84ea2432..bf90e924a671f1c1 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2604,6 +2604,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 9b82f15109ca4b1a..ddb0d0621f80426b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2747,6 +2747,8 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 94caf012a7e9cada..ca14224cb7d5740d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2573,6 +2573,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index 6b0bade4d41eafd5..601850638d538ae0 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -164,6 +164,17 @@ __spawni_child (void *arguments)
&& __setpgid (0, attr->__pgrp) != 0)
goto fail;
+ /* Set the controlling terminal. */
+ if ((attr->__flags & POSIX_SPAWN_TCSETPGROUP) != 0)
+ {
+ /* Check if it is possible to avoid an extra syscall. */
+ pid_t pgrp = (attr->__flags & POSIX_SPAWN_SETPGROUP) != 0
+ && attr->__pgrp != 0
+ ? attr->__pgrp : __getpgid (0);
+ if (__tcsetpgrp (attr->__ctty_fd, pgrp) != 0)
+ goto fail;
+ }
+
/* Set the effective user and group IDs. */
if ((attr->__flags & POSIX_SPAWN_RESETIDS) != 0
&& (local_seteuid (__getuid ()) != 0
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 140e9e8c1ce7dd37..661d928adf2ac13c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2524,6 +2524,8 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 04d13ce27e3747f5..bb8058dfa4144bbc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2630,3 +2630,5 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
+GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
+GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
diff --git a/termios/tcsetpgrp.c b/termios/tcsetpgrp.c
index 05630cd04cb5f83a..9bd94a70bc9e879f 100644
--- a/termios/tcsetpgrp.c
+++ b/termios/tcsetpgrp.c
@@ -21,7 +21,7 @@
/* Set the foreground process group ID of FD set PGRP_ID. */
int
-tcsetpgrp (int fd, pid_t pgrp_id)
+__tcsetpgrp (int fd, pid_t pgrp_id)
{
if (fd < 0)
{
@@ -32,6 +32,7 @@ tcsetpgrp (int fd, pid_t pgrp_id)
__set_errno (ENOSYS);
return -1;
}
-
+weak_alias (__tcsetpgrp, tcsetpgrp);
+libc_hidden_def (__tcsetpgrp)
stub_warning (tcsetpgrp)

963
glibc-RHEL-93320-17.patch Normal file
View File

@ -0,0 +1,963 @@
commit 6289d28d3c4e56f34830cfb011c31271ef850418
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Thu Jan 27 10:11:30 2022 -0300
posix: Replace posix_spawnattr_tc{get,set}pgrp_np with posix_spawn_file_actions_addtcsetpgrp_np
The posix_spawnattr_tcsetpgrp_np works on a file descriptor (the
controlling terminal), so it would make more sense to actually fit
it on the file actions API.
Also, POSIX_SPAWN_TCSETPGROUP is not really required since it is
implicit by the presence of tcsetpgrp file action.
The posix/tst-spawn6.c is also fixed when TTY can is not present.
Checked on x86_64-linux-gnu and i686-linux-gnu.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Conflicts:
sysdeps/mach/hurd/i386/libc.abilist
Updated for minor context changes
sysdeps/unix/sysv/linux/or1k/libc.abilist
Omitted
diff --git a/posix/Makefile b/posix/Makefile
index 8cd6963029585e3d..7b70b4a736bc1215 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -58,13 +58,13 @@ routines := \
spawn_faction_addopen spawn_faction_adddup2 spawn_valid_fd \
spawn_faction_addchdir spawn_faction_addfchdir \
spawn_faction_addclosefrom \
+ spawn_faction_addtcsetpgrp_np \
spawnattr_init spawnattr_destroy \
spawnattr_getdefault spawnattr_setdefault \
spawnattr_getflags spawnattr_setflags \
spawnattr_getpgroup spawnattr_setpgroup spawn spawnp spawni \
spawnattr_getsigmask spawnattr_getschedpolicy spawnattr_getschedparam \
spawnattr_setsigmask spawnattr_setschedpolicy spawnattr_setschedparam \
- spawnattr_tcgetpgrp spawnattr_tcsetpgrp \
posix_madvise \
get_child_max sched_cpucount sched_cpualloc sched_cpufree \
streams-compat \
diff --git a/posix/Versions b/posix/Versions
index e4f4f649b0f21e85..3753810864c8ba97 100644
--- a/posix/Versions
+++ b/posix/Versions
@@ -157,8 +157,7 @@ libc {
posix_spawn_file_actions_addclosefrom_np;
}
GLIBC_2.35 {
- posix_spawnattr_tcgetpgrp_np;
- posix_spawnattr_tcsetpgrp_np;
+ posix_spawn_file_actions_addtcsetpgrp_np;
}
GLIBC_PRIVATE {
__libc_fork; __libc_pread; __libc_pwrite;
diff --git a/posix/spawn.h b/posix/spawn.h
index 742d4cb6257907b5..7cf1a5b628480404 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -34,8 +34,7 @@ typedef struct
sigset_t __ss;
struct sched_param __sp;
int __policy;
- int __ctty_fd;
- int __pad[15];
+ int __pad[16];
} posix_spawnattr_t;
@@ -60,7 +59,6 @@ typedef struct
#ifdef __USE_GNU
# define POSIX_SPAWN_USEVFORK 0x40
# define POSIX_SPAWN_SETSID 0x80
-# define POSIX_SPAWN_TCSETPGROUP 0x100
#endif
@@ -168,19 +166,6 @@ extern int posix_spawnattr_setschedparam (posix_spawnattr_t *__restrict __attr,
__restrict __schedparam)
__THROW __nonnull ((1, 2));
-#ifdef __USE_GNU
-/* Make the spawned process the foreground process group on the terminal
- associated with FD (which must be a controlling terminal, and still be
- associated with its session). */
-extern int posix_spawnattr_tcsetpgrp_np (posix_spawnattr_t *__attr, int fd)
- __THROW __nonnull ((1));
-
-/* Return the associated terminal FD in the attribute structure. */
-extern int posix_spawnattr_tcgetpgrp_np (const posix_spawnattr_t *
- __restrict __attr, int *fd)
- __THROW __nonnull ((1, 2));
-#endif
-
/* Initialize data structure for file attribute for `spawn' call. */
extern int posix_spawn_file_actions_init (posix_spawn_file_actions_t *
__file_actions)
@@ -235,6 +220,13 @@ posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *,
int __from)
__THROW __nonnull ((1));
+/* Add an action to set the process group of the forground process group
+ associated with the terminal TCFD. */
+extern int
+posix_spawn_file_actions_addtcsetpgrp_np (posix_spawn_file_actions_t *,
+ int __tcfd)
+ __THROW __nonnull ((1));
+
#endif
__END_DECLS
diff --git a/posix/spawn_faction_addtcsetpgrp_np.c b/posix/spawn_faction_addtcsetpgrp_np.c
new file mode 100644
index 0000000000000000..86f882cd84128f99
--- /dev/null
+++ b/posix/spawn_faction_addtcsetpgrp_np.c
@@ -0,0 +1,50 @@
+/* Add tcsetpgrp to the file action list for posix_spawn.
+ Copyright (C) 2022 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <spawn.h>
+#include <unistd.h>
+#include <spawn_int.h>
+
+int
+__posix_spawn_file_actions_addtcsetpgrp_np (posix_spawn_file_actions_t
+ *file_actions, int tcfd)
+{
+ struct __spawn_action *rec;
+
+ if (!__spawn_valid_fd (tcfd))
+ return EBADF;
+
+ /* Allocate more memory if needed. */
+ if (file_actions->__used == file_actions->__allocated
+ && __posix_spawn_file_actions_realloc (file_actions) != 0)
+ /* This can only mean we ran out of memory. */
+ return ENOMEM;
+
+ /* Add the new value. */
+ rec = &file_actions->__actions[file_actions->__used];
+ rec->tag = spawn_do_tcsetpgrp;
+ rec->action.setpgrp_action.fd = tcfd;
+
+ /* Account for the new entry. */
+ ++file_actions->__used;
+
+ return 0;
+}
+weak_alias (__posix_spawn_file_actions_addtcsetpgrp_np,
+ posix_spawn_file_actions_addtcsetpgrp_np)
diff --git a/posix/spawn_faction_destroy.c b/posix/spawn_faction_destroy.c
index 1a01b8e80ec58c85..6eddfbe91705c9cb 100644
--- a/posix/spawn_faction_destroy.c
+++ b/posix/spawn_faction_destroy.c
@@ -40,6 +40,7 @@ __posix_spawn_file_actions_destroy (posix_spawn_file_actions_t *file_actions)
case spawn_do_dup2:
case spawn_do_fchdir:
case spawn_do_closefrom:
+ case spawn_do_tcsetpgrp:
/* No cleanup required. */
break;
}
diff --git a/posix/spawn_int.h b/posix/spawn_int.h
index 81d43f2fa304e08b..a80fd46c1fe899cb 100644
--- a/posix/spawn_int.h
+++ b/posix/spawn_int.h
@@ -34,6 +34,7 @@ struct __spawn_action
spawn_do_chdir,
spawn_do_fchdir,
spawn_do_closefrom,
+ spawn_do_tcsetpgrp
} tag;
union
@@ -66,6 +67,10 @@ struct __spawn_action
{
int from;
} closefrom_action;
+ struct
+ {
+ int fd;
+ } setpgrp_action;
} action;
};
diff --git a/posix/spawnattr_setflags.c b/posix/spawnattr_setflags.c
index 95f521d04d71aca2..2b033a50fc08180f 100644
--- a/posix/spawnattr_setflags.c
+++ b/posix/spawnattr_setflags.c
@@ -26,8 +26,7 @@
| POSIX_SPAWN_SETSCHEDPARAM \
| POSIX_SPAWN_SETSCHEDULER \
| POSIX_SPAWN_SETSID \
- | POSIX_SPAWN_USEVFORK \
- | POSIX_SPAWN_TCSETPGROUP)
+ | POSIX_SPAWN_USEVFORK)
/* Store flags in the attribute structure. */
int
diff --git a/posix/spawnattr_tcgetpgrp.c b/posix/spawnattr_tcgetpgrp.c
deleted file mode 100644
index 8db33e447498ce7d..0000000000000000
--- a/posix/spawnattr_tcgetpgrp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Get the controlling terminal option.
- Copyright (C) 2022 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
- <https://www.gnu.org/licenses/>. */
-
-#include <spawn.h>
-
-int
-posix_spawnattr_tcgetpgrp_np (const posix_spawnattr_t *attr, int *fd)
-{
- *fd = attr->__ctty_fd;
- return 0;
-}
diff --git a/posix/spawnattr_tcsetpgrp.c b/posix/spawnattr_tcsetpgrp.c
deleted file mode 100644
index c3b2ea2718e2a1f3..0000000000000000
--- a/posix/spawnattr_tcsetpgrp.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Set the controlling terminal option.
- Copyright (C) 2022 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
- <https://www.gnu.org/licenses/>. */
-
-#include <spawn.h>
-
-int
-posix_spawnattr_tcsetpgrp_np (posix_spawnattr_t *attr, int fd)
-{
- attr->__ctty_fd = fd;
- return 0;
-}
diff --git a/posix/tst-spawn6.c b/posix/tst-spawn6.c
index 5f95bd1938a69552..911e90a461bfc401 100644
--- a/posix/tst-spawn6.c
+++ b/posix/tst-spawn6.c
@@ -29,12 +29,11 @@
#include <support/check.h>
#include <support/xunistd.h>
#include <sys/wait.h>
+#include <stdlib.h>
static int
-handle_restart (const char *argv1)
+handle_restart (const char *argv1, const char *argv2)
{
- int fd = xopen (_PATH_TTY, O_RDONLY, 0600);
-
/* If process group is not changed (POSIX_SPAWN_SETPGROUP), then check
the creating process one, otherwise check against the process group
itself. */
@@ -50,9 +49,20 @@ handle_restart (const char *argv1)
TEST_VERIFY (pgid != pgrp);
}
- TEST_COMPARE (tcgetpgrp (fd), pgrp);
+ char *endptr;
+ long int tcfd = strtol (argv2, &endptr, 10);
+ if (*endptr != '\0' || tcfd > INT_MAX)
+ FAIL_EXIT1 ("invalid file descriptor name: %s", argv2);
+ if (tcfd != -1)
+ {
+ TEST_COMPARE (fcntl (tcfd, F_GETFD), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+ int fd = xopen (_PATH_TTY, O_RDONLY, 0600);
+ TEST_COMPARE (tcgetpgrp (fd), pgrp);
xclose (fd);
+
return 0;
}
@@ -62,6 +72,7 @@ static int restart;
static void
run_subprogram (int argc, char *argv[], const posix_spawnattr_t *attr,
+ const posix_spawn_file_actions_t *actions, int tcfd,
int exp_err)
{
short int flags;
@@ -69,7 +80,9 @@ run_subprogram (int argc, char *argv[], const posix_spawnattr_t *attr,
bool setpgrp = flags & POSIX_SPAWN_SETPGROUP;
char *spargv[9];
+ TEST_VERIFY_EXIT (((argc - 1) + 4) < array_length (spargv));
char pgrp[INT_STRLEN_BOUND (pid_t)];
+ char tcfdstr[INT_STRLEN_BOUND (int)];
int i = 0;
for (; i < argc - 1; i++)
@@ -83,11 +96,12 @@ run_subprogram (int argc, char *argv[], const posix_spawnattr_t *attr,
snprintf (pgrp, sizeof pgrp, "%d", getpgrp ());
spargv[i++] = pgrp;
}
+ snprintf (tcfdstr, sizeof tcfdstr, "%d", tcfd);
+ spargv[i++] = tcfdstr;
spargv[i] = NULL;
- TEST_VERIFY_EXIT (i < array_length (spargv));
pid_t pid;
- TEST_COMPARE (posix_spawn (&pid, argv[1], NULL, attr, spargv, environ),
+ TEST_COMPARE (posix_spawn (&pid, argv[1], actions, attr, spargv, environ),
exp_err);
if (exp_err != 0)
return;
@@ -114,44 +128,55 @@ do_test (int argc, char *argv[])
*/
if (restart)
- return handle_restart (argv[1]);
+ return handle_restart (argv[1], argv[2]);
- int tcfd = xopen (_PATH_TTY, O_RDONLY, 0600);
+ int tcfd = open64 (_PATH_TTY, O_RDONLY, 0600);
+ if (tcfd == -1)
+ {
+ if (errno == ENXIO)
+ FAIL_UNSUPPORTED ("terminal not available, skipping test");
+ FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0600): %m", _PATH_TTY, O_RDONLY);
+ }
- /* Check getters and setters. */
+ /* Check setting the controlling terminal without changing the group. */
{
posix_spawnattr_t attr;
TEST_COMPARE (posix_spawnattr_init (&attr), 0);
- TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+ posix_spawn_file_actions_t actions;
+ TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0);
+ TEST_COMPARE (posix_spawn_file_actions_addtcsetpgrp_np (&actions, tcfd),
+ 0);
- int fd;
- TEST_COMPARE (posix_spawnattr_tcgetpgrp_np (&attr, &fd), 0);
- TEST_COMPARE (tcfd, fd);
+ run_subprogram (argc, argv, &attr, &actions, -1, 0);
}
- /* Check setting the controlling terminal without changing the group. */
+ /* Check setting both the controlling terminal and the create a new process
+ group. */
{
posix_spawnattr_t attr;
TEST_COMPARE (posix_spawnattr_init (&attr), 0);
- TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP),
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETPGROUP), 0);
+ posix_spawn_file_actions_t actions;
+ TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0);
+ TEST_COMPARE (posix_spawn_file_actions_addtcsetpgrp_np (&actions, tcfd),
0);
- TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
- run_subprogram (argc, argv, &attr, 0);
+ run_subprogram (argc, argv, &attr, &actions, -1, 0);
}
- /* Check setting both the controlling terminal and the create a new process
- group. */
+ /* Same as before, but check if the addclose file actions closes the terminal
+ file descriptor. */
{
posix_spawnattr_t attr;
TEST_COMPARE (posix_spawnattr_init (&attr), 0);
- TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP
- | POSIX_SPAWN_SETPGROUP),
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETPGROUP), 0);
+ posix_spawn_file_actions_t actions;
+ TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0);
+ TEST_COMPARE (posix_spawn_file_actions_addtcsetpgrp_np (&actions, tcfd),
0);
- TEST_COMPARE (posix_spawnattr_setpgroup (&attr, 0), 0);
- TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+ TEST_COMPARE (posix_spawn_file_actions_addclose (&actions, tcfd), 0);
- run_subprogram (argc, argv, &attr, 0);
+ run_subprogram (argc, argv, &attr, &actions, tcfd, 0);
}
/* Trying to set the controlling terminal after a setsid incurs in a ENOTTY
@@ -159,11 +184,13 @@ do_test (int argc, char *argv[])
{
posix_spawnattr_t attr;
TEST_COMPARE (posix_spawnattr_init (&attr), 0);
- TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_TCSETPGROUP
- | POSIX_SPAWN_SETSID), 0);
- TEST_COMPARE (posix_spawnattr_tcsetpgrp_np (&attr, tcfd), 0);
+ TEST_COMPARE (posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSID), 0);
+ posix_spawn_file_actions_t actions;
+ TEST_COMPARE (posix_spawn_file_actions_init (&actions), 0);
+ TEST_COMPARE (posix_spawn_file_actions_addtcsetpgrp_np (&actions, tcfd),
+ 0);
- run_subprogram (argc, argv, &attr, ENOTTY);
+ run_subprogram (argc, argv, &attr, &actions, -1, ENOTTY);
}
xclose (tcfd);
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index ba6ef0924ca632cb..119fdb1c3abed349 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2287,6 +2287,7 @@ GLIBC_2.34 shm_unlink F
GLIBC_2.34 timespec_getres F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/mach/hurd/spawni.c b/sysdeps/mach/hurd/spawni.c
index 4d71181643c19b0d..f46bdd04683a30b6 100644
--- a/sysdeps/mach/hurd/spawni.c
+++ b/sysdeps/mach/hurd/spawni.c
@@ -390,19 +390,6 @@ retry:
if (!err && (flags & POSIX_SPAWN_SETPGROUP) != 0)
err = __proc_setpgrp (proc, new_pid, attrp->__pgrp);
- /* Set the controlling terminal. */
- if (!err && (flags & POSIX_SPAWN_TCSETPGROUP) != 0)
- {
- pid_t pgrp;
- /* Check if it is possible to avoid an extra syscall. */
- if ((attrp->__flags & POSIX_SPAWN_SETPGROUP) != 0 && attrp->__pgrp != 0)
- pgrp = attrp->__pgrp;
- else
- err = __proc_getpgrp (proc, new_pid, &pgrp);
- if (!err)
- err = __tcsetpgrp (attrp->__ctty_fd, pgrp);
- }
-
/* Set the effective user and group IDs. */
if (!err && (flags & POSIX_SPAWN_RESETIDS) != 0)
{
@@ -643,6 +630,19 @@ retry:
case spawn_do_closefrom:
err = do_closefrom (action->action.closefrom_action.from);
break;
+
+ case spawn_do_tcsetpgrp:
+ {
+ pid_t pgrp;
+ /* Check if it is possible to avoid an extra syscall. */
+ if ((attrp->__flags & POSIX_SPAWN_SETPGROUP)
+ != 0 && attrp->__pgrp != 0)
+ pgrp = attrp->__pgrp;
+ else
+ err = __proc_getpgrp (proc, new_pid, &pgrp);
+ if (!err)
+ err = __tcsetpgrp (action->action.setpgrp_action.fd, pgrp);
+ }
}
if (err)
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 9dd574d9e2a7b541..1b63d9e447f16862 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2615,5 +2615,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index f66704877eb43052..e7e4cf7d2afe8e37 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2712,8 +2712,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 97aa3da1ad15a459..bc3d228e3183bbff 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2376,5 +2376,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 18f4364856980df6..db7039c4aba3a2cb 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -495,8 +495,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 2c12c020b1f2f320..d2add4fb49bec9ae 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -492,8 +492,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 7f28516feb9b3ce0..355d72a30c41b668 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2651,5 +2651,4 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 9776f20763a46963..3df39bb28cc68f8a 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2600,8 +2600,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 96b50d0a9bd68a19..c4da358f80c4aae3 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2784,8 +2784,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 9b2eebfbf1b91f06..241bac70ea822230 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2550,8 +2550,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 71cd35488e3b60ab..78bf372b729a2aa5 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -496,8 +496,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _Exit F
GLIBC_2.4 _IO_2_1_stderr_ D 0x98
GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index ced01a501dd816a6..00df5c901f5a608b 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2727,8 +2727,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 5406c01f1de62803..e8118569c30bbd1e 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2700,5 +2700,4 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 53b8ade4c3c16c9f..c0d2373e64a26700 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2697,5 +2697,4 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 919973ea46866c8a..2d0fd04f54bf3495 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2692,8 +2692,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 cf5a8dc1208d1f45..e39ccfb312c61434 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2690,8 +2690,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 003c3bd0a6bb0595..1e900f86e43b49ec 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2698,8 +2698,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 73629c2f21aed4a3..9145ba79316952fd 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2601,8 +2601,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 9e8645ebc0a996a7..e95d60d92622ea38 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2739,5 +2739,4 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 3d1ba9887c327899..3820b9f23524fb40 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2754,8 +2754,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index d979a3b93b98cc5a..464dc27fcd688a94 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2787,8 +2787,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 44688e52cf99e9fc..2f7e58747fb9a6b1 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2509,8 +2509,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 40682711eb73fb12..4f3043d913781166 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2811,5 +2811,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index e239d626b32e03ba..84b6ac815a622eda 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2378,5 +2378,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index ab0c4e70927d3dc0..4d5c19c56a03175d 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2578,5 +2578,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 74e3a4651f215344..7c5ee8d56959fb35 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2752,8 +2752,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index e5553f06b205f0cf..50de0b46cf078fda 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2546,8 +2546,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 9662041cd4c5df83..66fba013caaf0200 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2607,8 +2607,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index bf90e924a671f1c1..38703f8aa039b976 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2604,8 +2604,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index ddb0d0621f80426b..6df55eb76582a397 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2747,8 +2747,7 @@ GLIBC_2.35 __epoll_pwait2_time64 F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 _IO_fprintf F
GLIBC_2.4 _IO_printf F
GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index ca14224cb7d5740d..b90569d8814c603a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2573,8 +2573,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index 601850638d538ae0..231fbef6041d15d8 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -164,17 +164,6 @@ __spawni_child (void *arguments)
&& __setpgid (0, attr->__pgrp) != 0)
goto fail;
- /* Set the controlling terminal. */
- if ((attr->__flags & POSIX_SPAWN_TCSETPGROUP) != 0)
- {
- /* Check if it is possible to avoid an extra syscall. */
- pid_t pgrp = (attr->__flags & POSIX_SPAWN_SETPGROUP) != 0
- && attr->__pgrp != 0
- ? attr->__pgrp : __getpgid (0);
- if (__tcsetpgrp (attr->__ctty_fd, pgrp) != 0)
- goto fail;
- }
-
/* Set the effective user and group IDs. */
if ((attr->__flags & POSIX_SPAWN_RESETIDS) != 0
&& (local_seteuid (__getuid ()) != 0
@@ -279,6 +268,16 @@ __spawni_child (void *arguments)
if (r != 0 && !__closefrom_fallback (lowfd, false))
goto fail;
} break;
+
+ case spawn_do_tcsetpgrp:
+ {
+ /* Check if it is possible to avoid an extra syscall. */
+ pid_t pgrp = (attr->__flags & POSIX_SPAWN_SETPGROUP) != 0
+ && attr->__pgrp != 0
+ ? attr->__pgrp : __getpgid (0);
+ if (__tcsetpgrp (action->action.setpgrp_action.fd, pgrp) != 0)
+ goto fail;
+ }
}
}
}
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 661d928adf2ac13c..e88b0f101f788eee 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2524,8 +2524,7 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F
GLIBC_2.4 __confstr_chk F
GLIBC_2.4 __fgets_chk F
GLIBC_2.4 __fgets_unlocked_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 bb8058dfa4144bbc..e0755272eb62bec3 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2630,5 +2630,4 @@ GLIBC_2.34 tss_set F
GLIBC_2.35 __memcmpeq F
GLIBC_2.35 _dl_find_object F
GLIBC_2.35 epoll_pwait2 F
-GLIBC_2.35 posix_spawnattr_tcgetpgrp_np F
-GLIBC_2.35 posix_spawnattr_tcsetpgrp_np F
+GLIBC_2.35 posix_spawn_file_actions_addtcsetpgrp_np F

36
glibc-RHEL-93320-18.patch Normal file
View File

@ -0,0 +1,36 @@
commit 2ff48a4025515e93d722947a9eabb114f4a65b22
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Nov 4 07:43:59 2022 +0100
posix: Make posix_spawn extensions available by default
Some sources merely include <spawn.h> without -D_GNU_SOURCE and expect
declarations for posix_spawn_file_actions_addchdir_np to be available.
For consistency, declare posix_spawn_file_actions_addfchdir_np,
posix_spawn_file_actions_addclosefrom_np,
posix_spawn_file_actions_addtcsetpgrp_np as well.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/posix/spawn.h b/posix/spawn.h
index 7cf1a5b628480404..81202ef0caec031c 100644
--- a/posix/spawn.h
+++ b/posix/spawn.h
@@ -198,7 +198,7 @@ extern int posix_spawn_file_actions_adddup2 (posix_spawn_file_actions_t *
int __fd, int __newfd)
__THROW __nonnull ((1));
-#ifdef __USE_GNU
+#ifdef __USE_MISC
/* Add an action changing the directory to PATH during spawn. This
affects the subsequent file actions. */
extern int posix_spawn_file_actions_addchdir_np (posix_spawn_file_actions_t *
@@ -227,7 +227,7 @@ posix_spawn_file_actions_addtcsetpgrp_np (posix_spawn_file_actions_t *,
int __tcfd)
__THROW __nonnull ((1));
-#endif
+#endif /* __USE_MISC */
__END_DECLS

185
glibc-RHEL-93320-19.patch Normal file
View File

@ -0,0 +1,185 @@
Downstream-only patch to avoid ABI change:
Move _dl_find_object and _rtld_libc_freeres to GLIBC_PRIVATE ABI
Avoid modifying rtld_global_ro as it could cause interesting issues
during glibc updates due to mismatches between running and newly
installed glibc vs. ld.so
This means _dl_find_object() will not work from a shared object
dlopen()'d from a static binary. Th the corresponding test has to
be removed. This is considered a non-issue at this point as C++
exceptions are broken in that case for other reasons already
(TLS not initialized properly etc...)
Signed-off-by: Benjamin Herrenschmidt <benh@amazon.com>
Reviewed-by: DJ Delorie <dj@redhat.com>
diff --git a/elf/Makefile b/elf/Makefile
index 7382cf6dd498ce8a..a28ea58551ffd1d7 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -62,6 +62,7 @@ dl-routines = \
dl-find_object \
dl-fini \
dl-init \
+ dl-libc_freeres \
dl-load \
dl-lookup \
dl-lookup-direct \
@@ -138,7 +139,6 @@ rtld-routines = \
dl-hwcaps \
dl-hwcaps-subdirs \
dl-hwcaps_split \
- dl-libc_freeres \
dl-minimal \
dl-mutex \
dl-sysdep \
@@ -285,7 +285,6 @@ tests-static-internal := \
tst-stackguard1-static \
tst-tls1-static \
tst-tls1-static-non-pie \
- tst-dl_find_object-static \
# tests-static-internal
CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
diff --git a/elf/Versions b/elf/Versions
index 71d648a6b4bcbf5a..3e729c92d3be282d 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -76,5 +76,11 @@ ld {
# Check if an address range within a loaded ELF object is read-only.
_dl_readonly_area;
+
+ # Called from __libc_shared to deallocate malloc'ed memory.
+ __rtld_libc_freeres;
+
+ # Implementation of _dl_find_object. The public entry point is in libc
+ __dl_find_object_internal;
}
}
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 56894ca24a510b07..99797580066cdce8 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -356,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
}
int
-_dl_find_object (void *pc1, struct dl_find_object *result)
+__dl_find_object_internal (void *pc1, struct dl_find_object *result)
{
uintptr_t pc = (uintptr_t) pc1;
@@ -463,7 +463,7 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
return -1;
} /* Transaction retry loop. */
}
-rtld_hidden_def (_dl_find_object)
+rtld_hidden_def (__dl_find_object_internal)
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
diff --git a/elf/dl-libc_freeres.c b/elf/dl-libc_freeres.c
index 2a377fa9dfc4f1c0..1acb7a87297515b0 100644
--- a/elf/dl-libc_freeres.c
+++ b/elf/dl-libc_freeres.c
@@ -24,3 +24,4 @@ __rtld_libc_freeres (void)
{
_dl_find_object_freeres ();
}
+rtld_hidden_def (__rtld_libc_freeres)
diff --git a/elf/libc-dl_find_object.c b/elf/libc-dl_find_object.c
index 38ea3bc94999df6e..1ce487ac3812d2a9 100644
--- a/elf/libc-dl_find_object.c
+++ b/elf/libc-dl_find_object.c
@@ -22,5 +22,5 @@
int
_dl_find_object (void *address, struct dl_find_object *result)
{
- return GLRO (dl_find_object) (address, result);
+ return __dl_find_object_internal (address, result);
}
diff --git a/elf/rtld.c b/elf/rtld.c
index d698a32ae120e887..667880e18ae816d8 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -381,7 +381,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_catch_error = _dl_catch_error,
._dl_error_free = _dl_error_free,
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
- ._dl_libc_freeres = __rtld_libc_freeres,
#ifdef HAVE_DL_DISCOVER_OSVERSION
._dl_discover_osversion = _dl_discover_osversion
#endif
@@ -584,10 +583,6 @@ _dl_start (void *arg)
__rtld_malloc_init_stubs ();
- /* Do not use an initializer for these members because it would
- intefere with __rtld_static_init. */
- GLRO (dl_find_object) = &_dl_find_object;
-
{
#ifdef DONT_USE_BOOTSTRAP_MAP
ElfW(Addr) entry = _dl_start_final (arg);
diff --git a/elf/rtld_static_init.c b/elf/rtld_static_init.c
index 6027000d3a56e46e..3f8abb6800b401d7 100644
--- a/elf/rtld_static_init.c
+++ b/elf/rtld_static_init.c
@@ -78,7 +78,6 @@ __rtld_static_init (struct link_map *map)
extern __typeof (dl->_dl_tls_static_size) _dl_tls_static_size
attribute_hidden;
dl->_dl_tls_static_size = _dl_tls_static_size;
- dl->_dl_find_object = _dl_find_object;
__rtld_static_init_arch (map, dl);
}
diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index 856ff7831f84d07c..2a1e8971b2df218d 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -69,7 +69,7 @@ __libc_freeres (void)
call_function_static_weak (__libc_dlerror_result_free);
#ifdef SHARED
- GLRO (dl_libc_freeres) ();
+ __rtld_libc_freeres ();
#endif
for (p = symbol_set_first_element (__libc_freeres_ptrs);
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 29c87649f14a1b5b..e5860916345487e7 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -714,14 +714,6 @@ struct rtld_global_ro
void (*_dl_error_free) (void *);
void *(*_dl_tls_get_addr_soft) (struct link_map *);
- /* Called from __libc_shared to deallocate malloc'ed memory. */
- void (*_dl_libc_freeres) (void);
-
- /* Implementation of _dl_find_object. The public entry point is in
- libc, and this is patched by __rtld_static_init to support static
- dlopen. */
- int (*_dl_find_object) (void *, struct dl_find_object *);
-
#ifdef HAVE_DL_DISCOVER_OSVERSION
int (*_dl_discover_osversion) (void);
#endif
@@ -1513,7 +1505,13 @@ __rtld_mutex_init (void)
#endif /* !PTHREAD_IN_LIBC */
/* Implementation of GL (dl_libc_freeres). */
-void __rtld_libc_freeres (void) attribute_hidden;
+void __rtld_libc_freeres (void);
+rtld_hidden_proto (__rtld_libc_freeres)
+
+/* Implementation of _dl_find_object */
+int __dl_find_object_internal (void *, struct dl_find_object *);
+rtld_hidden_proto (__dl_find_object_internal)
+
#if THREAD_GSCOPE_IN_TCB
void __thread_gscope_wait (void) attribute_hidden;

692
glibc-RHEL-93320-2.patch Normal file
View File

@ -0,0 +1,692 @@
commit 8bd336a00a5311bf7a9e99b3b0e9f01ff5faa74b
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 17 12:20:13 2021 +0100
nptl: Extract <bits/atomic_wide_counter.h> from pthread_cond_common.c
And make it an installed header. This addresses a few aliasing
violations (which do not seem to result in miscompilation due to
the use of atomics), and also enables use of wide counters in other
parts of the library.
The debug output in nptl/tst-cond22 has been adjusted to print
the 32-bit values instead because it avoids a big-endian/little-endian
difference.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
nptl/Makefile
Adapt to different overall layout
nptl/tst-cond22.c
Updated for context due to
c36fc50781995e6758cae2b6927839d0157f213c
being already backported
sysdeps/nptl/bits/thread-shared-types.h
Updated for context due to
c36fc50781995e6758cae2b6927839d0157f213c
being already backported
diff --git a/bits/atomic_wide_counter.h b/bits/atomic_wide_counter.h
new file mode 100644
index 0000000000000000..0687eb554e5051a1
--- /dev/null
+++ b/bits/atomic_wide_counter.h
@@ -0,0 +1,35 @@
+/* Monotonically increasing wide counters (at least 62 bits).
+ Copyright (C) 2016-2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _BITS_ATOMIC_WIDE_COUNTER_H
+#define _BITS_ATOMIC_WIDE_COUNTER_H
+
+/* Counter that is monotonically increasing (by less than 2**31 per
+ increment), with a single writer, and an arbitrary number of
+ readers. */
+typedef union
+{
+ __extension__ unsigned long long int __value64;
+ struct
+ {
+ unsigned int __low;
+ unsigned int __high;
+ } __value32;
+} __atomic_wide_counter;
+
+#endif /* _BITS_ATOMIC_WIDE_COUNTER_H */
diff --git a/include/atomic_wide_counter.h b/include/atomic_wide_counter.h
new file mode 100644
index 0000000000000000..31f009d5e66cb45f
--- /dev/null
+++ b/include/atomic_wide_counter.h
@@ -0,0 +1,89 @@
+/* Monotonically increasing wide counters (at least 62 bits).
+ Copyright (C) 2016-2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#ifndef _ATOMIC_WIDE_COUNTER_H
+#define _ATOMIC_WIDE_COUNTER_H
+
+#include <atomic.h>
+#include <bits/atomic_wide_counter.h>
+
+#if __HAVE_64B_ATOMICS
+
+static inline uint64_t
+__atomic_wide_counter_load_relaxed (__atomic_wide_counter *c)
+{
+ return atomic_load_relaxed (&c->__value64);
+}
+
+static inline uint64_t
+__atomic_wide_counter_fetch_add_relaxed (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ return atomic_fetch_add_relaxed (&c->__value64, val);
+}
+
+static inline uint64_t
+__atomic_wide_counter_fetch_add_acquire (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ return atomic_fetch_add_acquire (&c->__value64, val);
+}
+
+static inline void
+__atomic_wide_counter_add_relaxed (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ atomic_store_relaxed (&c->__value64,
+ atomic_load_relaxed (&c->__value64) + val);
+}
+
+static uint64_t __attribute__ ((unused))
+__atomic_wide_counter_fetch_xor_release (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ return atomic_fetch_xor_release (&c->__value64, val);
+}
+
+#else /* !__HAVE_64B_ATOMICS */
+
+uint64_t __atomic_wide_counter_load_relaxed (__atomic_wide_counter *c)
+ attribute_hidden;
+
+uint64_t __atomic_wide_counter_fetch_add_relaxed (__atomic_wide_counter *c,
+ unsigned int op)
+ attribute_hidden;
+
+static inline uint64_t
+__atomic_wide_counter_fetch_add_acquire (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ uint64_t r = __atomic_wide_counter_fetch_add_relaxed (c, val);
+ atomic_thread_fence_acquire ();
+ return r;
+}
+
+static inline void
+__atomic_wide_counter_add_relaxed (__atomic_wide_counter *c,
+ unsigned int val)
+{
+ __atomic_wide_counter_fetch_add_relaxed (c, val);
+}
+
+#endif /* !__HAVE_64B_ATOMICS */
+
+#endif /* _ATOMIC_WIDE_COUNTER_H */
diff --git a/include/bits/atomic_wide_counter.h b/include/bits/atomic_wide_counter.h
new file mode 100644
index 0000000000000000..8fb09a529104cc1d
--- /dev/null
+++ b/include/bits/atomic_wide_counter.h
@@ -0,0 +1 @@
+#include_next <bits/atomic_wide_counter.h>
diff --git a/misc/Makefile b/misc/Makefile
index 5d6fc0f6824a734f..6e8725309cf73293 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -73,7 +73,8 @@ routines := brk sbrk sstk ioctl \
fgetxattr flistxattr fremovexattr fsetxattr getxattr \
listxattr lgetxattr llistxattr lremovexattr lsetxattr \
removexattr setxattr getauxval ifunc-impl-list makedev \
- allocate_once fd_to_filename single_threaded unwind-link
+ allocate_once fd_to_filename single_threaded unwind-link \
+ atomic_wide_counter
generated += tst-error1.mtrace tst-error1-mem.out \
tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/atomic_wide_counter.c b/misc/atomic_wide_counter.c
new file mode 100644
index 0000000000000000..56d898192573193e
--- /dev/null
+++ b/misc/atomic_wide_counter.c
@@ -0,0 +1,127 @@
+/* Monotonically increasing wide counters (at least 62 bits).
+ Copyright (C) 2016-2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <atomic_wide_counter.h>
+
+#if !__HAVE_64B_ATOMICS
+
+/* Values we add or xor are less than or equal to 1<<31, so we only
+ have to make overflow-and-addition atomic wrt. to concurrent load
+ operations and xor operations. To do that, we split each counter
+ into two 32b values of which we reserve the MSB of each to
+ represent an overflow from the lower-order half to the higher-order
+ half.
+
+ In the common case, the state is (higher-order / lower-order half, and . is
+ basically concatenation of the bits):
+ 0.h / 0.l = h.l
+
+ When we add a value of x that overflows (i.e., 0.l + x == 1.L), we run the
+ following steps S1-S4 (the values these represent are on the right-hand
+ side):
+ S1: 0.h / 1.L == (h+1).L
+ S2: 1.(h+1) / 1.L == (h+1).L
+ S3: 1.(h+1) / 0.L == (h+1).L
+ S4: 0.(h+1) / 0.L == (h+1).L
+ If the LSB of the higher-order half is set, readers will ignore the
+ overflow bit in the lower-order half.
+
+ To get an atomic snapshot in load operations, we exploit that the
+ higher-order half is monotonically increasing; if we load a value V from
+ it, then read the lower-order half, and then read the higher-order half
+ again and see the same value V, we know that both halves have existed in
+ the sequence of values the full counter had. This is similar to the
+ validated reads in the time-based STMs in GCC's libitm (e.g.,
+ method_ml_wt).
+
+ One benefit of this scheme is that this makes load operations
+ obstruction-free because unlike if we would just lock the counter, readers
+ can almost always interpret a snapshot of each halves. Readers can be
+ forced to read a new snapshot when the read is concurrent with an overflow.
+ However, overflows will happen infrequently, so load operations are
+ practically lock-free. */
+
+uint64_t
+__atomic_wide_counter_fetch_add_relaxed (__atomic_wide_counter *c,
+ unsigned int op)
+{
+ /* S1. Note that this is an atomic read-modify-write so it extends the
+ release sequence of release MO store at S3. */
+ unsigned int l = atomic_fetch_add_relaxed (&c->__value32.__low, op);
+ unsigned int h = atomic_load_relaxed (&c->__value32.__high);
+ uint64_t result = ((uint64_t) h << 31) | l;
+ l += op;
+ if ((l >> 31) > 0)
+ {
+ /* Overflow. Need to increment higher-order half. Note that all
+ add operations are ordered in happens-before. */
+ h++;
+ /* S2. Release MO to synchronize with the loads of the higher-order half
+ in the load operation. See __condvar_load_64_relaxed. */
+ atomic_store_release (&c->__value32.__high,
+ h | ((unsigned int) 1 << 31));
+ l ^= (unsigned int) 1 << 31;
+ /* S3. See __condvar_load_64_relaxed. */
+ atomic_store_release (&c->__value32.__low, l);
+ /* S4. Likewise. */
+ atomic_store_release (&c->__value32.__high, h);
+ }
+ return result;
+}
+
+uint64_t
+__atomic_wide_counter_load_relaxed (__atomic_wide_counter *c)
+{
+ unsigned int h, l, h2;
+ do
+ {
+ /* This load and the second one below to the same location read from the
+ stores in the overflow handling of the add operation or the
+ initializing stores (which is a simple special case because
+ initialization always completely happens before further use).
+ Because no two stores to the higher-order half write the same value,
+ the loop ensures that if we continue to use the snapshot, this load
+ and the second one read from the same store operation. All candidate
+ store operations have release MO.
+ If we read from S2 in the first load, then we will see the value of
+ S1 on the next load (because we synchronize with S2), or a value
+ later in modification order. We correctly ignore the lower-half's
+ overflow bit in this case. If we read from S4, then we will see the
+ value of S3 in the next load (or a later value), which does not have
+ the overflow bit set anymore.
+ */
+ h = atomic_load_acquire (&c->__value32.__high);
+ /* This will read from the release sequence of S3 (i.e, either the S3
+ store or the read-modify-writes at S1 following S3 in modification
+ order). Thus, the read synchronizes with S3, and the following load
+ of the higher-order half will read from the matching S2 (or a later
+ value).
+ Thus, if we read a lower-half value here that already overflowed and
+ belongs to an increased higher-order half value, we will see the
+ latter and h and h2 will not be equal. */
+ l = atomic_load_acquire (&c->__value32.__low);
+ /* See above. */
+ h2 = atomic_load_relaxed (&c->__value32.__high);
+ }
+ while (h != h2);
+ if (((l >> 31) > 0) && ((h >> 31) > 0))
+ l ^= (unsigned int) 1 << 31;
+ return ((uint64_t) (h & ~((unsigned int) 1 << 31)) << 31) + l;
+}
+
+#endif /* !__HAVE_64B_ATOMICS */
diff --git a/nptl/Makefile b/nptl/Makefile
index cac75eb8f5b68320..80c7587f0086677b 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -22,8 +22,14 @@ subdir := nptl
include ../Makeconfig
-headers := pthread.h semaphore.h bits/semaphore.h \
- bits/struct_mutex.h bits/struct_rwlock.h
+headers := \
+ bits/atomic_wide_counter.h \
+ bits/semaphore.h \
+ bits/struct_mutex.h \
+ bits/struct_rwlock.h \
+ pthread.h \
+ semaphore.h \
+ # headers
extra-libs := libpthread
extra-libs-others := $(extra-libs)
@@ -277,7 +283,6 @@ tests = \
tst-cancel7 \
tst-cancel17 \
tst-cancel24 \
- tst-cond22 \
tst-cond26 \
tst-context1 \
tst-default-attr \
@@ -368,6 +373,7 @@ tests-container = tst-pthread-getattr
tests-internal := \
tst-barrier5 \
+ tst-cond22 \
tst-mutex8 \
tst-mutex8-static \
tst-mutexpi8 \
diff --git a/nptl/pthread_cond_common.c b/nptl/pthread_cond_common.c
index 485aca4076a372d7..9e00ebd73d4d2fba 100644
--- a/nptl/pthread_cond_common.c
+++ b/nptl/pthread_cond_common.c
@@ -17,79 +17,52 @@
<https://www.gnu.org/licenses/>. */
#include <atomic.h>
+#include <atomic_wide_counter.h>
#include <stdint.h>
#include <pthread.h>
-/* We need 3 least-significant bits on __wrefs for something else. */
+/* We need 3 least-significant bits on __wrefs for something else.
+ This also matches __atomic_wide_counter requirements: The highest
+ value we add is __PTHREAD_COND_MAX_GROUP_SIZE << 2 to __g1_start
+ (the two extra bits are for the lock in the two LSBs of
+ __g1_start). */
#define __PTHREAD_COND_MAX_GROUP_SIZE ((unsigned) 1 << 29)
-#if __HAVE_64B_ATOMICS == 1
-
-static uint64_t __attribute__ ((unused))
+static inline uint64_t
__condvar_load_wseq_relaxed (pthread_cond_t *cond)
{
- return atomic_load_relaxed (&cond->__data.__wseq);
+ return __atomic_wide_counter_load_relaxed (&cond->__data.__wseq);
}
-static uint64_t __attribute__ ((unused))
+static inline uint64_t
__condvar_fetch_add_wseq_acquire (pthread_cond_t *cond, unsigned int val)
{
- return atomic_fetch_add_acquire (&cond->__data.__wseq, val);
+ return __atomic_wide_counter_fetch_add_acquire (&cond->__data.__wseq, val);
}
-static uint64_t __attribute__ ((unused))
-__condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val)
-{
- return atomic_fetch_xor_release (&cond->__data.__wseq, val);
-}
-
-static uint64_t __attribute__ ((unused))
+static inline uint64_t
__condvar_load_g1_start_relaxed (pthread_cond_t *cond)
{
- return atomic_load_relaxed (&cond->__data.__g1_start);
+ return __atomic_wide_counter_load_relaxed (&cond->__data.__g1_start);
}
-static void __attribute__ ((unused))
+static inline void
__condvar_add_g1_start_relaxed (pthread_cond_t *cond, unsigned int val)
{
- atomic_store_relaxed (&cond->__data.__g1_start,
- atomic_load_relaxed (&cond->__data.__g1_start) + val);
+ __atomic_wide_counter_add_relaxed (&cond->__data.__g1_start, val);
}
-#else
-
-/* We use two 64b counters: __wseq and __g1_start. They are monotonically
- increasing and single-writer-multiple-readers counters, so we can implement
- load, fetch-and-add, and fetch-and-xor operations even when we just have
- 32b atomics. Values we add or xor are less than or equal to 1<<31 (*),
- so we only have to make overflow-and-addition atomic wrt. to concurrent
- load operations and xor operations. To do that, we split each counter into
- two 32b values of which we reserve the MSB of each to represent an
- overflow from the lower-order half to the higher-order half.
-
- In the common case, the state is (higher-order / lower-order half, and . is
- basically concatenation of the bits):
- 0.h / 0.l = h.l
+#if __HAVE_64B_ATOMICS == 1
- When we add a value of x that overflows (i.e., 0.l + x == 1.L), we run the
- following steps S1-S4 (the values these represent are on the right-hand
- side):
- S1: 0.h / 1.L == (h+1).L
- S2: 1.(h+1) / 1.L == (h+1).L
- S3: 1.(h+1) / 0.L == (h+1).L
- S4: 0.(h+1) / 0.L == (h+1).L
- If the LSB of the higher-order half is set, readers will ignore the
- overflow bit in the lower-order half.
+static inline uint64_t
+__condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val)
+{
+ return atomic_fetch_xor_release (&cond->__data.__wseq.__value64, val);
+}
- To get an atomic snapshot in load operations, we exploit that the
- higher-order half is monotonically increasing; if we load a value V from
- it, then read the lower-order half, and then read the higher-order half
- again and see the same value V, we know that both halves have existed in
- the sequence of values the full counter had. This is similar to the
- validated reads in the time-based STMs in GCC's libitm (e.g.,
- method_ml_wt).
+#else /* !__HAVE_64B_ATOMICS */
- The xor operation needs to be an atomic read-modify-write. The write
+/* The xor operation needs to be an atomic read-modify-write. The write
itself is not an issue as it affects just the lower-order half but not bits
used in the add operation. To make the full fetch-and-xor atomic, we
exploit that concurrently, the value can increase by at most 1<<31 (*): The
@@ -97,117 +70,18 @@ __condvar_add_g1_start_relaxed (pthread_cond_t *cond, unsigned int val)
than __PTHREAD_COND_MAX_GROUP_SIZE waiters can enter concurrently and thus
increment __wseq. Therefore, if the xor operation observes a value of
__wseq, then the value it applies the modification to later on can be
- derived (see below).
-
- One benefit of this scheme is that this makes load operations
- obstruction-free because unlike if we would just lock the counter, readers
- can almost always interpret a snapshot of each halves. Readers can be
- forced to read a new snapshot when the read is concurrent with an overflow.
- However, overflows will happen infrequently, so load operations are
- practically lock-free.
-
- (*) The highest value we add is __PTHREAD_COND_MAX_GROUP_SIZE << 2 to
- __g1_start (the two extra bits are for the lock in the two LSBs of
- __g1_start). */
-
-typedef struct
-{
- unsigned int low;
- unsigned int high;
-} _condvar_lohi;
-
-static uint64_t
-__condvar_fetch_add_64_relaxed (_condvar_lohi *lh, unsigned int op)
-{
- /* S1. Note that this is an atomic read-modify-write so it extends the
- release sequence of release MO store at S3. */
- unsigned int l = atomic_fetch_add_relaxed (&lh->low, op);
- unsigned int h = atomic_load_relaxed (&lh->high);
- uint64_t result = ((uint64_t) h << 31) | l;
- l += op;
- if ((l >> 31) > 0)
- {
- /* Overflow. Need to increment higher-order half. Note that all
- add operations are ordered in happens-before. */
- h++;
- /* S2. Release MO to synchronize with the loads of the higher-order half
- in the load operation. See __condvar_load_64_relaxed. */
- atomic_store_release (&lh->high, h | ((unsigned int) 1 << 31));
- l ^= (unsigned int) 1 << 31;
- /* S3. See __condvar_load_64_relaxed. */
- atomic_store_release (&lh->low, l);
- /* S4. Likewise. */
- atomic_store_release (&lh->high, h);
- }
- return result;
-}
-
-static uint64_t
-__condvar_load_64_relaxed (_condvar_lohi *lh)
-{
- unsigned int h, l, h2;
- do
- {
- /* This load and the second one below to the same location read from the
- stores in the overflow handling of the add operation or the
- initializing stores (which is a simple special case because
- initialization always completely happens before further use).
- Because no two stores to the higher-order half write the same value,
- the loop ensures that if we continue to use the snapshot, this load
- and the second one read from the same store operation. All candidate
- store operations have release MO.
- If we read from S2 in the first load, then we will see the value of
- S1 on the next load (because we synchronize with S2), or a value
- later in modification order. We correctly ignore the lower-half's
- overflow bit in this case. If we read from S4, then we will see the
- value of S3 in the next load (or a later value), which does not have
- the overflow bit set anymore.
- */
- h = atomic_load_acquire (&lh->high);
- /* This will read from the release sequence of S3 (i.e, either the S3
- store or the read-modify-writes at S1 following S3 in modification
- order). Thus, the read synchronizes with S3, and the following load
- of the higher-order half will read from the matching S2 (or a later
- value).
- Thus, if we read a lower-half value here that already overflowed and
- belongs to an increased higher-order half value, we will see the
- latter and h and h2 will not be equal. */
- l = atomic_load_acquire (&lh->low);
- /* See above. */
- h2 = atomic_load_relaxed (&lh->high);
- }
- while (h != h2);
- if (((l >> 31) > 0) && ((h >> 31) > 0))
- l ^= (unsigned int) 1 << 31;
- return ((uint64_t) (h & ~((unsigned int) 1 << 31)) << 31) + l;
-}
-
-static uint64_t __attribute__ ((unused))
-__condvar_load_wseq_relaxed (pthread_cond_t *cond)
-{
- return __condvar_load_64_relaxed ((_condvar_lohi *) &cond->__data.__wseq32);
-}
-
-static uint64_t __attribute__ ((unused))
-__condvar_fetch_add_wseq_acquire (pthread_cond_t *cond, unsigned int val)
-{
- uint64_t r = __condvar_fetch_add_64_relaxed
- ((_condvar_lohi *) &cond->__data.__wseq32, val);
- atomic_thread_fence_acquire ();
- return r;
-}
+ derived. */
static uint64_t __attribute__ ((unused))
__condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val)
{
- _condvar_lohi *lh = (_condvar_lohi *) &cond->__data.__wseq32;
/* First, get the current value. See __condvar_load_64_relaxed. */
unsigned int h, l, h2;
do
{
- h = atomic_load_acquire (&lh->high);
- l = atomic_load_acquire (&lh->low);
- h2 = atomic_load_relaxed (&lh->high);
+ h = atomic_load_acquire (&cond->__data.__wseq.__value32.__high);
+ l = atomic_load_acquire (&cond->__data.__wseq.__value32.__low);
+ h2 = atomic_load_relaxed (&cond->__data.__wseq.__value32.__high);
}
while (h != h2);
if (((l >> 31) > 0) && ((h >> 31) == 0))
@@ -219,8 +93,9 @@ __condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val)
earlier in modification order than the following fetch-xor.
This uses release MO to make the full operation have release semantics
(all other operations access the lower-order half). */
- unsigned int l2 = atomic_fetch_xor_release (&lh->low, val)
- & ~((unsigned int) 1 << 31);
+ unsigned int l2
+ = (atomic_fetch_xor_release (&cond->__data.__wseq.__value32.__low, val)
+ & ~((unsigned int) 1 << 31));
if (l2 < l)
/* The lower-order half overflowed in the meantime. This happened exactly
once due to the limit on concurrent waiters (see above). */
@@ -228,22 +103,7 @@ __condvar_fetch_xor_wseq_release (pthread_cond_t *cond, unsigned int val)
return ((uint64_t) h << 31) + l2;
}
-static uint64_t __attribute__ ((unused))
-__condvar_load_g1_start_relaxed (pthread_cond_t *cond)
-{
- return __condvar_load_64_relaxed
- ((_condvar_lohi *) &cond->__data.__g1_start32);
-}
-
-static void __attribute__ ((unused))
-__condvar_add_g1_start_relaxed (pthread_cond_t *cond, unsigned int val)
-{
- ignore_value (__condvar_fetch_add_64_relaxed
- ((_condvar_lohi *) &cond->__data.__g1_start32, val));
-}
-
-#endif /* !__HAVE_64B_ATOMICS */
-
+#endif /* !__HAVE_64B_ATOMICS */
/* The lock that signalers use. See pthread_cond_wait_common for uses.
The lock is our normal three-state lock: not acquired (0) / acquired (1) /
diff --git a/nptl/tst-cond22.c b/nptl/tst-cond22.c
index ebeeeaf666070076..bdcb45c53674a5fd 100644
--- a/nptl/tst-cond22.c
+++ b/nptl/tst-cond22.c
@@ -106,8 +106,11 @@ do_test (void)
status = 1;
}
- printf ("cond = { %llu, %llu, %u/%u, %u/%u, %u, %u }\n",
- c.__data.__wseq, c.__data.__g1_start,
+ printf ("cond = { 0x%x:%x, 0x%x:%x, %u/%u, %u/%u, %u, %u }\n",
+ c.__data.__wseq.__value32.__high,
+ c.__data.__wseq.__value32.__low,
+ c.__data.__g1_start.__value32.__high,
+ c.__data.__g1_start.__value32.__low,
c.__data.__g_signals[0], c.__data.__g_size[0],
c.__data.__g_signals[1], c.__data.__g_size[1],
c.__data.__g1_orig_size, c.__data.__wrefs);
@@ -149,8 +152,11 @@ do_test (void)
status = 1;
}
- printf ("cond = { %llu, %llu, %u/%u, %u/%u, %u, %u }\n",
- c.__data.__wseq, c.__data.__g1_start,
+ printf ("cond = { 0x%x:%x, 0x%x:%x, %u/%u, %u/%u, %u, %u }\n",
+ c.__data.__wseq.__value32.__high,
+ c.__data.__wseq.__value32.__low,
+ c.__data.__g1_start.__value32.__high,
+ c.__data.__g1_start.__value32.__low,
c.__data.__g_signals[0], c.__data.__g_size[0],
c.__data.__g_signals[1], c.__data.__g_size[1],
c.__data.__g1_orig_size, c.__data.__wrefs);
diff --git a/sysdeps/nptl/bits/thread-shared-types.h b/sysdeps/nptl/bits/thread-shared-types.h
index 5644472323fe5424..2143281eabc7016c 100644
--- a/sysdeps/nptl/bits/thread-shared-types.h
+++ b/sysdeps/nptl/bits/thread-shared-types.h
@@ -43,6 +43,8 @@
#include <bits/pthreadtypes-arch.h>
+#include <bits/atomic_wide_counter.h>
+
/* Common definition of pthread_mutex_t. */
@@ -91,24 +93,8 @@ typedef struct __pthread_internal_slist
struct __pthread_cond_s
{
- __extension__ union
- {
- __extension__ unsigned long long int __wseq;
- struct
- {
- unsigned int __low;
- unsigned int __high;
- } __wseq32;
- };
- __extension__ union
- {
- __extension__ unsigned long long int __g1_start;
- struct
- {
- unsigned int __low;
- unsigned int __high;
- } __g1_start32;
- };
+ __atomic_wide_counter __wseq;
+ __atomic_wide_counter __g1_start;
unsigned int __glibc_unused___g_refs[2] __LOCK_ALIGNMENT;
unsigned int __g_size[2];
unsigned int __g1_orig_size;

119
glibc-RHEL-93320-3.patch Normal file
View File

@ -0,0 +1,119 @@
commit f1d333b5bfdb3561c93feb4b5653d051c3258c59
Author: Florian Weimer <fweimer@redhat.com>
Date: Wed Nov 17 12:20:29 2021 +0100
elf: Introduce GLRO (dl_libc_freeres), called from __libc_freeres
This will be used to deallocate memory allocated using the non-minimal
malloc.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Conflicts:
elf/Makefile
Updated for change of layout
sysdeps/generic/ldsodefs.h
Updated for minor context changes
diff --git a/elf/Makefile b/elf/Makefile
index 3eac746d21042ec9..f5c9b6df9a8f9acd 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -133,6 +133,7 @@ rtld-routines = \
dl-hwcaps \
dl-hwcaps-subdirs \
dl-hwcaps_split \
+ dl-libc_freeres \
dl-minimal \
dl-mutex \
dl-sysdep \
diff --git a/elf/dl-libc_freeres.c b/elf/dl-libc_freeres.c
new file mode 100644
index 0000000000000000..68f305a6f98aac0c
--- /dev/null
+++ b/elf/dl-libc_freeres.c
@@ -0,0 +1,24 @@
+/* Deallocating malloc'ed memory from the dynamic loader.
+ Copyright (C) 2021 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
+ <https://www.gnu.org/licenses/>. */
+
+#include <ldsodefs.h>
+
+void
+__rtld_libc_freeres (void)
+{
+}
diff --git a/elf/rtld.c b/elf/rtld.c
index dac827e249b2fe14..fd70c4c3528cda2d 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -380,6 +380,7 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
._dl_catch_error = _dl_catch_error,
._dl_error_free = _dl_error_free,
._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
+ ._dl_libc_freeres = __rtld_libc_freeres,
#ifdef HAVE_DL_DISCOVER_OSVERSION
._dl_discover_osversion = _dl_discover_osversion
#endif
diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index 5c19a2725cdb61e7..856ff7831f84d07c 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -21,6 +21,7 @@
#include <libc-internal.h>
#include <unwind-link.h>
#include <dlfcn/dlerror.h>
+#include <ldsodefs.h>
#include "../nss/nsswitch.h"
#include "../libio/libioP.h"
@@ -67,6 +68,10 @@ __libc_freeres (void)
call_function_static_weak (__libc_dlerror_result_free);
+#ifdef SHARED
+ GLRO (dl_libc_freeres) ();
+#endif
+
for (p = symbol_set_first_element (__libc_freeres_ptrs);
!symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
free (*p);
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index 484893c2928db8e7..9142bc8f493bce64 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -713,6 +713,10 @@ struct rtld_global_ro
namespace. */
void (*_dl_error_free) (void *);
void *(*_dl_tls_get_addr_soft) (struct link_map *);
+
+ /* Called from __libc_shared to deallocate malloc'ed memory. */
+ void (*_dl_libc_freeres) (void);
+
#ifdef HAVE_DL_DISCOVER_OSVERSION
int (*_dl_discover_osversion) (void);
#endif
@@ -1503,6 +1507,9 @@ __rtld_mutex_init (void)
}
#endif /* !PTHREAD_IN_LIBC */
+/* Implementation of GL (dl_libc_freeres). */
+void __rtld_libc_freeres (void) attribute_hidden;
+
#if THREAD_GSCOPE_IN_TCB
void __thread_gscope_wait (void) attribute_hidden;
# define THREAD_GSCOPE_WAIT() __thread_gscope_wait ()

2764
glibc-RHEL-93320-4.patch Normal file

File diff suppressed because it is too large Load Diff

420
glibc-RHEL-93320-5.patch Normal file
View File

@ -0,0 +1,420 @@
commit acbaad31e8ea10fce8b9c0aef58afb388bf7489d
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jan 7 13:21:57 2022 +0100
elf: Fix fences in _dl_find_object_update (bug 28745)
As explained in Hans Boehm, Can Seqlocks Get Along with Programming
Language Memory Models?, an acquire fence is needed in
_dlfo_read_success. The lack of a fence resulted in an observable
bug on powerpc64le compile-time load reordering.
The fence in _dlfo_mappings_begin_update has been reordered, turning
the fence/store sequence into a release MO store equivalent.
Relaxed MO loads are used on the reader side, and relaxed MO stores
on the writer side for the shared data, to avoid formal data races.
This is just to be conservative; it should not actually be necessary
given how the data is used.
This commit also fixes the test run time. The intent was to run it
for 3 seconds, but 0.3 seconds was enough to uncover the bug very
occasionally (while 3 seconds did not reliably show the bug on every
test run).
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index 324f40742d59b4dc..b23bcaf0a15e82cd 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -17,6 +17,7 @@
<https://www.gnu.org/licenses/>. */
#include <assert.h>
+#include <atomic.h>
#include <atomic_wide_counter.h>
#include <dl-find_object.h>
#include <dlfcn.h>
@@ -80,13 +81,18 @@ static struct dl_find_object_internal *_dlfo_nodelete_mappings
over all segments, even though the data is not stored in one
contiguous array.
- During updates, the segments are overwritten in place, and a
- software transactional memory construct (involving the
+ During updates, the segments are overwritten in place. A software
+ transactional memory construct (involving the
_dlfo_loaded_mappings_version variable) is used to detect
- concurrent modification, and retry as necessary. The memory
- allocations are never deallocated, but slots used for objects that
- have been dlclose'd can be reused by dlopen. The memory can live
- in the regular C malloc heap.
+ concurrent modification, and retry as necessary. (This approach is
+ similar to seqlocks, except that two copies are used, and there is
+ only one writer, ever, due to the loader lock.) Technically,
+ relaxed MO loads and stores need to be used for the shared TM data,
+ to avoid data races.
+
+ The memory allocations are never deallocated, but slots used for
+ objects that have been dlclose'd can be reused by dlopen. The
+ memory can live in the regular C malloc heap.
The segments are populated from the start of the list, with the
mappings with the highest address. Only if this segment is full,
@@ -101,17 +107,18 @@ static struct dl_find_object_internal *_dlfo_nodelete_mappings
needed. */
struct dlfo_mappings_segment
{
- /* The previous segment has lower base addresses. */
+ /* The previous segment has lower base addresses. Constant after
+ initialization; read in the TM region. */
struct dlfo_mappings_segment *previous;
/* Used by __libc_freeres to deallocate malloc'ed memory. */
void *to_free;
/* Count of array elements in use and allocated. */
- size_t size;
+ size_t size; /* Read in the TM region. */
size_t allocated;
- struct dl_find_object_internal objects[];
+ struct dl_find_object_internal objects[]; /* Read in the TM region. */
};
/* To achieve async-signal-safety, two copies of the data structure
@@ -240,7 +247,8 @@ static inline uint64_t
_dlfo_read_start_version (void)
{
/* Acquire MO load synchronizes with the fences at the beginning and
- end of the TM update region. */
+ end of the TM update region in _dlfo_mappings_begin_update,
+ _dlfo_mappings_end_update, _dlfo_mappings_end_update_no_switch. */
return __atomic_wide_counter_load_acquire (&_dlfo_loaded_mappings_version);
}
@@ -258,34 +266,30 @@ _dlfo_read_version_locked (void)
static inline unsigned int
_dlfo_mappings_begin_update (void)
{
- unsigned int v
- = __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version,
- 2);
- /* Subsequent stores to the TM data must not be reordered before the
- store above with the version update. */
+ /* The store synchronizes with loads in _dlfo_read_start_version
+ (also called from _dlfo_read_success). */
atomic_thread_fence_release ();
- return v & 1;
+ return __atomic_wide_counter_fetch_add_relaxed
+ (&_dlfo_loaded_mappings_version, 2);
}
/* Installs the just-updated version as the active version. */
static inline void
_dlfo_mappings_end_update (void)
{
- /* The previous writes to the TM data must not be reordered after
- the version update below. */
+ /* The store synchronizes with loads in _dlfo_read_start_version
+ (also called from _dlfo_read_success). */
atomic_thread_fence_release ();
- __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version,
- 1);
+ __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version, 1);
}
/* Completes an in-place update without switching versions. */
static inline void
_dlfo_mappings_end_update_no_switch (void)
{
- /* The previous writes to the TM data must not be reordered after
- the version update below. */
+ /* The store synchronizes with loads in _dlfo_read_start_version
+ (also called from _dlfo_read_success). */
atomic_thread_fence_release ();
- __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version,
- 2);
+ __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version, 2);
}
/* Return true if the read was successful, given the start
@@ -293,6 +297,19 @@ _dlfo_mappings_end_update_no_switch (void)
static inline bool
_dlfo_read_success (uint64_t start_version)
{
+ /* See Hans Boehm, Can Seqlocks Get Along with Programming Language
+ Memory Models?, Section 4. This is necessary so that loads in
+ the TM region are not ordered past the version check below. */
+ atomic_thread_fence_acquire ();
+
+ /* Synchronizes with stores in _dlfo_mappings_begin_update,
+ _dlfo_mappings_end_update, _dlfo_mappings_end_update_no_switch.
+ It is important that all stores from the last update have been
+ visible, and stores from the next updates are not.
+
+ Unlike with seqlocks, there is no check for odd versions here
+ because we have read the unmodified copy (confirmed to be
+ unmodified by the unchanged version). */
return _dlfo_read_start_version () == start_version;
}
@@ -318,7 +335,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
{
size_t half = size >> 1;
struct dl_find_object_internal *middle = first + half;
- if (middle->map_start < pc)
+ if (atomic_load_relaxed (&middle->map_start) < pc)
{
first = middle + 1;
size -= half + 1;
@@ -327,9 +344,9 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
size = half;
}
- if (first != end && pc == first->map_start)
+ if (first != end && pc == atomic_load_relaxed (&first->map_start))
{
- if (pc < first->map_end)
+ if (pc < atomic_load_relaxed (&first->map_end))
return first;
else
/* Zero-length mapping after dlclose. */
@@ -339,7 +356,7 @@ _dlfo_lookup (uintptr_t pc, struct dl_find_object_internal *first1, size_t size)
{
/* Check to see if PC is in the previous mapping. */
--first;
- if (pc < first->map_end)
+ if (pc < atomic_load_relaxed (&first->map_end))
/* pc >= first->map_start implied by the search above. */
return first;
else
@@ -408,39 +425,47 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
size on earlier unused segments. */
for (struct dlfo_mappings_segment *seg
= _dlfo_mappings_active_segment (start_version);
- seg != NULL && seg->size > 0; seg = seg->previous)
- if (pc >= seg->objects[0].map_start)
- {
- /* PC may lie within this segment. If it is less than the
- segment start address, it can only lie in a previous
- segment, due to the base address sorting. */
- struct dl_find_object_internal *obj
- = _dlfo_lookup (pc, seg->objects, seg->size);
+ seg != NULL;
+ seg = atomic_load_acquire (&seg->previous))
+ {
+ size_t seg_size = atomic_load_relaxed (&seg->size);
+ if (seg_size == 0)
+ break;
- if (obj != NULL)
- {
- /* Found the right mapping. Copy out the data prior to
- checking if the read transaction was successful. */
- struct dl_find_object_internal copy = *obj;
- if (_dlfo_read_success (start_version))
- {
- _dl_find_object_to_external (&copy, result);
- return 0;
- }
- else
- /* Read transaction failure. */
- goto retry;
- }
- else
- {
- /* PC is not covered by this mapping. */
- if (_dlfo_read_success (start_version))
- return -1;
- else
- /* Read transaction failure. */
- goto retry;
- }
- } /* if: PC might lie within the current seg. */
+ if (pc >= atomic_load_relaxed (&seg->objects[0].map_start))
+ {
+ /* PC may lie within this segment. If it is less than the
+ segment start address, it can only lie in a previous
+ segment, due to the base address sorting. */
+ struct dl_find_object_internal *obj
+ = _dlfo_lookup (pc, seg->objects, seg_size);
+
+ if (obj != NULL)
+ {
+ /* Found the right mapping. Copy out the data prior to
+ checking if the read transaction was successful. */
+ struct dl_find_object_internal copy;
+ _dl_find_object_internal_copy (obj, &copy);
+ if (_dlfo_read_success (start_version))
+ {
+ _dl_find_object_to_external (&copy, result);
+ return 0;
+ }
+ else
+ /* Read transaction failure. */
+ goto retry;
+ }
+ else
+ {
+ /* PC is not covered by this mapping. */
+ if (_dlfo_read_success (start_version))
+ return -1;
+ else
+ /* Read transaction failure. */
+ goto retry;
+ }
+ } /* if: PC might lie within the current seg. */
+ }
/* PC is not covered by any segment. */
if (_dlfo_read_success (start_version))
@@ -619,15 +644,19 @@ static inline size_t
_dlfo_update_init_seg (struct dlfo_mappings_segment *seg,
size_t remaining_to_add)
{
+ size_t new_seg_size;
if (remaining_to_add < seg->allocated)
/* Partially filled segment. */
- seg->size = remaining_to_add;
+ new_seg_size = remaining_to_add;
else
- seg->size = seg->allocated;
- return seg->size;
+ new_seg_size = seg->allocated;
+ atomic_store_relaxed (&seg->size, new_seg_size);
+ return new_seg_size;
}
-/* Invoked from _dl_find_object_update after sorting. */
+/* Invoked from _dl_find_object_update after sorting. Stores to the
+ shared data need to use relaxed MO. But plain loads can be used
+ because the loader lock prevents concurrent stores. */
static bool
_dl_find_object_update_1 (struct link_map **loaded, size_t count)
{
@@ -727,7 +756,8 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
{
/* Prefer mapping in current_seg. */
assert (current_seg_index1 > 0);
- *dlfo = current_seg->objects[current_seg_index1 - 1];
+ _dl_find_object_internal_copy
+ (&current_seg->objects[current_seg_index1 - 1], dlfo);
--current_seg_index1;
}
else
@@ -753,7 +783,7 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
/* Prevent searching further into unused segments. */
if (target_seg->previous != NULL)
- target_seg->previous->size = 0;
+ atomic_store_relaxed (&target_seg->previous->size, 0);
_dlfo_mappings_end_update ();
return true;
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h
index f899905e09427a0d..11569efc9b7daf9c 100644
--- a/elf/dl-find_object.h
+++ b/elf/dl-find_object.h
@@ -20,6 +20,7 @@
#define _DL_FIND_EH_FRAME_H
#include <assert.h>
+#include <atomic.h>
#include <dlfcn.h>
#include <ldsodefs.h>
#include <stdbool.h>
@@ -44,6 +45,30 @@ struct dl_find_object_internal
#endif
};
+/* Create a copy of *SOURCE in *COPY using relaxed MO loads and
+ stores. */
+static inline void
+_dl_find_object_internal_copy (const struct dl_find_object_internal *source,
+ struct dl_find_object_internal *copy)
+{
+ atomic_store_relaxed (&copy->map_start,
+ atomic_load_relaxed (&source->map_start));
+ atomic_store_relaxed (&copy->map_end,
+ atomic_load_relaxed (&source->map_end));
+ atomic_store_relaxed (&copy->map,
+ atomic_load_relaxed (&source->map));
+ atomic_store_relaxed (&copy->eh_frame,
+ atomic_load_relaxed (&source->eh_frame));
+#if DLFO_STRUCT_HAS_EH_DBASE
+ atomic_store_relaxed (&copy->eh_dbase,
+ atomic_load_relaxed (&source->eh_dbase));
+#endif
+#if DLFO_STRUCT_HAS_EH_COUNT
+ atomic_store_relaxed (&copy->eh_count,
+ atomic_load_relaxed (&source->eh_count));
+#endif
+}
+
static inline void
_dl_find_object_to_external (struct dl_find_object_internal *internal,
struct dl_find_object *external)
@@ -62,34 +87,35 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
}
/* Extract the object location data from a link map and writes it to
- *RESULT. */
+ *RESULT using relaxed MO stores. */
static void __attribute__ ((unused))
_dl_find_object_from_map (struct link_map *l,
struct dl_find_object_internal *result)
{
- result->map_start = (uintptr_t) l->l_map_start;
- result->map_end = (uintptr_t) l->l_map_end;
- result->map = l;
+ atomic_store_relaxed (&result->map_start, (uintptr_t) l->l_map_start);
+ atomic_store_relaxed (&result->map_end, (uintptr_t) l->l_map_end);
+ atomic_store_relaxed (&result->map, l);
#if DLFO_STRUCT_HAS_EH_DBASE
- result->eh_dbase = (void *) l->l_info[DT_PLTGOT];
+ atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
ph < ph_end; ++ph)
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
{
- result->eh_frame = (void *) (ph->p_vaddr + l->l_addr);
+ atomic_store_relaxed (&result->eh_frame,
+ (void *) (ph->p_vaddr + l->l_addr));
#if DLFO_STRUCT_HAS_EH_COUNT
- result->eh_count = ph->p_memsz / 8;
+ atomic_store_relaxed (&result->eh_count, ph->p_memsz / 8);
#endif
return;
}
/* Object has no exception handling segment. */
- result->eh_frame = NULL;
+ atomic_store_relaxed (&result->eh_frame, NULL);
#if DLFO_STRUCT_HAS_EH_COUNT
- result->eh_count = 0;
+ atomic_store_relaxed (&result->eh_count, 0);
#endif
}
diff --git a/elf/tst-dl_find_object-threads.c b/elf/tst-dl_find_object-threads.c
index 472deeec57da0560..453ba684024b5069 100644
--- a/elf/tst-dl_find_object-threads.c
+++ b/elf/tst-dl_find_object-threads.c
@@ -138,12 +138,12 @@ check (void *address, struct dl_find_object *expected, int line)
#endif
}
-/* Request process termination after 3 seconds. */
+/* Request process termination after 0.3 seconds. */
static bool exit_requested;
static void *
exit_thread (void *ignored)
{
- usleep (3 * 100 * 1000);
+ usleep (300 * 1000);
__atomic_store_n (&exit_requested, true, __ATOMIC_RELAXED);
return NULL;
}

124
glibc-RHEL-93320-6.patch Normal file
View File

@ -0,0 +1,124 @@
commit e72ef23ee88187284b4b1ca9b2e314e618429d35
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jan 10 13:31:39 2022 +0100
elf: Simplify software TM implementation in _dl_find_object
With the current set of fences, the version update at the start
of the TM write operation is redundant, and the version update
at the end does not need to use an atomic read-modify-write
operation.
Also use relaxed MO stores during the dlclose update, and skip any
version changes there.
Suggested-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
diff --git a/elf/dl-find_object.c b/elf/dl-find_object.c
index b23bcaf0a15e82cd..2952c651ff26db04 100644
--- a/elf/dl-find_object.c
+++ b/elf/dl-find_object.c
@@ -123,9 +123,9 @@ struct dlfo_mappings_segment
/* To achieve async-signal-safety, two copies of the data structure
are used, so that a signal handler can still use this data even if
- dlopen or dlclose modify the other copy. The the MSB in
- _dlfo_loaded_mappings_version determines which array element is the
- currently active region. */
+ dlopen or dlclose modify the other copy. The the least significant
+ bit in _dlfo_loaded_mappings_version determines which array element
+ is the currently active region. */
static struct dlfo_mappings_segment *_dlfo_loaded_mappings[2];
/* Returns the number of actually used elements in all segments
@@ -248,7 +248,7 @@ _dlfo_read_start_version (void)
{
/* Acquire MO load synchronizes with the fences at the beginning and
end of the TM update region in _dlfo_mappings_begin_update,
- _dlfo_mappings_end_update, _dlfo_mappings_end_update_no_switch. */
+ _dlfo_mappings_end_update. */
return __atomic_wide_counter_load_acquire (&_dlfo_loaded_mappings_version);
}
@@ -261,35 +261,25 @@ _dlfo_read_version_locked (void)
}
/* Update the version to reflect that an update is happening. This
- does not change the bit that controls the active segment chain.
- Returns the index of the currently active segment chain. */
-static inline unsigned int
+ does not change the bit that controls the active segment chain. */
+static inline void
_dlfo_mappings_begin_update (void)
{
- /* The store synchronizes with loads in _dlfo_read_start_version
+ /* The fence synchronizes with loads in _dlfo_read_start_version
(also called from _dlfo_read_success). */
atomic_thread_fence_release ();
- return __atomic_wide_counter_fetch_add_relaxed
- (&_dlfo_loaded_mappings_version, 2);
}
/* Installs the just-updated version as the active version. */
static inline void
_dlfo_mappings_end_update (void)
{
- /* The store synchronizes with loads in _dlfo_read_start_version
+ /* The fence synchronizes with loads in _dlfo_read_start_version
(also called from _dlfo_read_success). */
atomic_thread_fence_release ();
- __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version, 1);
-}
-/* Completes an in-place update without switching versions. */
-static inline void
-_dlfo_mappings_end_update_no_switch (void)
-{
- /* The store synchronizes with loads in _dlfo_read_start_version
- (also called from _dlfo_read_success). */
- atomic_thread_fence_release ();
- __atomic_wide_counter_fetch_add_relaxed (&_dlfo_loaded_mappings_version, 2);
+ /* No atomic read-modify-write update needed because of the loader
+ lock. */
+ __atomic_wide_counter_add_relaxed (&_dlfo_loaded_mappings_version, 1);
}
/* Return true if the read was successful, given the start
@@ -302,10 +292,11 @@ _dlfo_read_success (uint64_t start_version)
the TM region are not ordered past the version check below. */
atomic_thread_fence_acquire ();
- /* Synchronizes with stores in _dlfo_mappings_begin_update,
- _dlfo_mappings_end_update, _dlfo_mappings_end_update_no_switch.
- It is important that all stores from the last update have been
- visible, and stores from the next updates are not.
+ /* Synchronizes with the fences in _dlfo_mappings_begin_update,
+ _dlfo_mappings_end_update. It is important that all stores from
+ the last update have become visible, and stores from the next
+ update to this version are not before the version number is
+ updated.
Unlike with seqlocks, there is no check for odd versions here
because we have read the unmodified copy (confirmed to be
@@ -839,17 +830,10 @@ _dl_find_object_dlclose (struct link_map *map)
issues around __libc_freeres. */
return;
- /* The update happens in-place, but given that we do not use
- atomic accesses on the read side, update the version around
- the update to trigger re-validation in concurrent
- readers. */
- _dlfo_mappings_begin_update ();
-
- /* Mark as closed. */
- obj->map_end = obj->map_start;
- obj->map = NULL;
-
- _dlfo_mappings_end_update_no_switch ();
+ /* Mark as closed. This does not change the overall data
+ structure, so no TM cycle is needed. */
+ atomic_store_relaxed (&obj->map_end, obj->map_start);
+ atomic_store_relaxed (&obj->map, NULL);
return;
}
}

353
glibc-RHEL-93320-7.patch Normal file
View File

@ -0,0 +1,353 @@
commit b4d4ff8963866367ba861681ef3b1251e122014a
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jan 17 09:57:19 2022 +0100
elf: Introduce rtld_setup_main_map
This function collects most of the processing needed to initialize
the link map for the main executable.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
Conflicts:
elf/rtld.c
Updated for minor context changes
diff --git a/elf/rtld.c b/elf/rtld.c
index b5be7674dc1dbf40..a47e105987d87add 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1129,6 +1129,163 @@ rtld_chain_load (struct link_map *main_map, char *argv0)
rtld_soname, pathname, errcode);
}
+/* Called to complete the initialization of the link map for the main
+ executable. Returns true if there is a PT_INTERP segment. */
+static bool
+rtld_setup_main_map (struct link_map *main_map)
+{
+ /* This have already been filled in right after _dl_new_object, or
+ as part of _dl_map_object. */
+ const ElfW(Phdr) *phdr = main_map->l_phdr;
+ ElfW(Word) phnum = main_map->l_phnum;
+
+ bool has_interp = false;
+
+ main_map->l_map_end = 0;
+ main_map->l_text_end = 0;
+ /* Perhaps the executable has no PT_LOAD header entries at all. */
+ main_map->l_map_start = ~0;
+ /* And it was opened directly. */
+ ++main_map->l_direct_opencount;
+
+ /* Scan the program header table for the dynamic section. */
+ for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
+ switch (ph->p_type)
+ {
+ case PT_PHDR:
+ /* Find out the load address. */
+ main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
+ break;
+ case PT_DYNAMIC:
+ /* This tells us where to find the dynamic section,
+ which tells us everything we need to do. */
+ main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+ break;
+ case PT_INTERP:
+ /* This "interpreter segment" was used by the program loader to
+ find the program interpreter, which is this program itself, the
+ dynamic linker. We note what name finds us, so that a future
+ dlopen call or DT_NEEDED entry, for something that wants to link
+ against the dynamic linker as a shared library, will know that
+ the shared object is already loaded. */
+ _dl_rtld_libname.name = ((const char *) main_map->l_addr
+ + ph->p_vaddr);
+ /* _dl_rtld_libname.next = NULL; Already zero. */
+ GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
+
+ /* Ordinarilly, we would get additional names for the loader from
+ our DT_SONAME. This can't happen if we were actually linked as
+ a static executable (detect this case when we have no DYNAMIC).
+ If so, assume the filename component of the interpreter path to
+ be our SONAME, and add it to our name list. */
+ if (GL(dl_rtld_map).l_ld == NULL)
+ {
+ const char *p = NULL;
+ const char *cp = _dl_rtld_libname.name;
+
+ /* Find the filename part of the path. */
+ while (*cp != '\0')
+ if (*cp++ == '/')
+ p = cp;
+
+ if (p != NULL)
+ {
+ _dl_rtld_libname2.name = p;
+ /* _dl_rtld_libname2.next = NULL; Already zero. */
+ _dl_rtld_libname.next = &_dl_rtld_libname2;
+ }
+ }
+
+ has_interp = true;
+ break;
+ case PT_LOAD:
+ {
+ ElfW(Addr) mapstart;
+ ElfW(Addr) allocend;
+
+ /* Remember where the main program starts in memory. */
+ mapstart = (main_map->l_addr
+ + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
+ if (main_map->l_map_start > mapstart)
+ main_map->l_map_start = mapstart;
+
+ /* Also where it ends. */
+ allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
+ if (main_map->l_map_end < allocend)
+ main_map->l_map_end = allocend;
+ if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
+ main_map->l_text_end = allocend;
+ }
+ break;
+
+ case PT_TLS:
+ if (ph->p_memsz > 0)
+ {
+ /* Note that in the case the dynamic linker we duplicate work
+ here since we read the PT_TLS entry already in
+ _dl_start_final. But the result is repeatable so do not
+ check for this special but unimportant case. */
+ main_map->l_tls_blocksize = ph->p_memsz;
+ main_map->l_tls_align = ph->p_align;
+ if (ph->p_align == 0)
+ main_map->l_tls_firstbyte_offset = 0;
+ else
+ main_map->l_tls_firstbyte_offset = (ph->p_vaddr
+ & (ph->p_align - 1));
+ main_map->l_tls_initimage_size = ph->p_filesz;
+ main_map->l_tls_initimage = (void *) ph->p_vaddr;
+
+ /* This image gets the ID one. */
+ GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
+ }
+ break;
+
+ case PT_GNU_STACK:
+ GL(dl_stack_flags) = ph->p_flags;
+ break;
+
+ case PT_GNU_RELRO:
+ main_map->l_relro_addr = ph->p_vaddr;
+ main_map->l_relro_size = ph->p_memsz;
+ break;
+ }
+ /* Process program headers again, but scan them backwards so
+ that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */
+ for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)
+ switch (ph[-1].p_type)
+ {
+ case PT_NOTE:
+ _dl_process_pt_note (main_map, -1, &ph[-1]);
+ break;
+ case PT_GNU_PROPERTY:
+ _dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
+ break;
+ }
+
+ /* Adjust the address of the TLS initialization image in case
+ the executable is actually an ET_DYN object. */
+ if (main_map->l_tls_initimage != NULL)
+ main_map->l_tls_initimage
+ = (char *) main_map->l_tls_initimage + main_map->l_addr;
+ if (! main_map->l_map_end)
+ main_map->l_map_end = ~0;
+ if (! main_map->l_text_end)
+ main_map->l_text_end = ~0;
+ if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
+ {
+ /* We were invoked directly, so the program might not have a
+ PT_INTERP. */
+ _dl_rtld_libname.name = GL(dl_rtld_map).l_name;
+ /* _dl_rtld_libname.next = NULL; Already zero. */
+ GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
+ }
+ else
+ assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
+
+ return has_interp;
+}
+
/* Adjusts the contents of the stack and related globals for the user
entry point. The ld.so processed skip_args arguments and bumped
_dl_argv and _dl_argc accordingly. Those arguments are removed from
@@ -1191,11 +1348,9 @@ dl_main (const ElfW(Phdr) *phdr,
ElfW(Addr) *user_entry,
ElfW(auxv_t) *auxv)
{
- const ElfW(Phdr) *ph;
struct link_map *main_map;
size_t file_size;
char *file;
- bool has_interp = false;
unsigned int i;
bool prelinked = false;
bool rtld_is_main = false;
@@ -1397,7 +1552,7 @@ dl_main (const ElfW(Phdr) *phdr,
load the program below unless it has a PT_GNU_STACK indicating
nonexecutable stack is ok. */
- for (ph = phdr; ph < &phdr[phnum]; ++ph)
+ for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
if (ph->p_type == PT_GNU_STACK)
{
GL(dl_stack_flags) = ph->p_flags;
@@ -1519,147 +1674,7 @@ dl_main (const ElfW(Phdr) *phdr,
information for the program. */
}
- main_map->l_map_end = 0;
- main_map->l_text_end = 0;
- /* Perhaps the executable has no PT_LOAD header entries at all. */
- main_map->l_map_start = ~0;
- /* And it was opened directly. */
- ++main_map->l_direct_opencount;
-
- /* Scan the program header table for the dynamic section. */
- for (ph = phdr; ph < &phdr[phnum]; ++ph)
- switch (ph->p_type)
- {
- case PT_PHDR:
- /* Find out the load address. */
- main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
- break;
- case PT_DYNAMIC:
- /* This tells us where to find the dynamic section,
- which tells us everything we need to do. */
- main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
- main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
- break;
- case PT_INTERP:
- /* This "interpreter segment" was used by the program loader to
- find the program interpreter, which is this program itself, the
- dynamic linker. We note what name finds us, so that a future
- dlopen call or DT_NEEDED entry, for something that wants to link
- against the dynamic linker as a shared library, will know that
- the shared object is already loaded. */
- _dl_rtld_libname.name = ((const char *) main_map->l_addr
- + ph->p_vaddr);
- /* _dl_rtld_libname.next = NULL; Already zero. */
- GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
-
- /* Ordinarilly, we would get additional names for the loader from
- our DT_SONAME. This can't happen if we were actually linked as
- a static executable (detect this case when we have no DYNAMIC).
- If so, assume the filename component of the interpreter path to
- be our SONAME, and add it to our name list. */
- if (GL(dl_rtld_map).l_ld == NULL)
- {
- const char *p = NULL;
- const char *cp = _dl_rtld_libname.name;
-
- /* Find the filename part of the path. */
- while (*cp != '\0')
- if (*cp++ == '/')
- p = cp;
-
- if (p != NULL)
- {
- _dl_rtld_libname2.name = p;
- /* _dl_rtld_libname2.next = NULL; Already zero. */
- _dl_rtld_libname.next = &_dl_rtld_libname2;
- }
- }
-
- has_interp = true;
- break;
- case PT_LOAD:
- {
- ElfW(Addr) mapstart;
- ElfW(Addr) allocend;
-
- /* Remember where the main program starts in memory. */
- mapstart = (main_map->l_addr
- + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
- if (main_map->l_map_start > mapstart)
- main_map->l_map_start = mapstart;
-
- /* Also where it ends. */
- allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
- if (main_map->l_map_end < allocend)
- main_map->l_map_end = allocend;
- if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
- main_map->l_text_end = allocend;
- }
- break;
-
- case PT_TLS:
- if (ph->p_memsz > 0)
- {
- /* Note that in the case the dynamic linker we duplicate work
- here since we read the PT_TLS entry already in
- _dl_start_final. But the result is repeatable so do not
- check for this special but unimportant case. */
- main_map->l_tls_blocksize = ph->p_memsz;
- main_map->l_tls_align = ph->p_align;
- if (ph->p_align == 0)
- main_map->l_tls_firstbyte_offset = 0;
- else
- main_map->l_tls_firstbyte_offset = (ph->p_vaddr
- & (ph->p_align - 1));
- main_map->l_tls_initimage_size = ph->p_filesz;
- main_map->l_tls_initimage = (void *) ph->p_vaddr;
-
- /* This image gets the ID one. */
- GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
- }
- break;
-
- case PT_GNU_STACK:
- GL(dl_stack_flags) = ph->p_flags;
- break;
-
- case PT_GNU_RELRO:
- main_map->l_relro_addr = ph->p_vaddr;
- main_map->l_relro_size = ph->p_memsz;
- break;
- }
- /* Process program headers again, but scan them backwards so
- that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */
- for (ph = &phdr[phnum]; ph != phdr; --ph)
- switch (ph[-1].p_type)
- {
- case PT_NOTE:
- _dl_process_pt_note (main_map, -1, &ph[-1]);
- break;
- case PT_GNU_PROPERTY:
- _dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
- break;
- }
-
- /* Adjust the address of the TLS initialization image in case
- the executable is actually an ET_DYN object. */
- if (main_map->l_tls_initimage != NULL)
- main_map->l_tls_initimage
- = (char *) main_map->l_tls_initimage + main_map->l_addr;
- if (! main_map->l_map_end)
- main_map->l_map_end = ~0;
- if (! main_map->l_text_end)
- main_map->l_text_end = ~0;
- if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
- {
- /* We were invoked directly, so the program might not have a
- PT_INTERP. */
- _dl_rtld_libname.name = GL(dl_rtld_map).l_name;
- /* _dl_rtld_libname.next = NULL; Already zero. */
- GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
- }
- else
- assert (GL(dl_rtld_map).l_libname); /* How else did we get here? */
+ bool has_interp = rtld_setup_main_map (main_map);
/* If the current libname is different from the SONAME, add the
latter as well. */

70
glibc-RHEL-93320-8.patch Normal file
View File

@ -0,0 +1,70 @@
commit 8eb2510d38226ce10a3a15109be948f052585106
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jan 17 09:57:19 2022 +0100
elf: Set l_contiguous to 1 for the main map in more cases
l_contiguous was not initialized at all for the main map and
always 0. This commit adds code to check if the LOAD segments
are adjacent to each other, and sets l_contiguous accordingly.
This helps _dl_find_object because it is more efficient if the
main mapping is contiguous.
Note that not all (PIE or non-PIE) binaries are contiguous in this
way because BFD ld creates executables with LOAD holes:
ELF LOAD segments creating holes in the process image on GNU/Linux
https://sourceware.org/pipermail/binutils/2022-January/119082.html
https://sourceware.org/bugzilla/show_bug.cgi?id=28743
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/elf/rtld.c b/elf/rtld.c
index a47e105987d87add..d698a32ae120e887 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -1147,6 +1147,22 @@ rtld_setup_main_map (struct link_map *main_map)
main_map->l_map_start = ~0;
/* And it was opened directly. */
++main_map->l_direct_opencount;
+ main_map->l_contiguous = 1;
+
+ /* A PT_LOAD segment at an unexpected address will clear the
+ l_contiguous flag. The ELF specification says that PT_LOAD
+ segments need to be sorted in in increasing order, but perhaps
+ not all executables follow this requirement. Having l_contiguous
+ equal to 1 is just an optimization, so the code below does not
+ try to sort the segments in case they are unordered.
+
+ There is one corner case in which l_contiguous is not set to 1,
+ but where it could be set: If a PIE (ET_DYN) binary is loaded by
+ glibc itself (not the kernel), it is always contiguous due to the
+ way the glibc loader works. However, the kernel loader may still
+ create holes in this case, and the code here still uses 0
+ conservatively for the glibc-loaded case, too. */
+ ElfW(Addr) expected_load_address = 0;
/* Scan the program header table for the dynamic section. */
for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
@@ -1210,12 +1226,21 @@ rtld_setup_main_map (struct link_map *main_map)
if (main_map->l_map_start > mapstart)
main_map->l_map_start = mapstart;
+ if (main_map->l_contiguous && expected_load_address != 0
+ && expected_load_address != mapstart)
+ main_map->l_contiguous = 0;
+
/* Also where it ends. */
allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
if (main_map->l_map_end < allocend)
main_map->l_map_end = allocend;
if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
main_map->l_text_end = allocend;
+
+ /* The next expected address is the page following this load
+ segment. */
+ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
+ & ~(GLRO(dl_pagesize) - 1));
}
break;

49
glibc-RHEL-93320-9.patch Normal file
View File

@ -0,0 +1,49 @@
commit 06200aac9bec34dbcac28b8c60e49a77e7851c1f
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Jan 17 09:57:19 2022 +0100
elf/tst-dl_find_object: Disable subtests for non-contiguous maps (bug 28732)
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
diff --git a/elf/tst-dl_find_object.c b/elf/tst-dl_find_object.c
index 9abffa35d479c8fc..d8c217545d116453 100644
--- a/elf/tst-dl_find_object.c
+++ b/elf/tst-dl_find_object.c
@@ -71,19 +71,24 @@ check (void *address,
__FILE__, line, address,
actual.dlfo_flags, expected->dlfo_flags);
}
- if (actual.dlfo_flags != expected->dlfo_flags)
+ if (expected->dlfo_link_map->l_contiguous)
{
- support_record_failure ();
- printf ("%s:%d: error: %p: map start is %p, expected %p\n",
- __FILE__, line,
- address, actual.dlfo_map_start, expected->dlfo_map_start);
- }
- if (actual.dlfo_map_end != expected->dlfo_map_end)
- {
- support_record_failure ();
- printf ("%s:%d: error: %p: map end is %p, expected %p\n",
- __FILE__, line,
- address, actual.dlfo_map_end, expected->dlfo_map_end);
+ /* If the mappings are not contiguous, the actual and execpted
+ mappings may differ, so this subtest will not work. */
+ if (actual.dlfo_flags != expected->dlfo_flags)
+ {
+ support_record_failure ();
+ printf ("%s:%d: error: %p: map start is %p, expected %p\n",
+ __FILE__, line,
+ address, actual.dlfo_map_start, expected->dlfo_map_start);
+ }
+ if (actual.dlfo_map_end != expected->dlfo_map_end)
+ {
+ support_record_failure ();
+ printf ("%s:%d: error: %p: map end is %p, expected %p\n",
+ __FILE__, line,
+ address, actual.dlfo_map_end, expected->dlfo_map_end);
+ }
}
if (actual.dlfo_link_map != expected->dlfo_link_map)
{

View File

@ -15,3 +15,31 @@
name = _dl_readonly_area
parameter = '0 void *
parameter = '1 size_t
# Changes in glibc-2.34-216.
[suppress_function]
symbol_name = epoll_pwait2
[suppress_function]
symbol_name = __epoll_pwait2_time64
[suppress_function]
# Use symbol name to ignore the (unexported) __-prefixed symbol as well.
symbol_name = posix_spawn_file_actions_addtcsetpgrp_np
[suppress_function]
# Use symbol_name to ignore bcmp, memcmp aliases of the new symbol.
symbol_name = __memcmpeq
[suppress_function]
symbol_name = _dl_find_object
[suppress_function]
name = __dl_find_object_internal
parameter = '0 void *
parameter = '1 dl_find_object *
[suppress_function]
name = __rtld_libc_freeres
[suppress_type]
type_kind = struct
name = link_map
has_data_member_inserted_between = {offset_of(l_tls_in_slotinfo), offset_of(l_nodelete_active)}
[suppress_type]
type_kind = struct
name = __pthread_cond_s
has_data_member = {__wseq, __wseq32, __g1_start, __g1_start32}

View File

@ -157,7 +157,7 @@ end \
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: 215%{?dist}
Release: 216%{?dist}
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@ -1302,6 +1302,25 @@ Patch992: glibc-RHEL-49549-8.patch
Patch993: glibc-RHEL-49549-9.patch
Patch994: glibc-RHEL-101986-1.patch
Patch995: glibc-RHEL-101986-2.patch
Patch996: glibc-RHEL-93320-1.patch
Patch997: glibc-RHEL-93320-2.patch
Patch998: glibc-RHEL-93320-3.patch
Patch999: glibc-RHEL-93320-4.patch
Patch1000: glibc-RHEL-93320-5.patch
Patch1001: glibc-RHEL-93320-6.patch
Patch1002: glibc-RHEL-93320-7.patch
Patch1003: glibc-RHEL-93320-8.patch
Patch1004: glibc-RHEL-93320-9.patch
Patch1005: glibc-RHEL-93320-10.patch
Patch1006: glibc-RHEL-93320-11.patch
Patch1007: glibc-RHEL-93320-12.patch
Patch1008: glibc-RHEL-93320-13.patch
Patch1009: glibc-RHEL-93320-14.patch
Patch1010: glibc-RHEL-93320-15.patch
Patch1011: glibc-RHEL-93320-16.patch
Patch1012: glibc-RHEL-93320-17.patch
Patch1013: glibc-RHEL-93320-18.patch
Patch1014: glibc-RHEL-93320-19.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -3299,6 +3318,9 @@ update_gconv_modules_cache ()
%endif
%changelog
* Mon Jul 14 2025 Benjamin Herrenschmidt <benh@amazon.com> - 2.34-216
- Backport GLIBC_2.35 libc symbols incl. _dl_find_object (RHEL-93320)
* Thu Jul 10 2025 Arjun Shankar <arjun@redhat.com> - 2.34-215
- Extend struct r_debug to support multiple namespaces (RHEL-101986)