summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkash Hadke <akash.hadke@kpit.com>2021-12-24 16:12:28 +0530
committerRichard Purdie <richard.purdie@linuxfoundation.org>2022-01-22 17:56:53 +0000
commit6348d2d8a03a5763778b6b9c75bbb51423ab7bfd (patch)
tree0193e6ba3274aebd801eed9742a7d08d261dd8d0
parent7a4fa2864255cb015f7da8e6b9def25ca2de1ea1 (diff)
downloadpoky-6348d2d8a03a5763778b6b9c75bbb51423ab7bfd.tar.gz
glibc: Add fix for data races in pthread_create and TLS access
Inconsistency detected by ld.so: dl-tls.c: 493: _dl_allocate_tls_init: Assertion `listp->slotinfo[cnt].gen <= _rtld_local._dl_tls_generation' failed! caused by dlopen (in _dl_add_to_slotinfo and in dl_open_worker) doing listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1; //... if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0)) while pthread_create (in _dl_allocate_tls_init) concurrently doing assert (listp->slotinfo[cnt].gen <= GL(dl_tls_generation)); Backported below patch that can fix the following bugs with a lock that prevents DTV setup running concurrently with dlopen or dlclose. Bug 19329: https://sourceware.org/bugzilla/show_bug.cgi?id=19329 Bug 27111: https://sourceware.org/bugzilla/show_bug.cgi?id=27111 Patch: 0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=1387ad6225c2222f027790e3f460e31aa5dd2c54 It requires a supporting patch 0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=c0669ae1a629e16b536bf11cdd0865e0dbcf4bee After adding the above fix there is a number of racy read accesses to globals that will be changed to relaxed MO atomics in follow-up patch given below. This fixes the regressions and avoids cluttering the main part of the fix. 0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=f4f8f4d4e0f92488431b268c8cd9555730b9afe9 Backported the below patch to add the test to check the added fix. 0033-elf-Add-test-case-for-BZ-19329.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=9d0e30329c23b5ad736fda3f174208c25970dbce Previously modids were never resused for a different module, but after dlopen failure all gaps are reused not just the ones caused by the unfinished dlopened. The code has to handle reused modids already which seems to work, however the data races at thread creation and tls access (see bug 19329 and bug 27111) may be more severe if slots are reused. Fixing the races are not simpler if reuse is disallowed and reuse has other benefits so upstream added fix https://sourceware.org/git/?p=glibc.git;a=commit;h=572bd547d57a39b6cf0ea072545dc4048921f4c3 for the following bug. Bug 27135: https://sourceware.org/bugzilla/show_bug.cgi?id=27135 But in glibc upstream the commit 572bd547d57a was reverted as the issue with 572bd547d57a patch was the DTV entry only updated on dl_open_worker() with the update_tls_slotinfo() call after all dependencies are being processed by _dl_map_object_deps(). However _dl_map_object_deps() itself might call _dl_next_tls_modid(), and since the _dl_tls_dtv_slotinfo_list::map was not yet set the entry can be wrongly reused. So added below patch to fix Bug 27135. 0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=ba33937be210da5d07f7f01709323743f66011ce Not all TLS access related data races got fixed by adding 0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch, there are additional races at lazy tlsdesc relocations. Bug 27137: https://sourceware.org/bugzilla/show_bug.cgi?id=27137 Backported below patches to fix this issue. 0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86 0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=ddcacd91cc10ff92d6201eda87047d029c14158d The fix 0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch for bug 19329 caused a regression such that pthread_create can deadlock when concurrent ctors from dlopen are waiting for it to finish. Bug 28357: https://sourceware.org/bugzilla/show_bug.cgi?id=28357 Backported below patch to fix this issue. 0037-Avoid-deadlock-between-pthread_create-and-ctors.patch Link: https://sourceware.org/git/?p=glibc.git;a=patch;h=024a7640ab9ecea80e527f4e4d7f7a1868e952c5 (From OE-Core rev: 01f256bc72fb45c80b6a6c77506bc4c375965a3a) Signed-off-by: Akash Hadke <akash.hadke@kpit.com> Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> Signed-off-by: Steve Sakoman <steve@sakoman.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r--meta/recipes-core/glibc/glibc/0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch66
-rw-r--r--meta/recipes-core/glibc/glibc/0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch191
-rw-r--r--meta/recipes-core/glibc/glibc/0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch206
-rw-r--r--meta/recipes-core/glibc/glibc/0033-elf-Add-test-case-for-BZ-19329.patch144
-rw-r--r--meta/recipes-core/glibc/glibc/0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch180
-rw-r--r--meta/recipes-core/glibc/glibc/0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch56
-rw-r--r--meta/recipes-core/glibc/glibc/0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch124
-rw-r--r--meta/recipes-core/glibc/glibc/0037-Avoid-deadlock-between-pthread_create-and-ctors.patch276
-rw-r--r--meta/recipes-core/glibc/glibc_2.31.bb8
9 files changed, 1251 insertions, 0 deletions
diff --git a/meta/recipes-core/glibc/glibc/0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch b/meta/recipes-core/glibc/glibc/0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch
new file mode 100644
index 0000000000..dba491f4dc
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch
@@ -0,0 +1,66 @@
1From c0669ae1a629e16b536bf11cdd0865e0dbcf4bee Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Wed, 30 Dec 2020 21:52:38 +0000
4Subject: [PATCH] elf: Refactor _dl_update_slotinfo to avoid use after free
5
6map is not valid to access here because it can be freed by a concurrent
7dlclose: during tls access (via __tls_get_addr) _dl_update_slotinfo is
8called without holding dlopen locks. So don't check the modid of map.
9
10The map == 0 and map != 0 code paths can be shared (avoiding the dtv
11resize in case of map == 0 is just an optimization: larger dtv than
12necessary would be fine too).
13
14Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
15---
16 elf/dl-tls.c | 21 +++++----------------
17 1 file changed, 5 insertions(+), 16 deletions(-)
18---
19Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=c0669ae1a629e16b536bf11cdd0865e0dbcf4bee]
20Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
21Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
22---
23diff --git a/elf/dl-tls.c b/elf/dl-tls.c
24index 24d00c14ef..f8b32b3ecb 100644
25--- a/elf/dl-tls.c
26+++ b/elf/dl-tls.c
27@@ -743,6 +743,8 @@ _dl_update_slotinfo (unsigned long int req_modid)
28 {
29 for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
30 {
31+ size_t modid = total + cnt;
32+
33 size_t gen = listp->slotinfo[cnt].gen;
34
35 if (gen > new_gen)
36@@ -758,25 +760,12 @@ _dl_update_slotinfo (unsigned long int req_modid)
37
38 /* If there is no map this means the entry is empty. */
39 struct link_map *map = listp->slotinfo[cnt].map;
40- if (map == NULL)
41- {
42- if (dtv[-1].counter >= total + cnt)
43- {
44- /* If this modid was used at some point the memory
45- might still be allocated. */
46- free (dtv[total + cnt].pointer.to_free);
47- dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
48- dtv[total + cnt].pointer.to_free = NULL;
49- }
50-
51- continue;
52- }
53-
54 /* Check whether the current dtv array is large enough. */
55- size_t modid = map->l_tls_modid;
56- assert (total + cnt == modid);
57 if (dtv[-1].counter < modid)
58 {
59+ if (map == NULL)
60+ continue;
61+
62 /* Resize the dtv. */
63 dtv = _dl_resize_dtv (dtv);
64
65--
662.27.0
diff --git a/meta/recipes-core/glibc/glibc/0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch b/meta/recipes-core/glibc/glibc/0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch
new file mode 100644
index 0000000000..25beee1d50
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch
@@ -0,0 +1,191 @@
1From 1387ad6225c2222f027790e3f460e31aa5dd2c54 Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Wed, 30 Dec 2020 19:19:37 +0000
4Subject: [PATCH] elf: Fix data races in pthread_create and TLS access [BZ
5 #19329]
6
7DTV setup at thread creation (_dl_allocate_tls_init) is changed
8to take the dlopen lock, GL(dl_load_lock). Avoiding data races
9here without locks would require design changes: the map that is
10accessed for static TLS initialization here may be concurrently
11freed by dlclose. That use after free may be solved by only
12locking around static TLS setup or by ensuring dlclose does not
13free modules with static TLS, however currently every link map
14with TLS has to be accessed at least to see if it needs static
15TLS. And even if that's solved, still a lot of atomics would be
16needed to synchronize DTV related globals without a lock. So fix
17both bug 19329 and bug 27111 with a lock that prevents DTV setup
18running concurrently with dlopen or dlclose.
19
20_dl_update_slotinfo at TLS access still does not use any locks
21so CONCURRENCY NOTES are added to explain the synchronization.
22The early exit from the slotinfo walk when max_modid is reached
23is not strictly necessary, but does not hurt either.
24
25An incorrect acquire load was removed from _dl_resize_dtv: it
26did not synchronize with any release store or fence and
27synchronization is now handled separately at thread creation
28and TLS access time.
29
30There are still a number of racy read accesses to globals that
31will be changed to relaxed MO atomics in a followup patch. This
32should not introduce regressions compared to existing behaviour
33and avoid cluttering the main part of the fix.
34
35Not all TLS access related data races got fixed here: there are
36additional races at lazy tlsdesc relocations see bug 27137.
37
38Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
39---
40 elf/dl-tls.c | 63 +++++++++++++++++++++++++++++++++++++++-------------
41 1 file changed, 47 insertions(+), 16 deletions(-)
42---
43Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=1387ad6225c2222f027790e3f460e31aa5dd2c54]
44Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
45Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
46---
47diff --git a/elf/dl-tls.c b/elf/dl-tls.c
48index 6baff0c1ea..94f3cdbae0 100644
49--- a/elf/dl-tls.c
50+++ b/elf/dl-tls.c
51@@ -475,14 +475,11 @@ extern dtv_t _dl_static_dtv[];
52 #endif
53
54 static dtv_t *
55-_dl_resize_dtv (dtv_t *dtv)
56+_dl_resize_dtv (dtv_t *dtv, size_t max_modid)
57 {
58 /* Resize the dtv. */
59 dtv_t *newp;
60- /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
61- other threads concurrently. */
62- size_t newsize
63- = atomic_load_acquire (&GL(dl_tls_max_dtv_idx)) + DTV_SURPLUS;
64+ size_t newsize = max_modid + DTV_SURPLUS;
65 size_t oldsize = dtv[-1].counter;
66
67 if (dtv == GL(dl_initial_dtv))
68@@ -528,11 +525,14 @@ _dl_allocate_tls_init (void *result)
69 size_t total = 0;
70 size_t maxgen = 0;
71
72+ /* Protects global dynamic TLS related state. */
73+ __rtld_lock_lock_recursive (GL(dl_load_lock));
74+
75 /* Check if the current dtv is big enough. */
76 if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
77 {
78 /* Resize the dtv. */
79- dtv = _dl_resize_dtv (dtv);
80+ dtv = _dl_resize_dtv (dtv, GL(dl_tls_max_dtv_idx));
81
82 /* Install this new dtv in the thread data structures. */
83 INSTALL_DTV (result, &dtv[-1]);
84@@ -600,6 +600,7 @@ _dl_allocate_tls_init (void *result)
85 listp = listp->next;
86 assert (listp != NULL);
87 }
88+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
89
90 /* The DTV version is up-to-date now. */
91 dtv[0].counter = maxgen;
92@@ -734,12 +735,29 @@ _dl_update_slotinfo (unsigned long int req_modid)
93
94 if (dtv[0].counter < listp->slotinfo[idx].gen)
95 {
96- /* The generation counter for the slot is higher than what the
97- current dtv implements. We have to update the whole dtv but
98- only those entries with a generation counter <= the one for
99- the entry we need. */
100+ /* CONCURRENCY NOTES:
101+
102+ Here the dtv needs to be updated to new_gen generation count.
103+
104+ This code may be called during TLS access when GL(dl_load_lock)
105+ is not held. In that case the user code has to synchronize with
106+ dlopen and dlclose calls of relevant modules. A module m is
107+ relevant if the generation of m <= new_gen and dlclose of m is
108+ synchronized: a memory access here happens after the dlopen and
109+ before the dlclose of relevant modules. The dtv entries for
110+ relevant modules need to be updated, other entries can be
111+ arbitrary.
112+
113+ This e.g. means that the first part of the slotinfo list can be
114+ accessed race free, but the tail may be concurrently extended.
115+ Similarly relevant slotinfo entries can be read race free, but
116+ other entries are racy. However updating a non-relevant dtv
117+ entry does not affect correctness. For a relevant module m,
118+ max_modid >= modid of m. */
119 size_t new_gen = listp->slotinfo[idx].gen;
120 size_t total = 0;
121+ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
122+ assert (max_modid >= req_modid);
123
124 /* We have to look through the entire dtv slotinfo list. */
125 listp = GL(dl_tls_dtv_slotinfo_list);
126@@ -749,12 +767,14 @@ _dl_update_slotinfo (unsigned long int req_modid)
127 {
128 size_t modid = total + cnt;
129
130+ /* Later entries are not relevant. */
131+ if (modid > max_modid)
132+ break;
133+
134 size_t gen = listp->slotinfo[cnt].gen;
135
136 if (gen > new_gen)
137- /* This is a slot for a generation younger than the
138- one we are handling now. It might be incompletely
139- set up so ignore it. */
140+ /* Not relevant. */
141 continue;
142
143 /* If the entry is older than the current dtv layout we
144@@ -771,7 +791,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
145 continue;
146
147 /* Resize the dtv. */
148- dtv = _dl_resize_dtv (dtv);
149+ dtv = _dl_resize_dtv (dtv, max_modid);
150
151 assert (modid <= dtv[-1].counter);
152
153@@ -793,8 +813,17 @@ _dl_update_slotinfo (unsigned long int req_modid)
154 }
155
156 total += listp->len;
157+ if (total > max_modid)
158+ break;
159+
160+ /* Synchronize with _dl_add_to_slotinfo. Ideally this would
161+ be consume MO since we only need to order the accesses to
162+ the next node after the read of the address and on most
163+ hardware (other than alpha) a normal load would do that
164+ because of the address dependency. */
165+ listp = atomic_load_acquire (&listp->next);
166 }
167- while ((listp = listp->next) != NULL);
168+ while (listp != NULL);
169
170 /* This will be the new maximum generation counter. */
171 dtv[0].counter = new_gen;
172@@ -986,7 +1015,7 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
173 the first slot. */
174 assert (idx == 0);
175
176- listp = prevp->next = (struct dtv_slotinfo_list *)
177+ listp = (struct dtv_slotinfo_list *)
178 malloc (sizeof (struct dtv_slotinfo_list)
179 + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
180 if (listp == NULL)
181@@ -1000,6 +1029,8 @@ cannot create TLS data structures"));
182 listp->next = NULL;
183 memset (listp->slotinfo, '\0',
184 TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
185+ /* Synchronize with _dl_update_slotinfo. */
186+ atomic_store_release (&prevp->next, listp);
187 }
188
189 /* Add the information into the slotinfo data structure. */
190--
1912.27.0
diff --git a/meta/recipes-core/glibc/glibc/0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch b/meta/recipes-core/glibc/glibc/0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch
new file mode 100644
index 0000000000..eb8ef3161c
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch
@@ -0,0 +1,206 @@
1From f4f8f4d4e0f92488431b268c8cd9555730b9afe9 Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Wed, 30 Dec 2020 19:19:37 +0000
4Subject: [PATCH] elf: Use relaxed atomics for racy accesses [BZ #19329]
5
6This is a follow up patch to the fix for bug 19329. This adds relaxed
7MO atomics to accesses that were previously data races but are now
8race conditions, and where relaxed MO is sufficient.
9
10The race conditions all follow the pattern that the write is behind the
11dlopen lock, but a read can happen concurrently (e.g. during tls access)
12without holding the lock. For slotinfo entries the read value only
13matters if it reads from a synchronized write in dlopen or dlclose,
14otherwise the related dtv entry is not valid to access so it is fine
15to leave it in an inconsistent state. The same applies for
16GL(dl_tls_max_dtv_idx) and GL(dl_tls_generation), but there the
17algorithm relies on the fact that the read of the last synchronized
18write is an increasing value.
19
20Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
21---
22 elf/dl-close.c | 20 +++++++++++++-------
23 elf/dl-open.c | 5 ++++-
24 elf/dl-tls.c | 31 +++++++++++++++++++++++--------
25 sysdeps/x86_64/dl-tls.c | 3 ++-
26 4 files changed, 42 insertions(+), 17 deletions(-)
27---
28Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=f4f8f4d4e0f92488431b268c8cd9555730b9afe9]
29Comment: Hunks from elf/dl-open.c and elf/dl-tls.c are refreshed due to offset change.
30Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
31Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
32---
33diff --git a/elf/dl-close.c b/elf/dl-close.c
34index c51becd06b..3720e47dd1 100644
35--- a/elf/dl-close.c
36+++ b/elf/dl-close.c
37@@ -79,9 +79,10 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
38 {
39 assert (old_map->l_tls_modid == idx);
40
41- /* Mark the entry as unused. */
42- listp->slotinfo[idx - disp].gen = GL(dl_tls_generation) + 1;
43- listp->slotinfo[idx - disp].map = NULL;
44+ /* Mark the entry as unused. These can be read concurrently. */
45+ atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
46+ GL(dl_tls_generation) + 1);
47+ atomic_store_relaxed (&listp->slotinfo[idx - disp].map, NULL);
48 }
49
50 /* If this is not the last currently used entry no need to look
51@@ -96,8 +97,8 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
52
53 if (listp->slotinfo[idx - disp].map != NULL)
54 {
55- /* Found a new last used index. */
56- GL(dl_tls_max_dtv_idx) = idx;
57+ /* Found a new last used index. This can be read concurrently. */
58+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), idx);
59 return true;
60 }
61 }
62@@ -571,7 +572,9 @@ _dl_close_worker (struct link_map *map, bool force)
63 GL(dl_tls_dtv_slotinfo_list), 0,
64 imap->l_init_called))
65 /* All dynamically loaded modules with TLS are unloaded. */
66- GL(dl_tls_max_dtv_idx) = GL(dl_tls_static_nelem);
67+ /* Can be read concurrently. */
68+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx),
69+ GL(dl_tls_static_nelem));
70
71 if (imap->l_tls_offset != NO_TLS_OFFSET
72 && imap->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)
73@@ -769,8 +772,11 @@ _dl_close_worker (struct link_map *map, bool force)
74 /* If we removed any object which uses TLS bump the generation counter. */
75 if (any_tls)
76 {
77- if (__glibc_unlikely (++GL(dl_tls_generation) == 0))
78+ size_t newgen = GL(dl_tls_generation) + 1;
79+ if (__glibc_unlikely (newgen == 0))
80 _dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n");
81+ /* Can be read concurrently. */
82+ atomic_store_relaxed (&GL(dl_tls_generation), newgen);
83
84 if (tls_free_end == GL(dl_tls_static_used))
85 GL(dl_tls_static_used) = tls_free_start;
86diff --git a/elf/dl-open.c b/elf/dl-open.c
87index 09f0df7d38..bb79ef00f1 100644
88--- a/elf/dl-open.c
89+++ b/elf/dl-open.c
90@@ -387,9 +387,12 @@
91 }
92 }
93
94- if (__builtin_expect (++GL(dl_tls_generation) == 0, 0))
95+ size_t newgen = GL(dl_tls_generation) + 1;
96+ if (__glibc_unlikely (newgen == 0))
97 _dl_fatal_printf (N_("\
98 TLS generation counter wrapped! Please report this."));
99+ /* Can be read concurrently. */
100+ atomic_store_relaxed (&GL(dl_tls_generation), newgen);
101
102 /* We need a second pass for static tls data, because
103 _dl_update_slotinfo must not be run while calls to
104diff --git a/elf/dl-tls.c b/elf/dl-tls.c
105index 94f3cdbae0..dc69cd984e 100644
106--- a/elf/dl-tls.c
107+++ b/elf/dl-tls.c
108@@ -96,7 +96,9 @@
109 /* No gaps, allocate a new entry. */
110 nogaps:
111
112- result = ++GL(dl_tls_max_dtv_idx);
113+ result = GL(dl_tls_max_dtv_idx) + 1;
114+ /* Can be read concurrently. */
115+ atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result);
116 }
117
118 return result;
119@@ -279,10 +281,12 @@
120 dtv_t *dtv;
121 size_t dtv_length;
122
123+ /* Relaxed MO, because the dtv size is later rechecked, not relied on. */
124+ size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
125 /* We allocate a few more elements in the dtv than are needed for the
126 initial set of modules. This should avoid in most cases expansions
127 of the dtv. */
128- dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
129+ dtv_length = max_modid + DTV_SURPLUS;
130 dtv = calloc (dtv_length + 2, sizeof (dtv_t));
131 if (dtv != NULL)
132 {
133@@ -687,7 +691,7 @@
134 if (modid > max_modid)
135 break;
136
137- size_t gen = listp->slotinfo[cnt].gen;
138+ size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
139
140 if (gen > new_gen)
141 /* Not relevant. */
142@@ -699,7 +703,8 @@
143 continue;
144
145 /* If there is no map this means the entry is empty. */
146- struct link_map *map = listp->slotinfo[cnt].map;
147+ struct link_map *map
148+ = atomic_load_relaxed (&listp->slotinfo[cnt].map);
149 /* Check whether the current dtv array is large enough. */
150 if (dtv[-1].counter < modid)
151 {
152@@ -843,7 +848,12 @@
153 {
154 dtv_t *dtv = THREAD_DTV ();
155
156- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
157+ /* Update is needed if dtv[0].counter < the generation of the accessed
158+ module. The global generation counter is used here as it is easier
159+ to check. Synchronization for the relaxed MO access is guaranteed
160+ by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */
161+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
162+ if (__glibc_unlikely (dtv[0].counter != gen))
163 return update_get_addr (GET_ADDR_PARAM);
164
165 void *p = dtv[GET_ADDR_MODULE].pointer.val;
166@@ -866,7 +876,10 @@
167 return NULL;
168
169 dtv_t *dtv = THREAD_DTV ();
170- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
171+ /* This may be called without holding the GL(dl_load_lock). Reading
172+ arbitrary gen value is fine since this is best effort code. */
173+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
174+ if (__glibc_unlikely (dtv[0].counter != gen))
175 {
176 /* This thread's DTV is not completely current,
177 but it might already cover this module. */
178@@ -961,7 +974,9 @@
179 /* Add the information into the slotinfo data structure. */
180 if (do_add)
181 {
182- listp->slotinfo[idx].map = l;
183- listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
184+ /* Can be read concurrently. See _dl_update_slotinfo. */
185+ atomic_store_relaxed (&listp->slotinfo[idx].map, l);
186+ atomic_store_relaxed (&listp->slotinfo[idx].gen,
187+ GL(dl_tls_generation) + 1);
188 }
189 }
190
191diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
192index 6595f6615b..24ef560b71 100644
193--- a/sysdeps/x86_64/dl-tls.c
194+++ b/sysdeps/x86_64/dl-tls.c
195@@ -40,7 +40,8 @@ __tls_get_addr_slow (GET_ADDR_ARGS)
196 {
197 dtv_t *dtv = THREAD_DTV ();
198
199- if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation)))
200+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
201+ if (__glibc_unlikely (dtv[0].counter != gen))
202 return update_get_addr (GET_ADDR_PARAM);
203
204 return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL);
205--
2062.27.0
diff --git a/meta/recipes-core/glibc/glibc/0033-elf-Add-test-case-for-BZ-19329.patch b/meta/recipes-core/glibc/glibc/0033-elf-Add-test-case-for-BZ-19329.patch
new file mode 100644
index 0000000000..f22e52ea99
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0033-elf-Add-test-case-for-BZ-19329.patch
@@ -0,0 +1,144 @@
1From 9d0e30329c23b5ad736fda3f174208c25970dbce Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Tue, 13 Dec 2016 12:28:41 +0000
4Subject: [PATCH] elf: Add test case for [BZ #19329]
5
6Test concurrent dlopen and pthread_create when the loaded modules have
7TLS. This triggers dl-tls assertion failures more reliably than the
8nptl/tst-stack4 test.
9
10The dlopened module has 100 DT_NEEDED dependencies with TLS, they were
11reused from an existing TLS test. The number of created threads during
12dlopen depends on filesystem speed and hardware, but at most 3 threads
13are alive at a time to limit resource usage.
14
15Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
16---
17 elf/Makefile | 9 ++++--
18 elf/tst-tls21.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++
19 elf/tst-tls21mod.c | 1 +
20 3 files changed, 76 insertions(+), 2 deletions(-)
21 create mode 100644 elf/tst-tls21.c
22 create mode 100644 elf/tst-tls21mod.c
23---
24Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=9d0e30329c23b5ad736fda3f174208c25970dbce]
25Comment: Hunks from elf/Makefile are refreshed as per glibc 2.31 codebase.
26Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
27Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
28---
29diff --git a/elf/Makefile b/elf/Makefile
30index d3e909637a..3241cb6046 100644
31--- a/elf/Makefile
32+++ b/elf/Makefile
33@@ -201,7 +201,7 @@
34 tst-unwind-ctor tst-unwind-main tst-audit13 \
35 tst-sonamemove-link tst-sonamemove-dlopen tst-dlopen-tlsmodid \
36 tst-dlopen-self tst-auditmany tst-initfinilazyfail tst-dlopenfail \
37- tst-dlopenfail-2
38+ tst-dlopenfail-2 tst-tls21
39 # reldep9
40 tests-internal += loadtest unload unload2 circleload1 \
41 neededtest neededtest2 neededtest3 neededtest4 \
42@@ -312,7 +312,7 @@
43 tst-auditmanymod7 tst-auditmanymod8 tst-auditmanymod9 \
44 tst-initlazyfailmod tst-finilazyfailmod \
45 tst-dlopenfailmod1 tst-dlopenfaillinkmod tst-dlopenfailmod2 \
46- tst-dlopenfailmod3 tst-ldconfig-ld-mod
47+ tst-dlopenfailmod3 tst-ldconfig-ld-mod tst-tls21mod
48 # Most modules build with _ISOMAC defined, but those filtered out
49 # depend on internal headers.
50 modules-names-tests = $(filter-out ifuncmod% tst-libc_dlvsym-dso tst-tlsmod%,\
51@@ -1697,5 +1697,10 @@
52 $(objpfx)tst-dlopen-nodelete-reloc-mod16.so
53 LDFLAGS-tst-dlopen-nodelete-reloc-mod17.so = -Wl,--no-as-needed
54
55+# Reuses tst-tls-many-dynamic-modules
56+$(objpfx)tst-tls21: $(libdl) $(shared-thread-library)
57+$(objpfx)tst-tls21.out: $(objpfx)tst-tls21mod.so
58+$(objpfx)tst-tls21mod.so: $(tst-tls-many-dynamic-modules:%=$(objpfx)%.so)
59+
60 $(objpfx)tst-ldconfig-ld_so_conf-update.out: $(objpfx)tst-ldconfig-ld-mod.so
61 $(objpfx)tst-ldconfig-ld_so_conf-update: $(libdl)
62diff --git a/elf/tst-tls21.c b/elf/tst-tls21.c
63new file mode 100644
64index 0000000000..560bf5813a
65--- /dev/null
66+++ b/elf/tst-tls21.c
67@@ -0,0 +1,68 @@
68+/* Test concurrent dlopen and pthread_create: BZ 19329.
69+ Copyright (C) 2021 Free Software Foundation, Inc.
70+ This file is part of the GNU C Library.
71+
72+ The GNU C Library is free software; you can redistribute it and/or
73+ modify it under the terms of the GNU Lesser General Public
74+ License as published by the Free Software Foundation; either
75+ version 2.1 of the License, or (at your option) any later version.
76+
77+ The GNU C Library is distributed in the hope that it will be useful,
78+ but WITHOUT ANY WARRANTY; without even the implied warranty of
79+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
80+ Lesser General Public License for more details.
81+
82+ You should have received a copy of the GNU Lesser General Public
83+ License along with the GNU C Library; if not, see
84+ <http://www.gnu.org/licenses/>. */
85+
86+#include <dlfcn.h>
87+#include <pthread.h>
88+#include <stdio.h>
89+#include <stdatomic.h>
90+#include <support/xdlfcn.h>
91+#include <support/xthread.h>
92+
93+#define THREADS 10000
94+
95+static atomic_int done;
96+
97+static void *
98+start (void *a)
99+{
100+ /* Load a module with many dependencies that each have TLS. */
101+ xdlopen ("tst-tls21mod.so", RTLD_LAZY);
102+ atomic_store_explicit (&done, 1, memory_order_release);
103+ return 0;
104+}
105+
106+static void *
107+nop (void *a)
108+{
109+ return 0;
110+}
111+
112+static int
113+do_test (void)
114+{
115+ pthread_t t1, t2;
116+ int i;
117+
118+ /* Load a module with lots of dependencies and TLS. */
119+ t1 = xpthread_create (0, start, 0);
120+
121+ /* Concurrently create lots of threads until dlopen is observably done. */
122+ for (i = 0; i < THREADS; i++)
123+ {
124+ if (atomic_load_explicit (&done, memory_order_acquire) != 0)
125+ break;
126+ t2 = xpthread_create (0, nop, 0);
127+ xpthread_join (t2);
128+ }
129+
130+ xpthread_join (t1);
131+ printf ("threads created during dlopen: %d\n", i);
132+ return 0;
133+}
134+
135+#include <support/test-driver.c>
136diff --git a/elf/tst-tls21mod.c b/elf/tst-tls21mod.c
137new file mode 100644
138index 0000000000..206ece4fb3
139--- /dev/null
140+++ b/elf/tst-tls21mod.c
141@@ -0,0 +1 @@
142+int __thread x;
143--
1442.27.0
diff --git a/meta/recipes-core/glibc/glibc/0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch b/meta/recipes-core/glibc/glibc/0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch
new file mode 100644
index 0000000000..a87afe3230
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch
@@ -0,0 +1,180 @@
1From ba33937be210da5d07f7f01709323743f66011ce Mon Sep 17 00:00:00 2001
2From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
3Date: Fri, 25 Jun 2021 10:54:12 -0300
4Subject: [PATCH] elf: Fix DTV gap reuse logic (BZ #27135)
5
6This is updated version of the 572bd547d57a (reverted by 40ebfd016ad2)
7that fixes the _dl_next_tls_modid issues.
8
9This issue with 572bd547d57a patch is the DTV entry will be only
10update on dl_open_worker() with the update_tls_slotinfo() call after
11all dependencies are being processed by _dl_map_object_deps(). However
12_dl_map_object_deps() itself might call _dl_next_tls_modid(), and since
13the _dl_tls_dtv_slotinfo_list::map is not yet set the entry will be
14wrongly reused.
15
16This patch fixes by renaming the _dl_next_tls_modid() function to
17_dl_assign_tls_modid() and by passing the link_map so it can set
18the slotinfo value so a subsequente _dl_next_tls_modid() call will
19see the entry as allocated.
20
21The intermediary value is cleared up on remove_slotinfo() for the case
22a library fails to load with RTLD_NOW.
23
24This patch fixes BZ #27135.
25
26Checked on x86_64-linux-gnu.
27
28Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
29---
30 elf/dl-close.c | 8 +-
31 elf/dl-load.c | 2 +-
32 elf/dl-open.c | 10 --
33 elf/dl-tls.c | 17 +--
34 elf/rtld.c | 2 +-
35 sysdeps/generic/ldsodefs.h | 4 +-
36 6 files changed, 349 insertions(+), 33 deletions(-)
37---
38Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=ba33937be210da5d07f7f01709323743f66011ce]
39Comment: Removed hunks those were related to test. Hunk from elf/rtld.c is refreshed.
40Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
41Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
42---
43diff --git a/elf/dl-close.c b/elf/dl-close.c
44index 3720e47dd1..f39001cab9 100644
45--- a/elf/dl-close.c
46+++ b/elf/dl-close.c
47@@ -77,8 +77,6 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
48 object that wasn't fully set up. */
49 if (__glibc_likely (old_map != NULL))
50 {
51- assert (old_map->l_tls_modid == idx);
52-
53 /* Mark the entry as unused. These can be read concurrently. */
54 atomic_store_relaxed (&listp->slotinfo[idx - disp].gen,
55 GL(dl_tls_generation) + 1);
56@@ -88,7 +86,11 @@ remove_slotinfo (size_t idx, struct dtv_slotinfo_list *listp, size_t disp,
57 /* If this is not the last currently used entry no need to look
58 further. */
59 if (idx != GL(dl_tls_max_dtv_idx))
60- return true;
61+ {
62+ /* There is an unused dtv entry in the middle. */
63+ GL(dl_tls_dtv_gaps) = true;
64+ return true;
65+ }
66 }
67
68 while (idx - disp > (disp == 0 ? 1 + GL(dl_tls_static_nelem) : 0))
69diff --git a/elf/dl-load.c b/elf/dl-load.c
70index a08df001af..650e4edc35 100644
71--- a/elf/dl-load.c
72+++ b/elf/dl-load.c
73@@ -1498,7 +1498,7 @@ cannot enable executable stack as shared object requires");
74 not set up TLS data structures, so don't use them now. */
75 || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL)))
76 /* Assign the next available module ID. */
77- l->l_tls_modid = _dl_next_tls_modid ();
78+ _dl_assign_tls_modid (l);
79
80 #ifdef DL_AFTER_LOAD
81 DL_AFTER_LOAD (l);
82diff --git a/elf/dl-open.c b/elf/dl-open.c
83index a066f39bd0..d2240d8747 100644
84--- a/elf/dl-open.c
85+++ b/elf/dl-open.c
86@@ -899,16 +899,6 @@ no more namespaces available for dlmopen()"));
87 state if relocation failed, for example. */
88 if (args.map)
89 {
90- /* Maybe some of the modules which were loaded use TLS.
91- Since it will be removed in the following _dl_close call
92- we have to mark the dtv array as having gaps to fill the
93- holes. This is a pessimistic assumption which won't hurt
94- if not true. There is no need to do this when we are
95- loading the auditing DSOs since TLS has not yet been set
96- up. */
97- if ((mode & __RTLD_AUDIT) == 0)
98- GL(dl_tls_dtv_gaps) = true;
99-
100 _dl_close_worker (args.map, true);
101
102 /* All l_nodelete_pending objects should have been deleted
103diff --git a/elf/dl-tls.c b/elf/dl-tls.c
104index 2b5161d10a..423e380f7c 100644
105--- a/elf/dl-tls.c
106+++ b/elf/dl-tls.c
107@@ -126,8 +126,8 @@ oom (void)
108 }
109
110
111-size_t
112-_dl_next_tls_modid (void)
113+void
114+_dl_assign_tls_modid (struct link_map *l)
115 {
116 size_t result;
117
118@@ -157,7 +157,11 @@ _dl_next_tls_modid (void)
119 }
120
121 if (result - disp < runp->len)
122- break;
123+ {
124+ /* Mark the entry as used, so any dependency see it. */
125+ atomic_store_relaxed (&runp->slotinfo[result - disp].map, l);
126+ break;
127+ }
128
129 disp += runp->len;
130 }
131@@ -184,17 +188,14 @@ _dl_next_tls_modid (void)
132 atomic_store_relaxed (&GL(dl_tls_max_dtv_idx), result);
133 }
134
135- return result;
136+ l->l_tls_modid = result;
137 }
138
139
140 size_t
141 _dl_count_modids (void)
142 {
143- /* It is rare that we have gaps; see elf/dl-open.c (_dl_open) where
144- we fail to load a module and unload it leaving a gap. If we don't
145- have gaps then the number of modids is the current maximum so
146- return that. */
147+ /* The count is the max unless dlclose or failed dlopen created gaps. */
148 if (__glibc_likely (!GL(dl_tls_dtv_gaps)))
149 return GL(dl_tls_max_dtv_idx);
150
151diff --git a/elf/rtld.c b/elf/rtld.c
152index e3fb2a5b2a..d733359eaf 100644
153--- a/elf/rtld.c
154+++ b/elf/rtld.c
155@@ -1612,7 +1612,7 @@
156 /* Add the dynamic linker to the TLS list if it also uses TLS. */
157 if (GL(dl_rtld_map).l_tls_blocksize != 0)
158 /* Assign a module ID. Do this before loading any audit modules. */
159- GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
160+ _dl_assign_tls_modid (&GL(dl_rtld_map));
161
162 /* If we have auditing DSOs to load, do it now. */
163 bool need_security_init = true;
164diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
165index 176394de4d..9c15259236 100644
166--- a/sysdeps/generic/ldsodefs.h
167+++ b/sysdeps/generic/ldsodefs.h
168@@ -1171,8 +1171,8 @@ extern ElfW(Addr) _dl_sysdep_start (void **start_argptr,
169 extern void _dl_sysdep_start_cleanup (void) attribute_hidden;
170
171
172-/* Determine next available module ID. */
173-extern size_t _dl_next_tls_modid (void) attribute_hidden;
174+/* Determine next available module ID and set the L l_tls_modid. */
175+extern void _dl_assign_tls_modid (struct link_map *l) attribute_hidden;
176
177 /* Count the modules with TLS segments. */
178 extern size_t _dl_count_modids (void) attribute_hidden;
179--
1802.27.0
diff --git a/meta/recipes-core/glibc/glibc/0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch b/meta/recipes-core/glibc/glibc/0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch
new file mode 100644
index 0000000000..899111b118
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch
@@ -0,0 +1,56 @@
1From 8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86 Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Thu, 11 Feb 2021 11:29:23 +0000
4Subject: [PATCH] x86_64: Avoid lazy relocation of tlsdesc [BZ #27137]
5
6Lazy tlsdesc relocation is racy because the static tls optimization and
7tlsdesc management operations are done without holding the dlopen lock.
8
9This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67
10for aarch64, but it fixes a different race: bug 27137.
11
12Another issue is that ld auditing ignores DT_BIND_NOW and thus tries to
13relocate tlsdesc lazily, but that does not work in a BIND_NOW module
14due to missing DT_TLSDESC_PLT. Unconditionally relocating tlsdesc at
15load time fixes this bug 27721 too.
16---
17 sysdeps/x86_64/dl-machine.h | 19 ++++++++++++++-----
18 1 file changed, 14 insertions(+), 5 deletions(-)
19---
20Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86]
21Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
22Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
23---
24diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
25index 103eee6c3f..9a876a371e 100644
26--- a/sysdeps/x86_64/dl-machine.h
27+++ b/sysdeps/x86_64/dl-machine.h
28@@ -570,12 +570,21 @@ elf_machine_lazy_rel (struct link_map *map,
29 }
30 else if (__glibc_likely (r_type == R_X86_64_TLSDESC))
31 {
32- struct tlsdesc volatile * __attribute__((__unused__)) td =
33- (struct tlsdesc volatile *)reloc_addr;
34+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
35+ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
36+ const ElfW (Sym) *sym = &symtab[symndx];
37+ const struct r_found_version *version = NULL;
38
39- td->arg = (void*)reloc;
40- td->entry = (void*)(D_PTR (map, l_info[ADDRIDX (DT_TLSDESC_PLT)])
41- + map->l_addr);
42+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
43+ {
44+ const ElfW (Half) *vernum =
45+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
46+ version = &map->l_versions[vernum[symndx] & 0x7fff];
47+ }
48+
49+ /* Always initialize TLS descriptors completely at load time, in
50+ case static TLS is allocated for it that requires locking. */
51+ elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
52 }
53 else if (__glibc_unlikely (r_type == R_X86_64_IRELATIVE))
54 {
55--
562.27.0
diff --git a/meta/recipes-core/glibc/glibc/0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch b/meta/recipes-core/glibc/glibc/0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch
new file mode 100644
index 0000000000..ad0a1147aa
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch
@@ -0,0 +1,124 @@
1From ddcacd91cc10ff92d6201eda87047d029c14158d Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Thu, 11 Feb 2021 11:40:11 +0000
4Subject: [PATCH] i386: Avoid lazy relocation of tlsdesc [BZ #27137]
5
6Lazy tlsdesc relocation is racy because the static tls optimization and
7tlsdesc management operations are done without holding the dlopen lock.
8
9This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67
10for aarch64, but it fixes a different race: bug 27137.
11
12On i386 the code is a bit more complicated than on x86_64 because both
13rel and rela relocs are supported.
14---
15 sysdeps/i386/dl-machine.h | 76 ++++++++++++++++++---------------------
16 1 file changed, 34 insertions(+), 42 deletions(-)
17---
18Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=ddcacd91cc10ff92d6201eda87047d029c14158d]
19Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
20Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
21---
22diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
23index 23e9cc3bfb..590b41d8d7 100644
24--- a/sysdeps/i386/dl-machine.h
25+++ b/sysdeps/i386/dl-machine.h
26@@ -688,50 +688,32 @@ elf_machine_lazy_rel (struct link_map *map,
27 }
28 else if (__glibc_likely (r_type == R_386_TLS_DESC))
29 {
30- struct tlsdesc volatile * __attribute__((__unused__)) td =
31- (struct tlsdesc volatile *)reloc_addr;
32-
33- /* Handle relocations that reference the local *ABS* in a simple
34- way, so as to preserve a potential addend. */
35- if (ELF32_R_SYM (reloc->r_info) == 0)
36- td->entry = _dl_tlsdesc_resolve_abs_plus_addend;
37- /* Given a known-zero addend, we can store a pointer to the
38- reloc in the arg position. */
39- else if (td->arg == 0)
40- {
41- td->arg = (void*)reloc;
42- td->entry = _dl_tlsdesc_resolve_rel;
43- }
44- else
45- {
46- /* We could handle non-*ABS* relocations with non-zero addends
47- by allocating dynamically an arg to hold a pointer to the
48- reloc, but that sounds pointless. */
49- const Elf32_Rel *const r = reloc;
50- /* The code below was borrowed from elf_dynamic_do_rel(). */
51- const ElfW(Sym) *const symtab =
52- (const void *) D_PTR (map, l_info[DT_SYMTAB]);
53+ const Elf32_Rel *const r = reloc;
54+ /* The code below was borrowed from elf_dynamic_do_rel(). */
55+ const ElfW(Sym) *const symtab =
56+ (const void *) D_PTR (map, l_info[DT_SYMTAB]);
57
58+ /* Always initialize TLS descriptors completely at load time, in
59+ case static TLS is allocated for it that requires locking. */
60 # ifdef RTLD_BOOTSTRAP
61- /* The dynamic linker always uses versioning. */
62- assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
63+ /* The dynamic linker always uses versioning. */
64+ assert (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL);
65 # else
66- if (map->l_info[VERSYMIDX (DT_VERSYM)])
67+ if (map->l_info[VERSYMIDX (DT_VERSYM)])
68 # endif
69- {
70- const ElfW(Half) *const version =
71- (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
72- ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
73- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
74- &map->l_versions[ndx],
75- (void *) (l_addr + r->r_offset), skip_ifunc);
76- }
77+ {
78+ const ElfW(Half) *const version =
79+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
80+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
81+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)],
82+ &map->l_versions[ndx],
83+ (void *) (l_addr + r->r_offset), skip_ifunc);
84+ }
85 # ifndef RTLD_BOOTSTRAP
86- else
87- elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
88- (void *) (l_addr + r->r_offset), skip_ifunc);
89+ else
90+ elf_machine_rel (map, r, &symtab[ELFW(R_SYM) (r->r_info)], NULL,
91+ (void *) (l_addr + r->r_offset), skip_ifunc);
92 # endif
93- }
94 }
95 else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
96 {
97@@ -758,11 +740,21 @@ elf_machine_lazy_rela (struct link_map *map,
98 ;
99 else if (__glibc_likely (r_type == R_386_TLS_DESC))
100 {
101- struct tlsdesc volatile * __attribute__((__unused__)) td =
102- (struct tlsdesc volatile *)reloc_addr;
103+ const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
104+ const ElfW (Sym) *symtab = (const void *)D_PTR (map, l_info[DT_SYMTAB]);
105+ const ElfW (Sym) *sym = &symtab[symndx];
106+ const struct r_found_version *version = NULL;
107+
108+ if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
109+ {
110+ const ElfW (Half) *vernum =
111+ (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
112+ version = &map->l_versions[vernum[symndx] & 0x7fff];
113+ }
114
115- td->arg = (void*)reloc;
116- td->entry = _dl_tlsdesc_resolve_rela;
117+ /* Always initialize TLS descriptors completely at load time, in
118+ case static TLS is allocated for it that requires locking. */
119+ elf_machine_rela (map, reloc, sym, version, reloc_addr, skip_ifunc);
120 }
121 else if (__glibc_unlikely (r_type == R_386_IRELATIVE))
122 {
123--
1242.27.0
diff --git a/meta/recipes-core/glibc/glibc/0037-Avoid-deadlock-between-pthread_create-and-ctors.patch b/meta/recipes-core/glibc/glibc/0037-Avoid-deadlock-between-pthread_create-and-ctors.patch
new file mode 100644
index 0000000000..7a10131bad
--- /dev/null
+++ b/meta/recipes-core/glibc/glibc/0037-Avoid-deadlock-between-pthread_create-and-ctors.patch
@@ -0,0 +1,276 @@
1From 83b5323261bb72313bffcf37476c1b8f0847c736 Mon Sep 17 00:00:00 2001
2From: Szabolcs Nagy <szabolcs.nagy@arm.com>
3Date: Wed, 15 Sep 2021 15:16:19 +0100
4Subject: [PATCH] elf: Avoid deadlock between pthread_create and ctors [BZ
5 #28357]
6
7The fix for bug 19329 caused a regression such that pthread_create can
8deadlock when concurrent ctors from dlopen are waiting for it to finish.
9Use a new GL(dl_load_tls_lock) in pthread_create that is not taken
10around ctors in dlopen.
11
12The new lock is also used in __tls_get_addr instead of GL(dl_load_lock).
13
14The new lock is held in _dl_open_worker and _dl_close_worker around
15most of the logic before/after the init/fini routines. When init/fini
16routines are running then TLS is in a consistent, usable state.
17In _dl_open_worker the new lock requires catching and reraising dlopen
18failures that happen in the critical section.
19
20The new lock is reinitialized in a fork child, to keep the existing
21behaviour and it is kept recursive in case malloc interposition or TLS
22access from signal handlers can retake it. It is not obvious if this
23is necessary or helps, but avoids changing the preexisting behaviour.
24
25The new lock may be more appropriate for dl_iterate_phdr too than
26GL(dl_load_write_lock), since TLS state of an incompletely loaded
27module may be accessed. If the new lock can replace the old one,
28that can be a separate change.
29
30Fixes bug 28357.
31
32Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
33---
34 elf/dl-close.c | 6 ++
35 elf/dl-open.c | 35 ++++++++-
36 elf/dl-support.c | 7 ++
37 elf/dl-tls.c | 16 ++---
38 elf/rtld.c | 1 +
39 sysdeps/nptl/fork.c | 3 +
40 sysdeps/generic/ldsodefs.h | 9 ++-
41 10 files changed, 235 insertions(+), 12 deletions(-)
42---
43Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=024a7640ab9ecea80e527f4e4d7f7a1868e952c5]
44Comment: This patch is refreshed for glibc 2.31. In upstream glibc 2.34 multiple src files are shuffled, updated this patch as per the code present in glibc 2.31. Removed test case.
45Signed-off-by: Akash Hadke <akash.hadke@kpit.com>
46Signed-off-by: Akash Hadke <hadkeakash4@gmail.com>
47---
48diff --git a/elf/dl-close.c b/elf/dl-close.c
49index 93ff5c96e9..cfe0f1c0c9 100644
50--- a/elf/dl-close.c
51+++ b/elf/dl-close.c
52@@ -551,6 +551,9 @@
53 size_t tls_free_end;
54 tls_free_start = tls_free_end = NO_TLS_OFFSET;
55
56+ /* Protects global and module specitic TLS state. */
57+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
58+
59 /* We modify the list of loaded objects. */
60 __rtld_lock_lock_recursive (GL(dl_load_write_lock));
61
62@@ -786,6 +789,9 @@
63 GL(dl_tls_static_used) = tls_free_start;
64 }
65
66+ /* TLS is cleaned up for the unloaded modules. */
67+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
68+
69 #ifdef SHARED
70 /* Auditing checkpoint: we have deleted all objects. */
71 if (__glibc_unlikely (do_audit))
72diff --git a/elf/dl-open.c b/elf/dl-open.c
73index 5295e931b0..6ea5dd2457 100644
74--- a/elf/dl-open.c
75+++ b/elf/dl-open.c
76@@ -57,6 +57,9 @@
77 (non-negative). */
78 unsigned int original_global_scope_pending_adds;
79
80+ /* Set to true if the end of dl_open_worker_begin was reached. */
81+ bool worker_continue;
82+
83 /* Original parameters to the program and the current environment. */
84 int argc;
85 char **argv;
86@@ -473,7 +473,7 @@
87 }
88
89 static void
90-dl_open_worker (void *a)
91+dl_open_worker_begin (void *a)
92 {
93 struct dl_open_args *args = a;
94 const char *file = args->file;
95@@ -747,6 +747,36 @@
96 if (mode & RTLD_GLOBAL)
97 add_to_global_resize (new);
98
99+ args->worker_continue = true;
100+}
101+
102+static void
103+dl_open_worker (void *a)
104+{
105+ struct dl_open_args *args = a;
106+
107+ args->worker_continue = false;
108+
109+ {
110+ /* Protects global and module specific TLS state. */
111+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
112+
113+ struct dl_exception ex;
114+ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args);
115+
116+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
117+
118+ if (__glibc_unlikely (ex.errstring != NULL))
119+ /* Reraise the error. */
120+ _dl_signal_exception (err, &ex, NULL);
121+ }
122+
123+ if (!args->worker_continue)
124+ return;
125+
126+ int mode = args->mode;
127+ struct link_map *new = args->map;
128+
129 /* Run the initializer functions of new objects. Temporarily
130 disable the exception handler, so that lazy binding failures are
131 fatal. */
132diff --git a/elf/dl-support.c b/elf/dl-support.c
133index 02e2ed72f5..d99c1f1d62 100644
134--- a/elf/dl-support.c
135+++ b/elf/dl-support.c
136@@ -219,6 +219,13 @@
137 list of loaded objects while an object is added to or removed from
138 that list. */
139 __rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
140+/* This lock protects global and module specific TLS related data.
141+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
142+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
143+ accessed and when TLS related relocations are processed for a
144+ module. It was introduced to keep pthread_create accessing TLS
145+ state that is being set up. */
146+__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
147
148
149 #ifdef HAVE_AUX_VECTOR
150diff --git a/elf/dl-tls.c b/elf/dl-tls.c
151index d554ae4497..9260d2d696 100644
152--- a/elf/dl-tls.c
153+++ b/elf/dl-tls.c
154@@ -443,7 +443,7 @@
155 size_t maxgen = 0;
156
157 /* Protects global dynamic TLS related state. */
158- __rtld_lock_lock_recursive (GL(dl_load_lock));
159+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
160
161 /* Check if the current dtv is big enough. */
162 if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
163@@ -517,7 +517,7 @@
164 listp = listp->next;
165 assert (listp != NULL);
166 }
167- __rtld_lock_unlock_recursive (GL(dl_load_lock));
168+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
169
170 /* The DTV version is up-to-date now. */
171 dtv[0].counter = maxgen;
172@@ -656,7 +656,7 @@
173
174 Here the dtv needs to be updated to new_gen generation count.
175
176- This code may be called during TLS access when GL(dl_load_lock)
177+ This code may be called during TLS access when GL(dl_load_tls_lock)
178 is not held. In that case the user code has to synchronize with
179 dlopen and dlclose calls of relevant modules. A module m is
180 relevant if the generation of m <= new_gen and dlclose of m is
181@@ -778,11 +778,11 @@
182 if (__glibc_unlikely (the_map->l_tls_offset
183 != FORCED_DYNAMIC_TLS_OFFSET))
184 {
185- __rtld_lock_lock_recursive (GL(dl_load_lock));
186+ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
187 if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
188 {
189 the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
190- __rtld_lock_unlock_recursive (GL(dl_load_lock));
191+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
192 }
193 else if (__glibc_likely (the_map->l_tls_offset
194 != FORCED_DYNAMIC_TLS_OFFSET))
195@@ -794,7 +794,7 @@
196 #else
197 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
198 #endif
199- __rtld_lock_unlock_recursive (GL(dl_load_lock));
200+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
201
202 dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
203 dtv[GET_ADDR_MODULE].pointer.val = p;
204@@ -802,7 +802,7 @@
205 return (char *) p + GET_ADDR_OFFSET;
206 }
207 else
208- __rtld_lock_unlock_recursive (GL(dl_load_lock));
209+ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
210 }
211 struct dtv_pointer result = allocate_and_init (the_map);
212 dtv[GET_ADDR_MODULE].pointer = result;
213@@ -873,7 +873,7 @@
214 return NULL;
215
216 dtv_t *dtv = THREAD_DTV ();
217- /* This may be called without holding the GL(dl_load_lock). Reading
218+ /* This may be called without holding the GL(dl_load_tls_lock). Reading
219 arbitrary gen value is fine since this is best effort code. */
220 size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
221 if (__glibc_unlikely (dtv[0].counter != gen))
222diff --git a/elf/rtld.c b/elf/rtld.c
223index 8d2bba3d43..9642eb9c92 100644
224--- a/elf/rtld.c
225+++ b/elf/rtld.c
226@@ -283,6 +283,7 @@
227 #ifdef _LIBC_REENTRANT
228 ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
229 ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
230+ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
231 #endif
232 ._dl_nns = 1,
233 ._dl_ns =
234diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
235index c471f7b15f..021691b9b7 100644
236--- a/sysdeps/nptl/fork.c
237+++ b/sysdeps/nptl/fork.c
238@@ -125,6 +125,9 @@
239 /* Reset the lock the dynamic loader uses to protect its data. */
240 __rtld_lock_initialize (GL(dl_load_lock));
241
242+ /* Reset the lock protecting dynamic TLS related data. */
243+ __rtld_lock_initialize (GL(dl_load_tls_lock));
244+
245 /* Run the handlers registered for the child. */
246 __run_fork_handlers (atfork_run_child, multiple_threads);
247 }
248diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
249index d49529da0d..9ec1511bb0 100644
250--- a/sysdeps/generic/ldsodefs.h
251+++ b/sysdeps/generic/ldsodefs.h
252@@ -369,6 +369,13 @@
253 list of loaded objects while an object is added to or removed
254 from that list. */
255 __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock)
256+ /* This lock protects global and module specific TLS related data.
257+ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
258+ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
259+ accessed and when TLS related relocations are processed for a
260+ module. It was introduced to keep pthread_create accessing TLS
261+ state that is being set up. */
262+ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock)
263
264 /* Incremented whenever something may have been added to dl_loaded. */
265 EXTERN unsigned long long _dl_load_adds;
266@@ -1153,7 +1160,7 @@
267
268 /* Add module to slot information data. If DO_ADD is false, only the
269 required memory is allocated. Must be called with GL
270- (dl_load_lock) acquired. If the function has already been called
271+ (dl_load_tls_lock) acquired. If the function has already been called
272 for the link map L with !do_add, then this function will not raise
273 an exception, otherwise it is possible that it encounters a memory
274 allocation failure. */
275--
2762.27.0
diff --git a/meta/recipes-core/glibc/glibc_2.31.bb b/meta/recipes-core/glibc/glibc_2.31.bb
index 3a3586f1b9..4a545cb97d 100644
--- a/meta/recipes-core/glibc/glibc_2.31.bb
+++ b/meta/recipes-core/glibc/glibc_2.31.bb
@@ -70,6 +70,14 @@ SRC_URI = "${GLIBC_GIT_URI};branch=${SRCBRANCH};name=glibc \
70 file://CVE-2021-33574_1.patch \ 70 file://CVE-2021-33574_1.patch \
71 file://CVE-2021-33574_2.patch \ 71 file://CVE-2021-33574_2.patch \
72 file://CVE-2021-38604.patch \ 72 file://CVE-2021-38604.patch \
73 file://0030-elf-Refactor_dl_update-slotinfo-to-avoid-use-after-free.patch \
74 file://0031-elf-Fix-data-races-in-pthread_create-and-TLS-access-BZ-19329.patch \
75 file://0032-elf-Use-relaxed-atomics-for-racy-accesses-BZ-19329.patch \
76 file://0033-elf-Add-test-case-for-BZ-19329.patch \
77 file://0034-elf-Fix-DTV-gap-reuse-logic-BZ-27135.patch \
78 file://0035-x86_64-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch \
79 file://0036-i386-Avoid-lazy-relocation-of-tlsdesc-BZ-27137.patch \
80 file://0037-Avoid-deadlock-between-pthread_create-and-ctors.patch \
73 " 81 "
74S = "${WORKDIR}/git" 82S = "${WORKDIR}/git"
75B = "${WORKDIR}/build-${TARGET_SYS}" 83B = "${WORKDIR}/build-${TARGET_SYS}"