elf: Rework exception handling in the dynamic loader (RHEL-46979)

Resolves: RHEL-46979

Note glibc-RHEL-46979-3.patch contains backport-related
ABI protection and is not an upstream commit.
This commit is contained in:
DJ Delorie 2024-08-27 23:03:38 -04:00
parent 8e284fa1e8
commit 3d4f500e5c
5 changed files with 1282 additions and 1 deletions

83
glibc-RHEL-46979-1.patch Normal file
View File

@ -0,0 +1,83 @@
From a65ff76c9a1811dd2396ab45563f645579c0e687 Mon Sep 17 00:00:00 2001
From: Florian Weimer <fweimer@redhat.com>
Date: Thu, 27 Oct 2022 11:36:44 +0200
Subject: ld.so: Export tls_init_tp_called as __rtld_tls_init_tp_called
This allows the rest of dynamic loader to check whether the TCB
has been set up (and THREAD_GETMEM and THREAD_SETMEM will work).
Reviewed-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
Conflicts:
Regenerated for context changes.
diff -rup a/elf/rtld.c b/elf/rtld.c
--- a/elf/rtld.c 2024-08-22 17:57:02.000830481 -0400
+++ b/elf/rtld.c 2024-08-22 17:59:30.666562835 -0400
@@ -740,7 +740,7 @@ match_version (const char *string, struc
return 0;
}
-static bool tls_init_tp_called;
+bool __rtld_tls_init_tp_called;
static void *
init_tls (size_t naudit)
@@ -812,7 +812,7 @@ cannot allocate TLS data structures for
if (__glibc_unlikely (lossage != NULL))
_dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
__tls_init_tp ();
- tls_init_tp_called = true;
+ __rtld_tls_init_tp_called = true;
return tcbp;
}
@@ -2057,7 +2057,7 @@ dl_main (const ElfW(Phdr) *phdr,
an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
used. Trying to do it lazily is too hairy to try when there could be
multiple threads (from a non-TLS-using libpthread). */
- bool was_tls_init_tp_called = tls_init_tp_called;
+ bool was_tls_init_tp_called = __rtld_tls_init_tp_called;
if (tcbp == NULL)
tcbp = init_tls (0);
@@ -2411,7 +2411,7 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_protect_relro (l);
/* Add object to slot information data if necessasy. */
- if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
_dl_add_to_slotinfo (l, true);
}
}
@@ -2462,7 +2462,7 @@ dl_main (const ElfW(Phdr) *phdr,
consider_profiling);
/* Add object to slot information data if necessasy. */
- if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+ if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called)
_dl_add_to_slotinfo (l, true);
}
rtld_timer_stop (&relocate_time, start);
@@ -2488,7 +2488,7 @@ dl_main (const ElfW(Phdr) *phdr,
_dl_allocate_tls_init (tcbp, true);
/* And finally install it for the main thread. */
- if (! tls_init_tp_called)
+ if (! __rtld_tls_init_tp_called)
{
const char *lossage = TLS_INIT_TP (tcbp);
if (__glibc_unlikely (lossage != NULL))
diff -rup a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
--- a/sysdeps/generic/ldsodefs.h 2024-08-22 17:57:02.011830906 -0400
+++ b/sysdeps/generic/ldsodefs.h 2024-08-22 17:58:10.900487160 -0400
@@ -1262,6 +1262,9 @@ extern void *_dl_allocate_tls_storage (v
extern void *_dl_allocate_tls_init (void *result, bool main_thread);
rtld_hidden_proto (_dl_allocate_tls_init)
+/* True if the TCB has been set up. */
+extern bool __rtld_tls_init_tp_called attribute_hidden;
+
/* Deallocate memory allocated with _dl_allocate_tls. */
extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb);
rtld_hidden_proto (_dl_deallocate_tls)

1030
glibc-RHEL-46979-2.patch Normal file

File diff suppressed because it is too large Load Diff

82
glibc-RHEL-46979-3.patch Normal file
View File

@ -0,0 +1,82 @@
Extra changes needed for backport:
* rename field "rtld_catch" to "rtld_catch_f" to avoid conflict
between "struct rtld-catch" and rtld_catch macro
* move rtld_catch into one of the unused padding fields to preserve
ABI
* Validate that the padding fields used don't overlap other fields.
diff -rup a/elf/dl-catch.c b/elf/dl-catch.c
--- a/elf/dl-catch.c 2024-09-04 16:30:02.086402568 -0400
+++ b/elf/dl-catch.c 2024-09-04 16:55:01.933440181 -0400
@@ -59,7 +59,7 @@ get_catch (void)
return rtld_catch_notls;
else
#endif
- return THREAD_GETMEM (THREAD_SELF, rtld_catch);
+ return THREAD_GETMEM (THREAD_SELF, rtld_catch_f);
}
static void
@@ -70,7 +70,7 @@ set_catch (struct rtld_catch *catch)
rtld_catch_notls = catch;
else
#endif
- THREAD_SETMEM (THREAD_SELF, rtld_catch, catch);
+ THREAD_SETMEM (THREAD_SELF, rtld_catch_f, catch);
}
/* Lossage while resolving the program's own symbols is always fatal. */
diff -rup a/nptl/descr.h b/nptl/descr.h
--- a/nptl/descr.h 2024-08-29 11:29:16.801811033 -0400
+++ b/nptl/descr.h 2024-08-29 11:48:56.547644398 -0400
@@ -164,6 +164,12 @@ struct pthread
void *__padding[24];
};
+#ifdef __x86_64__
+#define rtld_catch_f header.__padding[7]
+#else
+#define rtld_catch_f __padding[23]
+#endif
+
/* This descriptor's link on the GL (dl_stack_used) or
GL (dl_stack_user) list. */
list_t list;
@@ -396,9 +402,6 @@ struct pthread
masked.) */
sigset_t sigmask;
- /* Used by the exception handling implementation in the dynamic loader. */
- struct rtld_catch *rtld_catch;
-
/* Indicates whether is a C11 thread created by thrd_creat. */
bool c11;
@@ -432,6 +435,12 @@ struct pthread
+ sizeof ((struct pthread) {}.rseq_area))
} __attribute ((aligned (TCB_ALIGNMENT)));
+#ifdef __x86_64__
+_Static_assert (sizeof ((*(struct pthread *)0).header) > sizeof ((*(struct pthread *)0).__padding), "rtld_catch");
+#else
+_Static_assert (sizeof ((*(struct pthread *)0).header) < sizeof ((*(struct pthread *)0).__padding), "rtld_catch");
+#endif
+
static inline bool
cancel_enabled_and_canceled (int value)
{
diff -rup a/sysdeps/mach/hurd/i386/tls.h b/sysdeps/mach/hurd/i386/tls.h
--- a/sysdeps/mach/hurd/i386/tls.h 2024-08-29 11:29:16.810811382 -0400
+++ b/sysdeps/mach/hurd/i386/tls.h 2024-08-29 11:35:45.262899113 -0400
@@ -50,7 +50,7 @@ typedef struct
struct hurd_sigstate *_hurd_sigstate;
/* Used by the exception handling implementation in the dynamic loader. */
- struct rtld_catch *rtld_catch;
+ struct rtld_catch *rtld_catch_f;
} tcbhead_t;
#endif

