diff options
Diffstat (limited to 'meta/recipes-core')
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 @@ | |||
| 1 | From c0669ae1a629e16b536bf11cdd0865e0dbcf4bee Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Wed, 30 Dec 2020 21:52:38 +0000 | ||
| 4 | Subject: [PATCH] elf: Refactor _dl_update_slotinfo to avoid use after free | ||
| 5 | |||
| 6 | map is not valid to access here because it can be freed by a concurrent | ||
| 7 | dlclose: during tls access (via __tls_get_addr) _dl_update_slotinfo is | ||
| 8 | called without holding dlopen locks. So don't check the modid of map. | ||
| 9 | |||
| 10 | The map == 0 and map != 0 code paths can be shared (avoiding the dtv | ||
| 11 | resize in case of map == 0 is just an optimization: larger dtv than | ||
| 12 | necessary would be fine too). | ||
| 13 | |||
| 14 | Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> | ||
| 15 | --- | ||
| 16 | elf/dl-tls.c | 21 +++++---------------- | ||
| 17 | 1 file changed, 5 insertions(+), 16 deletions(-) | ||
| 18 | --- | ||
| 19 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=c0669ae1a629e16b536bf11cdd0865e0dbcf4bee] | ||
| 20 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 21 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 22 | --- | ||
| 23 | diff --git a/elf/dl-tls.c b/elf/dl-tls.c | ||
| 24 | index 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 | -- | ||
| 66 | 2.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 @@ | |||
| 1 | From 1387ad6225c2222f027790e3f460e31aa5dd2c54 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Wed, 30 Dec 2020 19:19:37 +0000 | ||
| 4 | Subject: [PATCH] elf: Fix data races in pthread_create and TLS access [BZ | ||
| 5 | #19329] | ||
| 6 | |||
| 7 | DTV setup at thread creation (_dl_allocate_tls_init) is changed | ||
| 8 | to take the dlopen lock, GL(dl_load_lock). Avoiding data races | ||
| 9 | here without locks would require design changes: the map that is | ||
| 10 | accessed for static TLS initialization here may be concurrently | ||
| 11 | freed by dlclose. That use after free may be solved by only | ||
| 12 | locking around static TLS setup or by ensuring dlclose does not | ||
| 13 | free modules with static TLS, however currently every link map | ||
| 14 | with TLS has to be accessed at least to see if it needs static | ||
| 15 | TLS. And even if that's solved, still a lot of atomics would be | ||
| 16 | needed to synchronize DTV related globals without a lock. So fix | ||
| 17 | both bug 19329 and bug 27111 with a lock that prevents DTV setup | ||
| 18 | running concurrently with dlopen or dlclose. | ||
| 19 | |||
| 20 | _dl_update_slotinfo at TLS access still does not use any locks | ||
| 21 | so CONCURRENCY NOTES are added to explain the synchronization. | ||
| 22 | The early exit from the slotinfo walk when max_modid is reached | ||
| 23 | is not strictly necessary, but does not hurt either. | ||
| 24 | |||
| 25 | An incorrect acquire load was removed from _dl_resize_dtv: it | ||
| 26 | did not synchronize with any release store or fence and | ||
| 27 | synchronization is now handled separately at thread creation | ||
| 28 | and TLS access time. | ||
| 29 | |||
| 30 | There are still a number of racy read accesses to globals that | ||
| 31 | will be changed to relaxed MO atomics in a followup patch. This | ||
| 32 | should not introduce regressions compared to existing behaviour | ||
| 33 | and avoid cluttering the main part of the fix. | ||
| 34 | |||
| 35 | Not all TLS access related data races got fixed here: there are | ||
| 36 | additional races at lazy tlsdesc relocations see bug 27137. | ||
| 37 | |||
| 38 | Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> | ||
| 39 | --- | ||
| 40 | elf/dl-tls.c | 63 +++++++++++++++++++++++++++++++++++++++------------- | ||
| 41 | 1 file changed, 47 insertions(+), 16 deletions(-) | ||
| 42 | --- | ||
| 43 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=1387ad6225c2222f027790e3f460e31aa5dd2c54] | ||
| 44 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 45 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 46 | --- | ||
| 47 | diff --git a/elf/dl-tls.c b/elf/dl-tls.c | ||
| 48 | index 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 | -- | ||
| 191 | 2.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 @@ | |||
| 1 | From f4f8f4d4e0f92488431b268c8cd9555730b9afe9 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Wed, 30 Dec 2020 19:19:37 +0000 | ||
| 4 | Subject: [PATCH] elf: Use relaxed atomics for racy accesses [BZ #19329] | ||
| 5 | |||
| 6 | This is a follow up patch to the fix for bug 19329. This adds relaxed | ||
| 7 | MO atomics to accesses that were previously data races but are now | ||
| 8 | race conditions, and where relaxed MO is sufficient. | ||
| 9 | |||
| 10 | The race conditions all follow the pattern that the write is behind the | ||
| 11 | dlopen lock, but a read can happen concurrently (e.g. during tls access) | ||
| 12 | without holding the lock. For slotinfo entries the read value only | ||
| 13 | matters if it reads from a synchronized write in dlopen or dlclose, | ||
| 14 | otherwise the related dtv entry is not valid to access so it is fine | ||
| 15 | to leave it in an inconsistent state. The same applies for | ||
| 16 | GL(dl_tls_max_dtv_idx) and GL(dl_tls_generation), but there the | ||
| 17 | algorithm relies on the fact that the read of the last synchronized | ||
| 18 | write is an increasing value. | ||
| 19 | |||
| 20 | Reviewed-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 | --- | ||
| 28 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=f4f8f4d4e0f92488431b268c8cd9555730b9afe9] | ||
| 29 | Comment: Hunks from elf/dl-open.c and elf/dl-tls.c are refreshed due to offset change. | ||
| 30 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 31 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 32 | --- | ||
| 33 | diff --git a/elf/dl-close.c b/elf/dl-close.c | ||
| 34 | index 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; | ||
| 86 | diff --git a/elf/dl-open.c b/elf/dl-open.c | ||
| 87 | index 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 | ||
| 104 | diff --git a/elf/dl-tls.c b/elf/dl-tls.c | ||
| 105 | index 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 | |||
| 191 | diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c | ||
| 192 | index 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 | -- | ||
| 206 | 2.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 @@ | |||
| 1 | From 9d0e30329c23b5ad736fda3f174208c25970dbce Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Tue, 13 Dec 2016 12:28:41 +0000 | ||
| 4 | Subject: [PATCH] elf: Add test case for [BZ #19329] | ||
| 5 | |||
| 6 | Test concurrent dlopen and pthread_create when the loaded modules have | ||
| 7 | TLS. This triggers dl-tls assertion failures more reliably than the | ||
| 8 | nptl/tst-stack4 test. | ||
| 9 | |||
| 10 | The dlopened module has 100 DT_NEEDED dependencies with TLS, they were | ||
| 11 | reused from an existing TLS test. The number of created threads during | ||
| 12 | dlopen depends on filesystem speed and hardware, but at most 3 threads | ||
| 13 | are alive at a time to limit resource usage. | ||
| 14 | |||
| 15 | Reviewed-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 | --- | ||
| 24 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=9d0e30329c23b5ad736fda3f174208c25970dbce] | ||
| 25 | Comment: Hunks from elf/Makefile are refreshed as per glibc 2.31 codebase. | ||
| 26 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 27 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 28 | --- | ||
| 29 | diff --git a/elf/Makefile b/elf/Makefile | ||
| 30 | index 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) | ||
| 62 | diff --git a/elf/tst-tls21.c b/elf/tst-tls21.c | ||
| 63 | new file mode 100644 | ||
| 64 | index 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> | ||
| 136 | diff --git a/elf/tst-tls21mod.c b/elf/tst-tls21mod.c | ||
| 137 | new file mode 100644 | ||
| 138 | index 0000000000..206ece4fb3 | ||
| 139 | --- /dev/null | ||
| 140 | +++ b/elf/tst-tls21mod.c | ||
| 141 | @@ -0,0 +1 @@ | ||
| 142 | +int __thread x; | ||
| 143 | -- | ||
| 144 | 2.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 @@ | |||
| 1 | From ba33937be210da5d07f7f01709323743f66011ce Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Adhemerval Zanella <adhemerval.zanella@linaro.org> | ||
| 3 | Date: Fri, 25 Jun 2021 10:54:12 -0300 | ||
| 4 | Subject: [PATCH] elf: Fix DTV gap reuse logic (BZ #27135) | ||
| 5 | |||
| 6 | This is updated version of the 572bd547d57a (reverted by 40ebfd016ad2) | ||
| 7 | that fixes the _dl_next_tls_modid issues. | ||
| 8 | |||
| 9 | This issue with 572bd547d57a patch is the DTV entry will be only | ||
| 10 | update on dl_open_worker() with the update_tls_slotinfo() call after | ||
| 11 | all dependencies are being processed by _dl_map_object_deps(). However | ||
| 12 | _dl_map_object_deps() itself might call _dl_next_tls_modid(), and since | ||
| 13 | the _dl_tls_dtv_slotinfo_list::map is not yet set the entry will be | ||
| 14 | wrongly reused. | ||
| 15 | |||
| 16 | This 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 | ||
| 18 | the slotinfo value so a subsequente _dl_next_tls_modid() call will | ||
| 19 | see the entry as allocated. | ||
| 20 | |||
| 21 | The intermediary value is cleared up on remove_slotinfo() for the case | ||
| 22 | a library fails to load with RTLD_NOW. | ||
| 23 | |||
| 24 | This patch fixes BZ #27135. | ||
| 25 | |||
| 26 | Checked on x86_64-linux-gnu. | ||
| 27 | |||
| 28 | Reviewed-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 | --- | ||
| 38 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=ba33937be210da5d07f7f01709323743f66011ce] | ||
| 39 | Comment: Removed hunks those were related to test. Hunk from elf/rtld.c is refreshed. | ||
| 40 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 41 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 42 | --- | ||
| 43 | diff --git a/elf/dl-close.c b/elf/dl-close.c | ||
| 44 | index 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)) | ||
| 69 | diff --git a/elf/dl-load.c b/elf/dl-load.c | ||
| 70 | index 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); | ||
| 82 | diff --git a/elf/dl-open.c b/elf/dl-open.c | ||
| 83 | index 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 | ||
| 103 | diff --git a/elf/dl-tls.c b/elf/dl-tls.c | ||
| 104 | index 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 | |||
| 151 | diff --git a/elf/rtld.c b/elf/rtld.c | ||
| 152 | index 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; | ||
| 164 | diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h | ||
| 165 | index 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 | -- | ||
| 180 | 2.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 @@ | |||
| 1 | From 8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Thu, 11 Feb 2021 11:29:23 +0000 | ||
| 4 | Subject: [PATCH] x86_64: Avoid lazy relocation of tlsdesc [BZ #27137] | ||
| 5 | |||
| 6 | Lazy tlsdesc relocation is racy because the static tls optimization and | ||
| 7 | tlsdesc management operations are done without holding the dlopen lock. | ||
| 8 | |||
| 9 | This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67 | ||
| 10 | for aarch64, but it fixes a different race: bug 27137. | ||
| 11 | |||
| 12 | Another issue is that ld auditing ignores DT_BIND_NOW and thus tries to | ||
| 13 | relocate tlsdesc lazily, but that does not work in a BIND_NOW module | ||
| 14 | due to missing DT_TLSDESC_PLT. Unconditionally relocating tlsdesc at | ||
| 15 | load time fixes this bug 27721 too. | ||
| 16 | --- | ||
| 17 | sysdeps/x86_64/dl-machine.h | 19 ++++++++++++++----- | ||
| 18 | 1 file changed, 14 insertions(+), 5 deletions(-) | ||
| 19 | --- | ||
| 20 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=8f7e09f4dbdb5c815a18b8285fbc5d5d7bc17d86] | ||
| 21 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 22 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 23 | --- | ||
| 24 | diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h | ||
| 25 | index 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 | -- | ||
| 56 | 2.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 @@ | |||
| 1 | From ddcacd91cc10ff92d6201eda87047d029c14158d Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Thu, 11 Feb 2021 11:40:11 +0000 | ||
| 4 | Subject: [PATCH] i386: Avoid lazy relocation of tlsdesc [BZ #27137] | ||
| 5 | |||
| 6 | Lazy tlsdesc relocation is racy because the static tls optimization and | ||
| 7 | tlsdesc management operations are done without holding the dlopen lock. | ||
| 8 | |||
| 9 | This similar to the commit b7cf203b5c17dd6d9878537d41e0c7cc3d270a67 | ||
| 10 | for aarch64, but it fixes a different race: bug 27137. | ||
| 11 | |||
| 12 | On i386 the code is a bit more complicated than on x86_64 because both | ||
| 13 | rel and rela relocs are supported. | ||
| 14 | --- | ||
| 15 | sysdeps/i386/dl-machine.h | 76 ++++++++++++++++++--------------------- | ||
| 16 | 1 file changed, 34 insertions(+), 42 deletions(-) | ||
| 17 | --- | ||
| 18 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=ddcacd91cc10ff92d6201eda87047d029c14158d] | ||
| 19 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 20 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 21 | --- | ||
| 22 | diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h | ||
| 23 | index 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 | -- | ||
| 124 | 2.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 @@ | |||
| 1 | From 83b5323261bb72313bffcf37476c1b8f0847c736 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Szabolcs Nagy <szabolcs.nagy@arm.com> | ||
| 3 | Date: Wed, 15 Sep 2021 15:16:19 +0100 | ||
| 4 | Subject: [PATCH] elf: Avoid deadlock between pthread_create and ctors [BZ | ||
| 5 | #28357] | ||
| 6 | |||
| 7 | The fix for bug 19329 caused a regression such that pthread_create can | ||
| 8 | deadlock when concurrent ctors from dlopen are waiting for it to finish. | ||
| 9 | Use a new GL(dl_load_tls_lock) in pthread_create that is not taken | ||
| 10 | around ctors in dlopen. | ||
| 11 | |||
| 12 | The new lock is also used in __tls_get_addr instead of GL(dl_load_lock). | ||
| 13 | |||
| 14 | The new lock is held in _dl_open_worker and _dl_close_worker around | ||
| 15 | most of the logic before/after the init/fini routines. When init/fini | ||
| 16 | routines are running then TLS is in a consistent, usable state. | ||
| 17 | In _dl_open_worker the new lock requires catching and reraising dlopen | ||
| 18 | failures that happen in the critical section. | ||
| 19 | |||
| 20 | The new lock is reinitialized in a fork child, to keep the existing | ||
| 21 | behaviour and it is kept recursive in case malloc interposition or TLS | ||
| 22 | access from signal handlers can retake it. It is not obvious if this | ||
| 23 | is necessary or helps, but avoids changing the preexisting behaviour. | ||
| 24 | |||
| 25 | The new lock may be more appropriate for dl_iterate_phdr too than | ||
| 26 | GL(dl_load_write_lock), since TLS state of an incompletely loaded | ||
| 27 | module may be accessed. If the new lock can replace the old one, | ||
| 28 | that can be a separate change. | ||
| 29 | |||
| 30 | Fixes bug 28357. | ||
| 31 | |||
| 32 | Reviewed-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 | --- | ||
| 43 | Upstream-Status: Backport [https://sourceware.org/git/?p=glibc.git;a=patch;h=024a7640ab9ecea80e527f4e4d7f7a1868e952c5] | ||
| 44 | Comment: 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. | ||
| 45 | Signed-off-by: Akash Hadke <akash.hadke@kpit.com> | ||
| 46 | Signed-off-by: Akash Hadke <hadkeakash4@gmail.com> | ||
| 47 | --- | ||
| 48 | diff --git a/elf/dl-close.c b/elf/dl-close.c | ||
| 49 | index 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)) | ||
| 72 | diff --git a/elf/dl-open.c b/elf/dl-open.c | ||
| 73 | index 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. */ | ||
| 132 | diff --git a/elf/dl-support.c b/elf/dl-support.c | ||
| 133 | index 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 | ||
| 150 | diff --git a/elf/dl-tls.c b/elf/dl-tls.c | ||
| 151 | index 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)) | ||
| 222 | diff --git a/elf/rtld.c b/elf/rtld.c | ||
| 223 | index 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 = | ||
| 234 | diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c | ||
| 235 | index 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 | } | ||
| 248 | diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h | ||
| 249 | index 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 | -- | ||
| 276 | 2.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 | " |
| 74 | S = "${WORKDIR}/git" | 82 | S = "${WORKDIR}/git" |
| 75 | B = "${WORKDIR}/build-${TARGET_SYS}" | 83 | B = "${WORKDIR}/build-${TARGET_SYS}" |