79
glibc-RHEL-46979-4.patch Normal file
View File

@ -0,0 +1,79 @@
New test case to verify padding usage.
diff --git a/nptl/Makefile b/nptl/Makefile
index ff4d590f11c38277..9a56d34313d06444 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -319,6 +319,8 @@ tests-internal := tst-robustpi8 tst-rwlock19 tst-rwlock20 \
tst-barrier5 tst-signal7 tst-mutex8 tst-mutex8-static \
tst-mutexpi8 tst-mutexpi8-static \
tst-setgetname \
+ tst-nptl-padding \
+ # tests-internal
xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \
tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 tst-setgroups \
diff --git a/nptl/tst-nptl-padding.c b/nptl/tst-nptl-padding.c
new file mode 100644
index 0000000000000000..5bb64f4a54335e36
--- /dev/null
+++ b/nptl/tst-nptl-padding.c
@@ -0,0 +1,57 @@
+/* Downstream-only test for verifying that fields that have been
+ relocated into struct pthread padding actually use the padding.
+
+ At present, only rtld_catch (downstream: rtld_catch_f) has been
+ placed into padding. */
+
+#include <descr.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ struct pthread descr;
+
+ /* Mark the entire descriptor as used. */
+ memset (&descr, 0xff, sizeof (descr));
+
+ /* Mark the padding as unused. */
+#ifdef __x86_64__
+ /* Special case: Usable padding is in the header. */
+ memset (&descr.header.__padding, 0, sizeof (descr.header.__padding));
+#else
+ /* The padding should be directly adjacent to the first real
+ struct field. */
+ TEST_COMPARE (sizeof (descr.__padding), offsetof (struct pthread, list));
+
+ /* Clear the unused tail of the padding. */
+ {
+ char *base = (char *) &descr;
+ char *end_of_header = base + sizeof (descr.header);
+ char *end_of_padding = base + sizeof (descr.__padding);
+ memset (end_of_header, 0, end_of_padding - end_of_header);
+ }
+#endif
+
+ /* These fields are not in padding and should remain marked as used. */
+ TEST_COMPARE (descr.header.gscope_flag, -1);
+ TEST_COMPARE ((intptr_t) descr.list.next, -1);
+ TEST_COMPARE ((intptr_t) descr.list.prev, -1);
+
+ /* But this field remains in padding. */
+ TEST_COMPARE ((intptr_t) descr.rtld_catch_f, 0);
+
+ /* Write to all padding-relocated fields below to show that they
+ have independent locations. */
+ struct rtld_catch *rtld_catch_dummy = (void *) "rtld_catch_dummy";
+ descr.rtld_catch_f = rtld_catch_dummy;
+
+ TEST_VERIFY (descr.rtld_catch_f == rtld_catch_dummy);
+
+ return 0;
+}
+
+#include <support/test-driver.c>

View File

@ -157,7 +157,7 @@ end \
Summary: The GNU libc libraries
Name: glibc
Version: %{glibcversion}
Release: 124%{?dist}
Release: 125%{?dist}
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
# libraries.
@ -865,6 +865,10 @@ Patch626: glibc-RHEL-54447-7.patch
Patch627: glibc-RHEL-54447-8.patch
Patch628: glibc-RHEL-54447-9.patch
Patch629: glibc-RHEL-54447-10.patch
Patch630: glibc-RHEL-46979-1.patch
Patch631: glibc-RHEL-46979-2.patch
Patch632: glibc-RHEL-46979-3.patch
Patch633: glibc-RHEL-46979-4.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -3024,6 +3028,9 @@ update_gconv_modules_cache ()
%endif
%changelog
* Thu Sep 5 2024 DJ Delorie <dj@redhat.com> - 2.34-125
- elf: Rework exception handling in the dynamic loader (RHEL-46979)
* Thu Sep 5 2024 Siddhesh Poyarekar <siddhesh@redhat.com> - 2.34-124
- Fix ungetc leak and invalid read (RHEL-54447)