diff --git a/packages/glibc/0028-Revert-elf-Remove-unused-l_text_end-field-from-struc.patch b/packages/glibc/0028-Revert-elf-Remove-unused-l_text_end-field-from-struc.patch new file mode 100644 index 00000000000..6b9e8766210 --- /dev/null +++ b/packages/glibc/0028-Revert-elf-Remove-unused-l_text_end-field-from-struc.patch @@ -0,0 +1,135 @@ +From e0b6c9706c91a642c781918eea52588ee8dc9f09 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 18 Oct 2023 14:22:59 +0200 +Subject: [PATCH] Revert "elf: Remove unused l_text_end field from struct + link_map" + +This reverts commit 750f19526ae71aac801c77a3f7ef5374890c09b7. + +Reason for revert: Restore ABI after revert of commit a3189f66a5f. +--- + elf/dl-load.c | 2 +- + elf/dl-load.h | 7 +++++-- + elf/rtld.c | 6 ++++++ + elf/setup-vdso.h | 4 ++++ + include/link.h | 2 ++ + 5 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 2923b1141d..9a87fda9c9 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -1253,7 +1253,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + + /* Now process the load commands and map segments into memory. + This is responsible for filling in: +- l_map_start, l_map_end, l_addr, l_contiguous, l_phdr ++ l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr + */ + errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds, + maplength, has_holes, loader); +diff --git a/elf/dl-load.h b/elf/dl-load.h +index 1d5207694b..ecf6910c68 100644 +--- a/elf/dl-load.h ++++ b/elf/dl-load.h +@@ -83,11 +83,14 @@ struct loadcmd + + /* This is a subroutine of _dl_map_segments. It should be called for each + load command, some time after L->l_addr has been set correctly. It is +- responsible for setting the l_phdr fields */ ++ responsible for setting up the l_text_end and l_phdr fields. */ + static __always_inline void + _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, + const struct loadcmd *c) + { ++ if (c->prot & PROT_EXEC) ++ l->l_text_end = l->l_addr + c->mapend; ++ + if (l->l_phdr == 0 + && c->mapoff <= header->e_phoff + && ((size_t) (c->mapend - c->mapstart + c->mapoff) +@@ -100,7 +103,7 @@ _dl_postprocess_loadcmd (struct link_map *l, const ElfW(Ehdr) *header, + + /* This is a subroutine of _dl_map_object_from_fd. It is responsible + for filling in several fields in *L: l_map_start, l_map_end, l_addr, +- l_contiguous, l_phdr. On successful return, all the ++ l_contiguous, l_text_end, l_phdr. On successful return, all the + segments are mapped (or copied, or whatever) from the file into their + final places in the address space, with the correct page permissions, + and any bss-like regions already zeroed. It returns a null pointer +diff --git a/elf/rtld.c b/elf/rtld.c +index 5107d16fe3..a91e2a4471 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -477,6 +477,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) + GL(dl_rtld_map).l_real = &GL(dl_rtld_map); + GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; + GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; ++ GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext; + /* Copy the TLS related data if necessary. */ + #ifndef DONT_USE_BOOTSTRAP_MAP + # if NO_TLS_OFFSET != 0 +@@ -1118,6 +1119,7 @@ rtld_setup_main_map (struct link_map *main_map) + bool has_interp = false; + + main_map->l_map_end = 0; ++ main_map->l_text_end = 0; + /* Perhaps the executable has no PT_LOAD header entries at all. */ + main_map->l_map_start = ~0; + /* And it was opened directly. */ +@@ -1209,6 +1211,8 @@ rtld_setup_main_map (struct link_map *main_map) + allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz; + if (main_map->l_map_end < allocend) + main_map->l_map_end = allocend; ++ if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end) ++ main_map->l_text_end = allocend; + + /* The next expected address is the page following this load + segment. */ +@@ -1268,6 +1272,8 @@ rtld_setup_main_map (struct link_map *main_map) + = (char *) main_map->l_tls_initimage + main_map->l_addr; + if (! main_map->l_map_end) + main_map->l_map_end = ~0; ++ if (! main_map->l_text_end) ++ main_map->l_text_end = ~0; + if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name) + { + /* We were invoked directly, so the program might not have a +diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h +index d92b12a7aa..0079842d1f 100644 +--- a/elf/setup-vdso.h ++++ b/elf/setup-vdso.h +@@ -51,6 +51,9 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + l->l_addr = ph->p_vaddr; + if (ph->p_vaddr + ph->p_memsz >= l->l_map_end) + l->l_map_end = ph->p_vaddr + ph->p_memsz; ++ if ((ph->p_flags & PF_X) ++ && ph->p_vaddr + ph->p_memsz >= l->l_text_end) ++ l->l_text_end = ph->p_vaddr + ph->p_memsz; + } + else + /* There must be no TLS segment. */ +@@ -59,6 +62,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), + l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso); + l->l_addr = l->l_map_start - l->l_addr; + l->l_map_end += l->l_addr; ++ l->l_text_end += l->l_addr; + l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); + elf_get_dynamic_info (l, false, false); + _dl_setup_hash (l); +diff --git a/include/link.h b/include/link.h +index 686813f281..a02d5f2eba 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -253,6 +253,8 @@ struct link_map + /* Start and finish of memory map for this object. l_map_start + need not be the same as l_addr. */ + ElfW(Addr) l_map_start, l_map_end; ++ /* End of the executable part of the mapping. */ ++ ElfW(Addr) l_text_end; + + /* Linked list of objects in reverse ELF constructor execution + order. Head of list is stored in _dl_init_called_list. */ +-- +2.43.0 + diff --git a/packages/glibc/0029-Revert-elf-Always-call-destructors-in-reverse-constr.patch b/packages/glibc/0029-Revert-elf-Always-call-destructors-in-reverse-constr.patch new file mode 100644 index 00000000000..d57028b7fef --- /dev/null +++ b/packages/glibc/0029-Revert-elf-Always-call-destructors-in-reverse-constr.patch @@ -0,0 +1,593 @@ +From 719866ab2ff0e6d514a04fb47e507d92e70ef7ee Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Wed, 18 Oct 2023 14:25:46 +0200 +Subject: [PATCH] Revert "elf: Always call destructors in reverse constructor + order (bug 30785)" + +This reverts commit a3189f66a5f2fe86568286fa025fa153be04c6c0. + +Reason for revert: Incompatibility with existing applications. +--- + NEWS | 1 - + elf/dl-close.c | 113 ++++++++++----------------- + elf/dl-fini.c | 152 ++++++++++++++++++++++++------------- + elf/dl-init.c | 16 ---- + elf/dso-sort-tests-1.def | 19 +++-- + elf/tst-audit23.c | 44 +++++------ + sysdeps/generic/ldsodefs.h | 4 - + 7 files changed, 173 insertions(+), 176 deletions(-) + +diff --git a/NEWS b/NEWS +index bfcd46efa9..f117874e34 100644 +--- a/NEWS ++++ b/NEWS +@@ -32,7 +32,6 @@ Security related changes: + The following bugs are resolved with this release: + + [30723] posix_memalign repeatedly scans long bin lists +- [30785] Always call destructors in reverse constructor order + [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) +diff --git a/elf/dl-close.c b/elf/dl-close.c +index ea62d0e601..b887a44888 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -138,31 +138,30 @@ _dl_close_worker (struct link_map *map, bool force) + + bool any_tls = false; + const unsigned int nloaded = ns->_ns_nloaded; ++ struct link_map *maps[nloaded]; + +- /* Run over the list and assign indexes to the link maps. */ ++ /* Run over the list and assign indexes to the link maps and enter ++ them into the MAPS array. */ + int idx = 0; + for (struct link_map *l = ns->_ns_loaded; l != NULL; l = l->l_next) + { + l->l_map_used = 0; + l->l_map_done = 0; + l->l_idx = idx; ++ maps[idx] = l; + ++idx; + } + assert (idx == nloaded); + +- /* Keep marking link maps until no new link maps are found. */ +- for (struct link_map *l = ns->_ns_loaded; l != NULL; ) ++ /* Keep track of the lowest index link map we have covered already. */ ++ int done_index = -1; ++ while (++done_index < nloaded) + { +- /* next is reset to earlier link maps for remarking. */ +- struct link_map *next = l->l_next; +- int next_idx = l->l_idx + 1; /* next->l_idx, but covers next == NULL. */ ++ struct link_map *l = maps[done_index]; + + if (l->l_map_done) +- { +- /* Already handled. */ +- l = next; +- continue; +- } ++ /* Already handled. */ ++ continue; + + /* Check whether this object is still used. */ + if (l->l_type == lt_loaded +@@ -172,10 +171,7 @@ _dl_close_worker (struct link_map *map, bool force) + acquire is sufficient and correct. */ + && atomic_load_acquire (&l->l_tls_dtor_count) == 0 + && !l->l_map_used) +- { +- l = next; +- continue; +- } ++ continue; + + /* We need this object and we handle it now. */ + l->l_map_used = 1; +@@ -202,11 +198,8 @@ _dl_close_worker (struct link_map *map, bool force) + already processed it, then we need to go back + and process again from that point forward to + ensure we keep all of its dependencies also. */ +- if ((*lp)->l_idx < next_idx) +- { +- next = *lp; +- next_idx = next->l_idx; +- } ++ if ((*lp)->l_idx - 1 < done_index) ++ done_index = (*lp)->l_idx - 1; + } + } + +@@ -226,65 +219,44 @@ _dl_close_worker (struct link_map *map, bool force) + if (!jmap->l_map_used) + { + jmap->l_map_used = 1; +- if (jmap->l_idx < next_idx) +- { +- next = jmap; +- next_idx = next->l_idx; +- } ++ if (jmap->l_idx - 1 < done_index) ++ done_index = jmap->l_idx - 1; + } + } + } +- +- l = next; + } + +- /* Call the destructors in reverse constructor order, and remove the +- closed link maps from the list. */ +- for (struct link_map **init_called_head = &_dl_init_called_list; +- *init_called_head != NULL; ) ++ /* Sort the entries. We can skip looking for the binary itself which is ++ at the front of the search list for the main namespace. */ ++ _dl_sort_maps (maps, nloaded, (nsid == LM_ID_BASE), true); ++ ++ /* Call all termination functions at once. */ ++ bool unload_any = false; ++ bool scope_mem_left = false; ++ unsigned int unload_global = 0; ++ unsigned int first_loaded = ~0; ++ for (unsigned int i = 0; i < nloaded; ++i) + { +- struct link_map *imap = *init_called_head; ++ struct link_map *imap = maps[i]; + +- /* _dl_init_called_list is global, to produce a global odering. +- Ignore the other namespaces (and link maps that are still used). */ +- if (imap->l_ns != nsid || imap->l_map_used) +- init_called_head = &imap->l_init_called_next; +- else ++ /* All elements must be in the same namespace. */ ++ assert (imap->l_ns == nsid); ++ ++ if (!imap->l_map_used) + { + assert (imap->l_type == lt_loaded && !imap->l_nodelete_active); + +- /* _dl_init_called_list is updated at the same time as +- l_init_called. */ +- assert (imap->l_init_called); +- +- if (imap->l_info[DT_FINI_ARRAY] != NULL +- || imap->l_info[DT_FINI] != NULL) ++ /* Call its termination function. Do not do it for ++ half-cooked objects. Temporarily disable exception ++ handling, so that errors are fatal. */ ++ if (imap->l_init_called) + _dl_catch_exception (NULL, _dl_call_fini, imap); + + #ifdef SHARED + /* Auditing checkpoint: we remove an object. */ + _dl_audit_objclose (imap); + #endif +- /* Unlink this link map. */ +- *init_called_head = imap->l_init_called_next; +- } +- } +- +- +- bool unload_any = false; +- bool scope_mem_left = false; +- unsigned int unload_global = 0; +- +- /* For skipping un-unloadable link maps in the second loop. */ +- struct link_map *first_loaded = ns->_ns_loaded; + +- /* Iterate over the namespace to find objects to unload. Some +- unloadable objects may not be on _dl_init_called_list due to +- dlopen failure. */ +- for (struct link_map *imap = first_loaded; imap != NULL; imap = imap->l_next) +- { +- if (!imap->l_map_used) +- { + /* This object must not be used anymore. */ + imap->l_removed = 1; + +@@ -295,8 +267,8 @@ _dl_close_worker (struct link_map *map, bool force) + ++unload_global; + + /* Remember where the first dynamically loaded object is. */ +- if (first_loaded == NULL) +- first_loaded = imap; ++ if (i < first_loaded) ++ first_loaded = i; + } + /* Else imap->l_map_used. */ + else if (imap->l_type == lt_loaded) +@@ -432,8 +404,8 @@ _dl_close_worker (struct link_map *map, bool force) + imap->l_loader = NULL; + + /* Remember where the first dynamically loaded object is. */ +- if (first_loaded == NULL) +- first_loaded = imap; ++ if (i < first_loaded) ++ first_loaded = i; + } + } + +@@ -504,11 +476,10 @@ _dl_close_worker (struct link_map *map, bool force) + + /* Check each element of the search list to see if all references to + it are gone. */ +- for (struct link_map *imap = first_loaded; imap != NULL; ) ++ for (unsigned int i = first_loaded; i < nloaded; ++i) + { +- if (imap->l_map_used) +- imap = imap->l_next; +- else ++ struct link_map *imap = maps[i]; ++ if (!imap->l_map_used) + { + assert (imap->l_type == lt_loaded); + +@@ -719,9 +690,7 @@ _dl_close_worker (struct link_map *map, bool force) + if (imap == GL(dl_initfirst)) + GL(dl_initfirst) = NULL; + +- struct link_map *next = imap->l_next; + free (imap); +- imap = next; + } + } + +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index e201d36651..9acb64f47c 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -24,68 +24,116 @@ + void + _dl_fini (void) + { +- /* Call destructors strictly in the reverse order of constructors. +- This causes fewer surprises than some arbitrary reordering based +- on new (relocation) dependencies. None of the objects are +- unmapped, so applications can deal with this if their DSOs remain +- in a consistent state after destructors have run. */ +- +- /* Protect against concurrent loads and unloads. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); +- +- /* Ignore objects which are opened during shutdown. */ +- struct link_map *local_init_called_list = _dl_init_called_list; +- +- for (struct link_map *l = local_init_called_list; l != NULL; +- l = l->l_init_called_next) +- /* Bump l_direct_opencount of all objects so that they +- are not dlclose()ed from underneath us. */ +- ++l->l_direct_opencount; +- +- /* After this point, everything linked from local_init_called_list +- cannot be unloaded because of the reference counter update. */ +- __rtld_lock_unlock_recursive (GL(dl_load_lock)); +- +- /* Perform two passes: One for non-audit modules, one for audit +- modules. This way, audit modules receive unload notifications +- for non-audit objects, and the destructors for audit modules +- still run. */ ++ /* Lots of fun ahead. We have to call the destructors for all still ++ loaded objects, in all namespaces. The problem is that the ELF ++ specification now demands that dependencies between the modules ++ are taken into account. I.e., the destructor for a module is ++ called before the ones for any of its dependencies. ++ ++ To make things more complicated, we cannot simply use the reverse ++ order of the constructors. Since the user might have loaded objects ++ using `dlopen' there are possibly several other modules with its ++ dependencies to be taken into account. Therefore we have to start ++ determining the order of the modules once again from the beginning. */ ++ ++ /* We run the destructors of the main namespaces last. As for the ++ other namespaces, we pick run the destructors in them in reverse ++ order of the namespace ID. */ ++#ifdef SHARED ++ int do_audit = 0; ++ again: ++#endif ++ for (Lmid_t ns = GL(dl_nns) - 1; ns >= 0; --ns) ++ { ++ /* Protect against concurrent loads and unloads. */ ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ ++ unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded; ++ /* No need to do anything for empty namespaces or those used for ++ auditing DSOs. */ ++ if (nloaded == 0 ++#ifdef SHARED ++ || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit ++#endif ++ ) ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ else ++ { + #ifdef SHARED +- int last_pass = GLRO(dl_naudit) > 0; +- Lmid_t last_ns = -1; +- for (int do_audit = 0; do_audit <= last_pass; ++do_audit) ++ _dl_audit_activity_nsid (ns, LA_ACT_DELETE); + #endif +- for (struct link_map *l = local_init_called_list; l != NULL; +- l = l->l_init_called_next) +- { ++ ++ /* Now we can allocate an array to hold all the pointers and ++ copy the pointers in. */ ++ struct link_map *maps[nloaded]; ++ ++ unsigned int i; ++ struct link_map *l; ++ assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL); ++ for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) ++ /* Do not handle ld.so in secondary namespaces. */ ++ if (l == l->l_real) ++ { ++ assert (i < nloaded); ++ ++ maps[i] = l; ++ l->l_idx = i; ++ ++i; ++ ++ /* Bump l_direct_opencount of all objects so that they ++ are not dlclose()ed from underneath us. */ ++ ++l->l_direct_opencount; ++ } ++ assert (ns != LM_ID_BASE || i == nloaded); ++ assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); ++ unsigned int nmaps = i; ++ ++ /* Now we have to do the sorting. We can skip looking for the ++ binary itself which is at the front of the search list for ++ the main namespace. */ ++ _dl_sort_maps (maps, nmaps, (ns == LM_ID_BASE), true); ++ ++ /* We do not rely on the linked list of loaded object anymore ++ from this point on. We have our own list here (maps). The ++ various members of this list cannot vanish since the open ++ count is too high and will be decremented in this loop. So ++ we release the lock so that some code which might be called ++ from a destructor can directly or indirectly access the ++ lock. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ ++ /* 'maps' now contains the objects in the right order. Now ++ call the destructors. We have to process this array from ++ the front. */ ++ for (i = 0; i < nmaps; ++i) ++ { ++ struct link_map *l = maps[i]; ++ ++ if (l->l_init_called) ++ { ++ _dl_call_fini (l); + #ifdef SHARED +- if (GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing != do_audit) +- continue; +- +- /* Avoid back-to-back calls of _dl_audit_activity_nsid for the +- same namespace. */ +- if (last_ns != l->l_ns) +- { +- if (last_ns >= 0) +- _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); +- _dl_audit_activity_nsid (l->l_ns, LA_ACT_DELETE); +- last_ns = l->l_ns; +- } ++ /* Auditing checkpoint: another object closed. */ ++ _dl_audit_objclose (l); + #endif ++ } + +- /* There is no need to re-enable exceptions because _dl_fini +- is not called from a context where exceptions are caught. */ +- _dl_call_fini (l); ++ /* Correct the previous increment. */ ++ --l->l_direct_opencount; ++ } + + #ifdef SHARED +- /* Auditing checkpoint: another object closed. */ +- _dl_audit_objclose (l); ++ _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT); + #endif +- } ++ } ++ } + + #ifdef SHARED +- if (last_ns >= 0) +- _dl_audit_activity_nsid (last_ns, LA_ACT_CONSISTENT); ++ if (! do_audit && GLRO(dl_naudit) > 0) ++ { ++ do_audit = 1; ++ goto again; ++ } + + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS)) + _dl_debug_printf ("\nruntime linker statistics:\n" +diff --git a/elf/dl-init.c b/elf/dl-init.c +index ffd05b7806..ba4d2fdc85 100644 +--- a/elf/dl-init.c ++++ b/elf/dl-init.c +@@ -21,7 +21,6 @@ + #include + #include + +-struct link_map *_dl_init_called_list; + + static void + call_init (struct link_map *l, int argc, char **argv, char **env) +@@ -43,21 +42,6 @@ call_init (struct link_map *l, int argc, char **argv, char **env) + dependency. */ + l->l_init_called = 1; + +- /* Help an already-running dlclose: The just-loaded object must not +- be removed during the current pass. (No effect if no dlclose in +- progress.) */ +- l->l_map_used = 1; +- +- /* Record execution before starting any initializers. This way, if +- the initializers themselves call dlopen, their ELF destructors +- will eventually be run before this object is destructed, matching +- that their ELF constructors have run before this object was +- constructed. _dl_fini uses this list for audit callbacks, so +- register objects on the list even if they do not have a +- constructor. */ +- l->l_init_called_next = _dl_init_called_list; +- _dl_init_called_list = l; +- + /* Check for object which constructors we do not run here. */ + if (__builtin_expect (l->l_name[0], 'a') == '\0' + && l->l_type == lt_executable) +diff --git a/elf/dso-sort-tests-1.def b/elf/dso-sort-tests-1.def +index 61dc54f8ae..4bf9052db1 100644 +--- a/elf/dso-sort-tests-1.def ++++ b/elf/dso-sort-tests-1.def +@@ -53,14 +53,21 @@ tst-dso-ordering10: {}->a->b->c;soname({})=c + output: b>a>{}b->c->d order). ++# The older dynamic_sort=1 algorithm does not achieve this, while the DFS-based ++# dynamic_sort=2 algorithm does, although it is still arguable whether going ++# beyond spec to do this is the right thing to do. ++# The below expected outputs are what the two algorithms currently produce ++# respectively, for regression testing purposes. + tst-bz15311: {+a;+e;+f;+g;+d;%d;-d;-g;-f;-e;-a};a->b->c->d;d=>[ba];c=>a;b=>e=>a;c=>f=>b;d=>g=>c +-output: {+a[d>c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[c>b>a>];+e[e>];+f[f>];+g[g>];+d[];%d(b(e(a()))a()g(c(a()f(b(e(a()))))));-d[];-g[];-f[];-e[];-a[a1;a->a2;a2->a;b->b1;c->a1;c=>a1 +-output: {+a[a2>a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());}a1>a>];+b[b1>b>];-b[];%c(a1());} +Date: Thu, 19 Oct 2023 09:17:38 +0200 +Subject: [PATCH] Revert "elf: Move l_init_called_next to old place of + l_text_end in link map" + +This reverts commit d3ba6c1333b10680ce5900a628108507d9d4b844. + +Reason: Preserve internal ABI. +--- + include/link.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/include/link.h b/include/link.h +index a02d5f2eba..69bda3ed17 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -256,10 +256,6 @@ struct link_map + /* End of the executable part of the mapping. */ + ElfW(Addr) l_text_end; + +- /* Linked list of objects in reverse ELF constructor execution +- order. Head of list is stored in _dl_init_called_list. */ +- struct link_map *l_init_called_next; +- + /* Default array for 'l_scope'. */ + struct r_scope_elem *l_scope_mem[4]; + /* Size of array allocated for 'l_scope'. */ +@@ -282,6 +278,10 @@ struct link_map + /* List of object in order of the init and fini calls. */ + struct link_map **l_initfini; + ++ /* Linked list of objects in reverse ELF constructor execution ++ order. Head of list is stored in _dl_init_called_list. */ ++ struct link_map *l_init_called_next; ++ + /* List of the dependencies introduced through symbol binding. */ + struct link_map_reldeps + { +-- +2.43.0 + diff --git a/packages/glibc/0031-sysdeps-sem_open-Clear-O_CREAT-when-semaphore-file-i.patch b/packages/glibc/0031-sysdeps-sem_open-Clear-O_CREAT-when-semaphore-file-i.patch new file mode 100644 index 00000000000..9453bf8dc9e --- /dev/null +++ b/packages/glibc/0031-sysdeps-sem_open-Clear-O_CREAT-when-semaphore-file-i.patch @@ -0,0 +1,105 @@ +From 63dbbc5c52f9823f86270f32fce20d1e91cdf484 Mon Sep 17 00:00:00 2001 +From: Sergio Durigan Junior +Date: Wed, 1 Nov 2023 18:15:23 -0400 +Subject: [PATCH] sysdeps: sem_open: Clear O_CREAT when semaphore file is + expected to exist [BZ #30789] + +When invoking sem_open with O_CREAT as one of its flags, we'll end up +in the second part of sem_open's "if ((oflag & O_CREAT) == 0 || (oflag +& O_EXCL) == 0)", which means that we don't expect the semaphore file +to exist. + +In that part, open_flags is initialized as "O_RDWR | O_CREAT | O_EXCL +| O_CLOEXEC" and there's an attempt to open(2) the file, which will +likely fail because it won't exist. After that first (expected) +failure, some cleanup is done and we go back to the label "try_again", +which lives in the first part of the aforementioned "if". + +The problem is that, in that part of the code, we expect the semaphore +file to exist, and as such O_CREAT (this time the flag we pass to +open(2)) needs to be cleaned from open_flags, otherwise we'll see +another failure (this time unexpected) when trying to open the file, +which will lead the call to sem_open to fail as well. + +This can cause very strange bugs, especially with OpenMPI, which makes +extensive use of semaphores. + +Fix the bug by simplifying the logic when choosing open(2) flags and +making sure O_CREAT is not set when the semaphore file is expected to +exist. + +A regression test for this issue would require a complex and cpu time +consuming logic, since to trigger the wrong code path is not +straightforward due the racy condition. There is a somewhat reliable +reproducer in the bug, but it requires using OpenMPI. + +This resolves BZ #30789. + +See also: https://bugs.launchpad.net/ubuntu/+source/h5py/+bug/2031912 + +Signed-off-by: Sergio Durigan Junior +Co-Authored-By: Simon Chopin +Co-Authored-By: Adhemerval Zanella Netto +Fixes: 533deafbdf189f5fbb280c28562dd43ace2f4b0f ("Use O_CLOEXEC in more places (BZ #15722)") +(cherry picked from commit f957f47df75b9fab995754011491edebc6feb147) +--- + NEWS | 2 ++ + sysdeps/pthread/sem_open.c | 10 ++++------ + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/NEWS b/NEWS +index f117874e34..5ac488bf9b 100644 +--- a/NEWS ++++ b/NEWS +@@ -32,6 +32,8 @@ Security related changes: + The following bugs are resolved with this release: + + [30723] posix_memalign repeatedly scans long bin lists ++ [30789] sem_open will fail on multithreaded scenarios when semaphore ++ file doesn't exist (O_CREAT) + [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) +diff --git a/sysdeps/pthread/sem_open.c b/sysdeps/pthread/sem_open.c +index e5db929d20..0e331a7445 100644 +--- a/sysdeps/pthread/sem_open.c ++++ b/sysdeps/pthread/sem_open.c +@@ -32,11 +32,12 @@ + # define __unlink unlink + #endif + ++#define SEM_OPEN_FLAGS (O_RDWR | O_NOFOLLOW | O_CLOEXEC) ++ + sem_t * + __sem_open (const char *name, int oflag, ...) + { + int fd; +- int open_flags; + sem_t *result; + + /* Check that shared futexes are supported. */ +@@ -65,10 +66,8 @@ __sem_open (const char *name, int oflag, ...) + /* If the semaphore object has to exist simply open it. */ + if ((oflag & O_CREAT) == 0 || (oflag & O_EXCL) == 0) + { +- open_flags = O_RDWR | O_NOFOLLOW | O_CLOEXEC; +- open_flags |= (oflag & ~(O_CREAT|O_ACCMODE)); + try_again: +- fd = __open (dirname.name, open_flags); ++ fd = __open (dirname.name, (oflag & O_EXCL) | SEM_OPEN_FLAGS); + + if (fd == -1) + { +@@ -135,8 +134,7 @@ __sem_open (const char *name, int oflag, ...) + } + + /* Open the file. Make sure we do not overwrite anything. */ +- open_flags = O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC; +- fd = __open (tmpfname, open_flags, mode); ++ fd = __open (tmpfname, O_CREAT | O_EXCL | SEM_OPEN_FLAGS, mode); + if (fd == -1) + { + if (errno == EEXIST) +-- +2.43.0 + diff --git a/packages/glibc/0032-elf-Fix-wrong-break-removal-from-8ee878592c.patch b/packages/glibc/0032-elf-Fix-wrong-break-removal-from-8ee878592c.patch new file mode 100644 index 00000000000..f4227213ead --- /dev/null +++ b/packages/glibc/0032-elf-Fix-wrong-break-removal-from-8ee878592c.patch @@ -0,0 +1,26 @@ +From bf5aa419cbf545d2cd09dc097e518033d6e4df5e Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Thu, 7 Dec 2023 11:17:35 -0300 +Subject: [PATCH] elf: Fix wrong break removal from 8ee878592c + +Reported-by: Alexander Monakov +(cherry picked from commit 546a1ba664626603660b595662249d524e429013) +--- + elf/readelflib.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/elf/readelflib.c b/elf/readelflib.c +index f5b8c80e38..64f1d662a9 100644 +--- a/elf/readelflib.c ++++ b/elf/readelflib.c +@@ -107,6 +107,7 @@ process_elf_file (const char *file_name, const char *lib, int *flag, + case PT_INTERP: + program_interpreter = (char *) (file_contents + segment->p_offset); + check_ptr (program_interpreter); ++ break; + + case PT_GNU_PROPERTY: + /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes +-- +2.43.0 + diff --git a/packages/glibc/0033-LoongArch-Delete-excessively-allocated-memory.patch b/packages/glibc/0033-LoongArch-Delete-excessively-allocated-memory.patch new file mode 100644 index 00000000000..d8ccd906a84 --- /dev/null +++ b/packages/glibc/0033-LoongArch-Delete-excessively-allocated-memory.patch @@ -0,0 +1,109 @@ +From 44f757a6364a546359809d48c76b3debd26e77d4 Mon Sep 17 00:00:00 2001 +From: caiyinyu +Date: Thu, 26 Oct 2023 17:27:21 +0800 +Subject: [PATCH] LoongArch: Delete excessively allocated memory. + +Backported from glibc 2.39 development. +--- + sysdeps/loongarch/dl-trampoline.h | 68 +++++++++++++++---------------- + 1 file changed, 34 insertions(+), 34 deletions(-) + +diff --git a/sysdeps/loongarch/dl-trampoline.h b/sysdeps/loongarch/dl-trampoline.h +index 02375286f8..99fcacab76 100644 +--- a/sysdeps/loongarch/dl-trampoline.h ++++ b/sysdeps/loongarch/dl-trampoline.h +@@ -19,9 +19,9 @@ + /* Assembler veneer called from the PLT header code for lazy loading. + The PLT header passes its own args in t0-t2. */ + #ifdef USE_LASX +-# define FRAME_SIZE (-((-9 * SZREG - 8 * SZFREG - 8 * SZXREG) & ALMASK)) ++# define FRAME_SIZE (-((-9 * SZREG - 8 * SZXREG) & ALMASK)) + #elif defined USE_LSX +-# define FRAME_SIZE (-((-9 * SZREG - 8 * SZFREG - 8 * SZVREG) & ALMASK)) ++# define FRAME_SIZE (-((-9 * SZREG - 8 * SZVREG) & ALMASK)) + #elif !defined __loongarch_soft_float + # define FRAME_SIZE (-((-9 * SZREG - 8 * SZFREG) & ALMASK)) + #else +@@ -44,23 +44,23 @@ ENTRY (_dl_runtime_resolve) + REG_S a7, sp, 8*SZREG + + #ifdef USE_LASX +- xvst xr0, sp, 9*SZREG + 8*SZFREG + 0*SZXREG +- xvst xr1, sp, 9*SZREG + 8*SZFREG + 1*SZXREG +- xvst xr2, sp, 9*SZREG + 8*SZFREG + 2*SZXREG +- xvst xr3, sp, 9*SZREG + 8*SZFREG + 3*SZXREG +- xvst xr4, sp, 9*SZREG + 8*SZFREG + 4*SZXREG +- xvst xr5, sp, 9*SZREG + 8*SZFREG + 5*SZXREG +- xvst xr6, sp, 9*SZREG + 8*SZFREG + 6*SZXREG +- xvst xr7, sp, 9*SZREG + 8*SZFREG + 7*SZXREG ++ xvst xr0, sp, 9*SZREG + 0*SZXREG ++ xvst xr1, sp, 9*SZREG + 1*SZXREG ++ xvst xr2, sp, 9*SZREG + 2*SZXREG ++ xvst xr3, sp, 9*SZREG + 3*SZXREG ++ xvst xr4, sp, 9*SZREG + 4*SZXREG ++ xvst xr5, sp, 9*SZREG + 5*SZXREG ++ xvst xr6, sp, 9*SZREG + 6*SZXREG ++ xvst xr7, sp, 9*SZREG + 7*SZXREG + #elif defined USE_LSX +- vst vr0, sp, 9*SZREG + 8*SZFREG + 0*SZVREG +- vst vr1, sp, 9*SZREG + 8*SZFREG + 1*SZVREG +- vst vr2, sp, 9*SZREG + 8*SZFREG + 2*SZVREG +- vst vr3, sp, 9*SZREG + 8*SZFREG + 3*SZVREG +- vst vr4, sp, 9*SZREG + 8*SZFREG + 4*SZVREG +- vst vr5, sp, 9*SZREG + 8*SZFREG + 5*SZVREG +- vst vr6, sp, 9*SZREG + 8*SZFREG + 6*SZVREG +- vst vr7, sp, 9*SZREG + 8*SZFREG + 7*SZVREG ++ vst vr0, sp, 9*SZREG + 0*SZVREG ++ vst vr1, sp, 9*SZREG + 1*SZVREG ++ vst vr2, sp, 9*SZREG + 2*SZVREG ++ vst vr3, sp, 9*SZREG + 3*SZVREG ++ vst vr4, sp, 9*SZREG + 4*SZVREG ++ vst vr5, sp, 9*SZREG + 5*SZVREG ++ vst vr6, sp, 9*SZREG + 6*SZVREG ++ vst vr7, sp, 9*SZREG + 7*SZVREG + #elif !defined __loongarch_soft_float + FREG_S fa0, sp, 9*SZREG + 0*SZFREG + FREG_S fa1, sp, 9*SZREG + 1*SZFREG +@@ -92,23 +92,23 @@ ENTRY (_dl_runtime_resolve) + REG_L a7, sp, 8*SZREG + + #ifdef USE_LASX +- xvld xr0, sp, 9*SZREG + 8*SZFREG + 0*SZXREG +- xvld xr1, sp, 9*SZREG + 8*SZFREG + 1*SZXREG +- xvld xr2, sp, 9*SZREG + 8*SZFREG + 2*SZXREG +- xvld xr3, sp, 9*SZREG + 8*SZFREG + 3*SZXREG +- xvld xr4, sp, 9*SZREG + 8*SZFREG + 4*SZXREG +- xvld xr5, sp, 9*SZREG + 8*SZFREG + 5*SZXREG +- xvld xr6, sp, 9*SZREG + 8*SZFREG + 6*SZXREG +- xvld xr7, sp, 9*SZREG + 8*SZFREG + 7*SZXREG ++ xvld xr0, sp, 9*SZREG + 0*SZXREG ++ xvld xr1, sp, 9*SZREG + 1*SZXREG ++ xvld xr2, sp, 9*SZREG + 2*SZXREG ++ xvld xr3, sp, 9*SZREG + 3*SZXREG ++ xvld xr4, sp, 9*SZREG + 4*SZXREG ++ xvld xr5, sp, 9*SZREG + 5*SZXREG ++ xvld xr6, sp, 9*SZREG + 6*SZXREG ++ xvld xr7, sp, 9*SZREG + 7*SZXREG + #elif defined USE_LSX +- vld vr0, sp, 9*SZREG + 8*SZFREG + 0*SZVREG +- vld vr1, sp, 9*SZREG + 8*SZFREG + 1*SZVREG +- vld vr2, sp, 9*SZREG + 8*SZFREG + 2*SZVREG +- vld vr3, sp, 9*SZREG + 8*SZFREG + 3*SZVREG +- vld vr4, sp, 9*SZREG + 8*SZFREG + 4*SZVREG +- vld vr5, sp, 9*SZREG + 8*SZFREG + 5*SZVREG +- vld vr6, sp, 9*SZREG + 8*SZFREG + 6*SZVREG +- vld vr7, sp, 9*SZREG + 8*SZFREG + 7*SZVREG ++ vld vr0, sp, 9*SZREG + 0*SZVREG ++ vld vr1, sp, 9*SZREG + 1*SZVREG ++ vld vr2, sp, 9*SZREG + 2*SZVREG ++ vld vr3, sp, 9*SZREG + 3*SZVREG ++ vld vr4, sp, 9*SZREG + 4*SZVREG ++ vld vr5, sp, 9*SZREG + 5*SZVREG ++ vld vr6, sp, 9*SZREG + 6*SZVREG ++ vld vr7, sp, 9*SZREG + 7*SZVREG + #elif !defined __loongarch_soft_float + FREG_L fa0, sp, 9*SZREG + 0*SZFREG + FREG_L fa1, sp, 9*SZREG + 1*SZFREG +-- +2.43.0 + diff --git a/packages/glibc/0034-elf-Fix-TLS-modid-reuse-generation-assignment-BZ-290.patch b/packages/glibc/0034-elf-Fix-TLS-modid-reuse-generation-assignment-BZ-290.patch new file mode 100644 index 00000000000..1f4b8341bae --- /dev/null +++ b/packages/glibc/0034-elf-Fix-TLS-modid-reuse-generation-assignment-BZ-290.patch @@ -0,0 +1,53 @@ +From ccdc4cba07684fe1397e1f5f134a0a827af98c04 Mon Sep 17 00:00:00 2001 +From: Hector Martin +Date: Tue, 28 Nov 2023 15:23:07 +0900 +Subject: [PATCH] elf: Fix TLS modid reuse generation assignment (BZ 29039) + +_dl_assign_tls_modid() assigns a slotinfo entry for a new module, but +does *not* do anything to the generation counter. The first time this +happens, the generation is zero and map_generation() returns the current +generation to be used during relocation processing. However, if +a slotinfo entry is later reused, it will already have a generation +assigned. If this generation has fallen behind the current global max +generation, then this causes an obsolete generation to be assigned +during relocation processing, as map_generation() returns this +generation if nonzero. _dl_add_to_slotinfo() eventually resets the +generation, but by then it is too late. This causes DTV updates to be +skipped, leading to NULL or broken TLS slot pointers and segfaults. + +Fix this by resetting the generation to zero in _dl_assign_tls_modid(), +so it behaves the same as the first time a slot is assigned. +_dl_add_to_slotinfo() will still assign the correct static generation +later during module load, but relocation processing will no longer use +an obsolete generation. + +Note that slotinfo entry (aka modid) reuse typically happens after a +dlclose and only TLS access via dynamic tlsdesc is affected. Because +tlsdesc is optimized to use the optional part of static TLS, dynamic +tlsdesc can be avoided by increasing the glibc.rtld.optional_static_tls +tunable to a large enough value, or by LD_PRELOAD-ing the affected +modules. + +Fixes bug 29039. + +Reviewed-by: Szabolcs Nagy +(cherry picked from commit 3921c5b40f293c57cb326f58713c924b0662ef59) +--- + elf/dl-tls.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/elf/dl-tls.c b/elf/dl-tls.c +index 99b83ca696..1f6f820819 100644 +--- a/elf/dl-tls.c ++++ b/elf/dl-tls.c +@@ -154,6 +154,7 @@ _dl_assign_tls_modid (struct link_map *l) + { + /* Mark the entry as used, so any dependency see it. */ + atomic_store_relaxed (&runp->slotinfo[result - disp].map, l); ++ atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0); + break; + } + +-- +2.43.0 + diff --git a/packages/glibc/0035-elf-Add-TLS-modid-reuse-test-for-bug-29039.patch b/packages/glibc/0035-elf-Add-TLS-modid-reuse-test-for-bug-29039.patch new file mode 100644 index 00000000000..f81fffd3425 --- /dev/null +++ b/packages/glibc/0035-elf-Add-TLS-modid-reuse-test-for-bug-29039.patch @@ -0,0 +1,208 @@ +From 0de9082ed8d8f149ca87d569a73692046e236c18 Mon Sep 17 00:00:00 2001 +From: Szabolcs Nagy +Date: Wed, 29 Nov 2023 11:31:37 +0000 +Subject: [PATCH] elf: Add TLS modid reuse test for bug 29039 + +This is a minimal regression test for bug 29039 which only affects +targets with TLSDESC and a reproducer requires that + +1) Have modid gaps (closed modules) with old generation. +2) Update a DTV to a newer generation (needs a newer dlopen). +3) But do not update the closed gap entry in that DTV. +4) Reuse the modid gap for a new module (another dlopen). +5) Use dynamic TLSDESC in that new module with old generation (bug). +6) Access TLS via this TLSDESC and the now outdated DTV. + +However step (3) in practice rarely happens: during DTV update the +entries for closed modids are initialized to "unallocated" and then +dynamic TLSDESC calls __tls_get_addr independently of its generation. +The only exception to this is DTV setup at thread creation (gaps are +initialized to NULL instead of unallocated) or DTV resize where the +gap entries are outside the previous DTV array (again NULL instead +of unallocated, and this requires loading > DTV_SURPLUS modules). + +So the bug can only cause NULL (+ offset) dereference, not use after +free. And the easiest way to get (3) is via thread creation. + +Note that step (5) requires that the newly loaded module has larger +TLS than the remaining optional static TLS. And for (6) there cannot +be other TLS access or dlopen in the thread that updates the DTV. + +Tested on aarch64-linux-gnu. + +Reviewed-by: Adhemerval Zanella +(cherry picked from commit 980450f12685326729d63ff72e93a996113bf073) +--- + elf/Makefile | 15 +++++++ + elf/tst-tlsgap-mod0.c | 2 + + elf/tst-tlsgap-mod1.c | 2 + + elf/tst-tlsgap-mod2.c | 2 + + elf/tst-tlsgap.c | 92 +++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 113 insertions(+) + create mode 100644 elf/tst-tlsgap-mod0.c + create mode 100644 elf/tst-tlsgap-mod1.c + create mode 100644 elf/tst-tlsgap-mod2.c + create mode 100644 elf/tst-tlsgap.c + +diff --git a/elf/Makefile b/elf/Makefile +index c00e2ccfc5..1a05a6aaca 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -459,6 +459,7 @@ tests += \ + tst-tls21 \ + tst-tlsalign \ + tst-tlsalign-extern \ ++ tst-tlsgap \ + tst-unique1 \ + tst-unique2 \ + tst-unwind-ctor \ +@@ -883,6 +884,9 @@ modules-names += \ + tst-tls20mod-bad \ + tst-tls21mod \ + tst-tlsalign-lib \ ++ tst-tlsgap-mod0 \ ++ tst-tlsgap-mod1 \ ++ tst-tlsgap-mod2 \ + tst-tlsmod1 \ + tst-tlsmod10 \ + tst-tlsmod11 \ +@@ -3009,3 +3013,14 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed + $(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so + $(objpfx)tst-dlclose-lazy.out: \ + $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so ++ ++$(objpfx)tst-tlsgap: $(shared-thread-library) ++$(objpfx)tst-tlsgap.out: \ ++ $(objpfx)tst-tlsgap-mod0.so \ ++ $(objpfx)tst-tlsgap-mod1.so \ ++ $(objpfx)tst-tlsgap-mod2.so ++ifeq (yes,$(have-mtls-dialect-gnu2)) ++CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2 ++CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2 ++endif +diff --git a/elf/tst-tlsgap-mod0.c b/elf/tst-tlsgap-mod0.c +new file mode 100644 +index 0000000000..1478b0beac +--- /dev/null ++++ b/elf/tst-tlsgap-mod0.c +@@ -0,0 +1,2 @@ ++int __thread tls0; ++int *f0(void) { return &tls0; } +diff --git a/elf/tst-tlsgap-mod1.c b/elf/tst-tlsgap-mod1.c +new file mode 100644 +index 0000000000..b10fc3702c +--- /dev/null ++++ b/elf/tst-tlsgap-mod1.c +@@ -0,0 +1,2 @@ ++int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2. */ ++int *f1(void) { return tls1; } +diff --git a/elf/tst-tlsgap-mod2.c b/elf/tst-tlsgap-mod2.c +new file mode 100644 +index 0000000000..166c27d7f3 +--- /dev/null ++++ b/elf/tst-tlsgap-mod2.c +@@ -0,0 +1,2 @@ ++int __thread tls2; ++int *f2(void) { return &tls2; } +diff --git a/elf/tst-tlsgap.c b/elf/tst-tlsgap.c +new file mode 100644 +index 0000000000..4932885076 +--- /dev/null ++++ b/elf/tst-tlsgap.c +@@ -0,0 +1,92 @@ ++/* TLS modid gap reuse regression test for bug 29039. ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void *mod[3]; ++#define MOD(i) "tst-tlsgap-mod" #i ".so" ++static const char *modname[3] = { MOD(0), MOD(1), MOD(2) }; ++#undef MOD ++ ++static void ++open_mod (int i) ++{ ++ mod[i] = xdlopen (modname[i], RTLD_LAZY); ++ printf ("open %s\n", modname[i]); ++} ++ ++static void ++close_mod (int i) ++{ ++ xdlclose (mod[i]); ++ mod[i] = NULL; ++ printf ("close %s\n", modname[i]); ++} ++ ++static void ++access_mod (int i, const char *sym) ++{ ++ int *(*f) (void) = xdlsym (mod[i], sym); ++ int *p = f (); ++ printf ("access %s: %s() = %p\n", modname[i], sym, p); ++ TEST_VERIFY_EXIT (p != NULL); ++ ++*p; ++} ++ ++static void * ++start (void *arg) ++{ ++ /* The DTV generation is at the last dlopen of mod0 and the ++ entry for mod1 is NULL. */ ++ ++ open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */ ++ ++ /* DTV is unchanged: dlopen only updates the DTV to the latest ++ generation if static TLS is allocated for a loaded module. ++ ++ With bug 29039, the TLSDESC relocation in mod1 uses the old ++ dlclose generation of mod1 instead of the new dlopen one so ++ DTV is not updated on TLS access. */ ++ ++ access_mod (1, "f1"); ++ ++ return arg; ++} ++ ++static int ++do_test (void) ++{ ++ open_mod (0); ++ open_mod (1); ++ open_mod (2); ++ close_mod (0); ++ close_mod (1); /* Create modid gap at mod1. */ ++ open_mod (0); /* Reuse modid of mod0, bump generation count. */ ++ ++ /* Create a thread where DTV of mod1 is NULL. */ ++ pthread_t t = xpthread_create (NULL, start, NULL); ++ xpthread_join (t); ++ return 0; ++} ++ ++#include +-- +2.43.0 + diff --git a/packages/glibc/0036-x86-64-Fix-the-dtv-field-load-for-x32-BZ-31184.patch b/packages/glibc/0036-x86-64-Fix-the-dtv-field-load-for-x32-BZ-31184.patch new file mode 100644 index 00000000000..b26b8626a2a --- /dev/null +++ b/packages/glibc/0036-x86-64-Fix-the-dtv-field-load-for-x32-BZ-31184.patch @@ -0,0 +1,68 @@ +From 35ea7549751d4f13a28c732e6ad68204f5e60a06 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 20 Dec 2023 16:31:43 -0800 +Subject: [PATCH] x86-64: Fix the dtv field load for x32 [BZ #31184] + +On x32, I got + +FAIL: elf/tst-tlsgap + +$ gdb elf/tst-tlsgap +... +open tst-tlsgap-mod1.so + +Thread 2 "tst-tlsgap" received signal SIGSEGV, Segmentation fault. +[Switching to LWP 2268754] +_dl_tlsdesc_dynamic () at ../sysdeps/x86_64/dl-tlsdesc.S:108 +108 movq (%rsi), %rax +(gdb) p/x $rsi +$4 = 0xf7dbf9005655fb18 +(gdb) + +This is caused by + +_dl_tlsdesc_dynamic: + _CET_ENDBR + /* Preserve call-clobbered registers that we modify. + We need two scratch regs anyway. */ + movq %rsi, -16(%rsp) + movq %fs:DTV_OFFSET, %rsi + +Since the dtv field in TCB is a pointer, %fs:DTV_OFFSET is a 32-bit +location, not 64-bit. Load the dtv field to RSI_LP instead of rsi. +This fixes BZ #31184. + +(cherry picked from commit 3502440397bbb840e2f7223734aa5cc2cc0e29b6) +--- + NEWS | 1 + + sysdeps/x86_64/dl-tlsdesc.S | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/NEWS b/NEWS +index 5ac488bf9b..71057e4793 100644 +--- a/NEWS ++++ b/NEWS +@@ -37,6 +37,7 @@ The following bugs are resolved with this release: + [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) ++ [31184] FAIL: elf/tst-tlsgap + + + Version 2.38 +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index 5593897e29..c4823547d7 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -102,7 +102,7 @@ _dl_tlsdesc_dynamic: + /* Preserve call-clobbered registers that we modify. + We need two scratch regs anyway. */ + movq %rsi, -16(%rsp) +- movq %fs:DTV_OFFSET, %rsi ++ mov %fs:DTV_OFFSET, %RSI_LP + movq %rdi, -8(%rsp) + movq TLSDESC_ARG(%rax), %rdi + movq (%rsi), %rax +-- +2.43.0 + diff --git a/packages/glibc/0037-x86-64-Fix-the-tcb-field-load-for-x32-BZ-31185.patch b/packages/glibc/0037-x86-64-Fix-the-tcb-field-load-for-x32-BZ-31185.patch new file mode 100644 index 00000000000..ffbf07a78c8 --- /dev/null +++ b/packages/glibc/0037-x86-64-Fix-the-tcb-field-load-for-x32-BZ-31185.patch @@ -0,0 +1,69 @@ +From 968c983d43bc51f719f3e7a0fcb1bb8669b5f7c4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Wed, 20 Dec 2023 19:42:12 -0800 +Subject: [PATCH] x86-64: Fix the tcb field load for x32 [BZ #31185] + +_dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic access the thread pointer +via the tcb field in TCB: + +_dl_tlsdesc_undefweak: + _CET_ENDBR + movq 8(%rax), %rax + subq %fs:0, %rax + ret + +_dl_tlsdesc_dynamic: + ... + subq %fs:0, %rax + movq -8(%rsp), %rdi + ret + +Since the tcb field in TCB is a pointer, %fs:0 is a 32-bit location, +not 64-bit. It should use "sub %fs:0, %RAX_LP" instead. Since +_dl_tlsdesc_undefweak returns ptrdiff_t and _dl_make_tlsdesc_dynamic +returns void *, RAX_LP is appropriate here for x32 and x86-64. This +fixes BZ #31185. + +(cherry picked from commit 81be2a61dafc168327c1639e97b6dae128c7ccf3) +--- + NEWS | 1 + + sysdeps/x86_64/dl-tlsdesc.S | 4 ++-- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/NEWS b/NEWS +index 71057e4793..6fbb8a9e1d 100644 +--- a/NEWS ++++ b/NEWS +@@ -38,6 +38,7 @@ The following bugs are resolved with this release: + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) + [31184] FAIL: elf/tst-tlsgap ++ [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic + + + Version 2.38 +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index c4823547d7..4579424bf7 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -61,7 +61,7 @@ _dl_tlsdesc_return: + _dl_tlsdesc_undefweak: + _CET_ENDBR + movq 8(%rax), %rax +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + ret + cfi_endproc + .size _dl_tlsdesc_undefweak, .-_dl_tlsdesc_undefweak +@@ -116,7 +116,7 @@ _dl_tlsdesc_dynamic: + addq TLSDESC_MODOFF(%rdi), %rax + .Lret: + movq -16(%rsp), %rsi +- subq %fs:0, %rax ++ sub %fs:0, %RAX_LP + movq -8(%rsp), %rdi + ret + .Lslow: +-- +2.43.0 + diff --git a/packages/glibc/0038-NEWS-Mention-bug-fixes-for-29039-30694-30709-30721.patch b/packages/glibc/0038-NEWS-Mention-bug-fixes-for-29039-30694-30709-30721.patch new file mode 100644 index 00000000000..a047469de64 --- /dev/null +++ b/packages/glibc/0038-NEWS-Mention-bug-fixes-for-29039-30694-30709-30721.patch @@ -0,0 +1,27 @@ +From d25e2c8d5cb0778ae87ad43b1f4c301abe5a932b Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 23 Dec 2023 06:24:41 -0800 +Subject: [PATCH] NEWS: Mention bug fixes for 29039/30694/30709/30721 + +--- + NEWS | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/NEWS b/NEWS +index 6fbb8a9e1d..db4d6c8373 100644 +--- a/NEWS ++++ b/NEWS +@@ -31,6 +31,10 @@ Security related changes: + + The following bugs are resolved with this release: + ++ [29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS ++ [30694] The iconv program no longer tells the user which given encoding name was wrong ++ [30709] nscd fails to build with cleanup handler if built with -fexceptions ++ [30721] x86_64: Fix build with --disable-multiarch + [30723] posix_memalign repeatedly scans long bin lists + [30789] sem_open will fail on multithreaded scenarios when semaphore + file doesn't exist (O_CREAT) +-- +2.43.0 + diff --git a/packages/glibc/0039-NEWS-Mention-bug-fixes-for-30745-30843.patch b/packages/glibc/0039-NEWS-Mention-bug-fixes-for-30745-30843.patch new file mode 100644 index 00000000000..70c22bf9e17 --- /dev/null +++ b/packages/glibc/0039-NEWS-Mention-bug-fixes-for-30745-30843.patch @@ -0,0 +1,30 @@ +From 27339a3eb8f987eebae72b854af80256c1588ebd Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Sat, 23 Dec 2023 06:27:50 -0800 +Subject: [PATCH] NEWS: Mention bug fixes for 30745/30843 + +--- + NEWS | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/NEWS b/NEWS +index db4d6c8373..905230b838 100644 +--- a/NEWS ++++ b/NEWS +@@ -36,11 +36,13 @@ The following bugs are resolved with this release: + [30709] nscd fails to build with cleanup handler if built with -fexceptions + [30721] x86_64: Fix build with --disable-multiarch + [30723] posix_memalign repeatedly scans long bin lists ++ [30745] Slight bug in cache info codes for x86 + [30789] sem_open will fail on multithreaded scenarios when semaphore + file doesn't exist (O_CREAT) + [30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) ++ [30843] potential use-after-free in getcanonname (CVE-2023-4806) + [31184] FAIL: elf/tst-tlsgap + [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic + +-- +2.43.0 + diff --git a/packages/glibc/0040-getaddrinfo-translate-ENOMEM-to-EAI_MEMORY-bug-31163.patch b/packages/glibc/0040-getaddrinfo-translate-ENOMEM-to-EAI_MEMORY-bug-31163.patch new file mode 100644 index 00000000000..81818522567 --- /dev/null +++ b/packages/glibc/0040-getaddrinfo-translate-ENOMEM-to-EAI_MEMORY-bug-31163.patch @@ -0,0 +1,36 @@ +From ae1e5217021e43e1f2de443d26e87ea3adfb221c Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Wed, 6 Dec 2023 14:48:22 +0100 +Subject: [PATCH] getaddrinfo: translate ENOMEM to EAI_MEMORY (bug 31163) + +When __resolv_context_get returns NULL due to out of memory, translate it +to a return value of EAI_MEMORY. + +(cherry picked from commit 5eabdb6a6ac1599d23dd5966a37417215950245f) +--- + sysdeps/posix/getaddrinfo.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c +index 13082305d3..da573bea24 100644 +--- a/sysdeps/posix/getaddrinfo.c ++++ b/sysdeps/posix/getaddrinfo.c +@@ -616,7 +616,14 @@ get_nss_addresses (const char *name, const struct addrinfo *req, + function variant. */ + res_ctx = __resolv_context_get (); + if (res_ctx == NULL) +- no_more = 1; ++ { ++ if (errno == ENOMEM) ++ { ++ result = -EAI_MEMORY; ++ goto out; ++ } ++ no_more = 1; ++ } + + while (!no_more) + { +-- +2.43.0 + diff --git a/packages/glibc/0041-libio-Check-remaining-buffer-size-in-_IO_wdo_write-b.patch b/packages/glibc/0041-libio-Check-remaining-buffer-size-in-_IO_wdo_write-b.patch new file mode 100644 index 00000000000..98bb72f7cbe --- /dev/null +++ b/packages/glibc/0041-libio-Check-remaining-buffer-size-in-_IO_wdo_write-b.patch @@ -0,0 +1,48 @@ +From cfe121910013a46e2477562282c56ae8062089aa Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 2 Jan 2024 14:36:17 +0100 +Subject: [PATCH] libio: Check remaining buffer size in _IO_wdo_write (bug + 31183) + +The multibyte character needs to fit into the remaining buffer space, +not the already-written buffer space. Without the fix, we were never +moving the write pointer from the start of the buffer, always using +the single-character fallback buffer. + +Fixes commit 04b76b5aa8b2d1d19066e42dd1 ("Don't error out writing +a multibyte character to an unbuffered stream (bug 17522)"). + +(cherry picked from commit ecc7c3deb9f347649c2078fcc0f94d4cedf92d60) +--- + NEWS | 1 + + libio/wfileops.c | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/NEWS b/NEWS +index 905230b838..6768c2da6f 100644 +--- a/NEWS ++++ b/NEWS +@@ -43,6 +43,7 @@ The following bugs are resolved with this release: + -D_FILE_OFFSET_BITS=64 + [30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527) + [30843] potential use-after-free in getcanonname (CVE-2023-4806) ++ [31183] Wide stream buffer size reduced MB_LEN_MAX bytes after bug 17522 fix + [31184] FAIL: elf/tst-tlsgap + [31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic + +diff --git a/libio/wfileops.c b/libio/wfileops.c +index f16f6db1c3..9ab8f2e7f3 100644 +--- a/libio/wfileops.c ++++ b/libio/wfileops.c +@@ -55,7 +55,7 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do) + char mb_buf[MB_LEN_MAX]; + char *write_base, *write_ptr, *buf_end; + +- if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf)) ++ if (fp->_IO_buf_end - fp->_IO_write_ptr < sizeof (mb_buf)) + { + /* Make sure we have room for at least one multibyte + character. */ +-- +2.43.0 + diff --git a/packages/glibc/0042-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch b/packages/glibc/0042-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch new file mode 100644 index 00000000000..653145dd7af --- /dev/null +++ b/packages/glibc/0042-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch @@ -0,0 +1,181 @@ +From 23514c72b780f3da097ecf33a793b7ba9c2070d2 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Mon, 15 Jan 2024 17:44:43 +0100 +Subject: [PATCH] syslog: Fix heap buffer overflow in __vsyslog_internal + (CVE-2023-6246) + +__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER +containing a long program name failed to update the required buffer +size, leading to the allocation and overflow of a too-small buffer on +the heap. This commit fixes that. It also adds a new regression test +that uses glibc.malloc.check. + +Reviewed-by: Adhemerval Zanella +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +(cherry picked from commit 6bd0e4efcc78f3c0115e5ea9739a1642807450da) +--- + misc/Makefile | 8 ++- + misc/syslog.c | 50 +++++++++++++------ + misc/tst-syslog-long-progname.c | 39 +++++++++++++++ + .../postclean.req | 0 + 4 files changed, 82 insertions(+), 15 deletions(-) + create mode 100644 misc/tst-syslog-long-progname.c + create mode 100644 misc/tst-syslog-long-progname.root/postclean.req + +diff --git a/misc/Makefile b/misc/Makefile +index fe0d49c1de..90b31952c5 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -289,7 +289,10 @@ tests-special += $(objpfx)tst-error1-mem.out \ + $(objpfx)tst-allocate_once-mem.out + endif + +-tests-container := tst-syslog ++tests-container := \ ++ tst-syslog \ ++ tst-syslog-long-progname \ ++ # tests-container + + CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables + CFLAGS-tsearch.c += $(uses-callbacks) +@@ -351,6 +354,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \ + $(evaluate-test) + ++tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \ ++ LD_PRELOAD=libc_malloc_debug.so.0 ++ + $(objpfx)tst-select: $(librt) + $(objpfx)tst-select-time64: $(librt) + $(objpfx)tst-pselect: $(librt) +diff --git a/misc/syslog.c b/misc/syslog.c +index 1b8cb722c5..814d224a1e 100644 +--- a/misc/syslog.c ++++ b/misc/syslog.c +@@ -124,8 +124,9 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + { + /* Try to use a static buffer as an optimization. */ + char bufs[1024]; +- char *buf = NULL; +- size_t bufsize = 0; ++ char *buf = bufs; ++ size_t bufsize; ++ + int msgoff; + int saved_errno = errno; + +@@ -177,29 +178,50 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + #define SYSLOG_HEADER_WITHOUT_TS(__pri, __msgoff) \ + "<%d>: %n", __pri, __msgoff + +- int l; ++ int l, vl; + if (has_ts) + l = __snprintf (bufs, sizeof bufs, + SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + else + l = __snprintf (bufs, sizeof bufs, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ ++ char *pos; ++ size_t len; ++ + if (0 <= l && l < sizeof bufs) + { +- va_list apc; +- va_copy (apc, ap); ++ /* At this point, there is still a chance that we can print the ++ remaining part of the log into bufs and use that. */ ++ pos = bufs + l; ++ len = sizeof (bufs) - l; ++ } ++ else ++ { ++ buf = NULL; ++ /* We already know that bufs is too small to use for this log message. ++ The next vsnprintf into bufs is used only to calculate the total ++ required buffer length. We will discard bufs contents and allocate ++ an appropriately sized buffer later instead. */ ++ pos = bufs; ++ len = sizeof (bufs); ++ } + +- /* Restore errno for %m format. */ +- __set_errno (saved_errno); ++ { ++ va_list apc; ++ va_copy (apc, ap); + +- int vl = __vsnprintf_internal (bufs + l, sizeof bufs - l, fmt, apc, +- mode_flags); +- if (0 <= vl && vl < sizeof bufs - l) +- buf = bufs; +- bufsize = l + vl; ++ /* Restore errno for %m format. */ ++ __set_errno (saved_errno); + +- va_end (apc); +- } ++ vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); ++ ++ if (!(0 <= vl && vl < len)) ++ buf = NULL; ++ ++ bufsize = l + vl; ++ va_end (apc); ++ } + + if (buf == NULL) + { +diff --git a/misc/tst-syslog-long-progname.c b/misc/tst-syslog-long-progname.c +new file mode 100644 +index 0000000000..88f37a8a00 +--- /dev/null ++++ b/misc/tst-syslog-long-progname.c +@@ -0,0 +1,39 @@ ++/* Test heap buffer overflow in syslog with long __progname (CVE-2023-6246) ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ . */ ++ ++#include ++#include ++ ++extern char * __progname; ++ ++static int ++do_test (void) ++{ ++ char long_progname[2048]; ++ ++ memset (long_progname, 'X', sizeof (long_progname) - 1); ++ long_progname[sizeof (long_progname) - 1] = '\0'; ++ ++ __progname = long_progname; ++ ++ syslog (LOG_INFO, "Hello, World!"); ++ ++ return 0; ++} ++ ++#include +diff --git a/misc/tst-syslog-long-progname.root/postclean.req b/misc/tst-syslog-long-progname.root/postclean.req +new file mode 100644 +index 0000000000..e69de29bb2 +-- +2.43.0 + diff --git a/packages/glibc/0043-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch b/packages/glibc/0043-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch new file mode 100644 index 00000000000..3c40e6c133c --- /dev/null +++ b/packages/glibc/0043-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch @@ -0,0 +1,106 @@ +From d0338312aace5bbfef85e03055e1212dd0e49578 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Mon, 15 Jan 2024 17:44:44 +0100 +Subject: [PATCH] syslog: Fix heap buffer overflow in __vsyslog_internal + (CVE-2023-6779) + +__vsyslog_internal used the return value of snprintf/vsnprintf to +calculate buffer sizes for memory allocation. If these functions (for +any reason) failed and returned -1, the resulting buffer would be too +small to hold output. This commit fixes that. + +All snprintf/vsnprintf calls are checked for negative return values and +the function silently returns upon encountering them. + +Reviewed-by: Carlos O'Donell +(cherry picked from commit 7e5a0c286da33159d47d0122007aac016f3e02cd) +--- + misc/syslog.c | 39 ++++++++++++++++++++++++++++----------- + 1 file changed, 28 insertions(+), 11 deletions(-) + +diff --git a/misc/syslog.c b/misc/syslog.c +index 814d224a1e..53440e47ad 100644 +--- a/misc/syslog.c ++++ b/misc/syslog.c +@@ -185,11 +185,13 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + else + l = __snprintf (bufs, sizeof bufs, + SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ if (l < 0) ++ goto out; + + char *pos; + size_t len; + +- if (0 <= l && l < sizeof bufs) ++ if (l < sizeof bufs) + { + /* At this point, there is still a chance that we can print the + remaining part of the log into bufs and use that. */ +@@ -215,12 +217,15 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + __set_errno (saved_errno); + + vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); ++ va_end (apc); ++ ++ if (vl < 0) ++ goto out; + +- if (!(0 <= vl && vl < len)) ++ if (vl >= len) + buf = NULL; + + bufsize = l + vl; +- va_end (apc); + } + + if (buf == NULL) +@@ -231,25 +236,37 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + /* Tell the cancellation handler to free this buffer. */ + clarg.buf = buf; + ++ int cl; + if (has_ts) +- __snprintf (buf, l + 1, +- SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); ++ cl = __snprintf (buf, l + 1, ++ SYSLOG_HEADER (pri, timestamp, &msgoff, pid)); + else +- __snprintf (buf, l + 1, +- SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ cl = __snprintf (buf, l + 1, ++ SYSLOG_HEADER_WITHOUT_TS (pri, &msgoff)); ++ if (cl != l) ++ goto out; + + va_list apc; + va_copy (apc, ap); +- __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, +- mode_flags); ++ cl = __vsnprintf_internal (buf + l, bufsize - l + 1, fmt, apc, ++ mode_flags); + va_end (apc); ++ ++ if (cl != vl) ++ goto out; + } + else + { ++ int bl; + /* Nothing much to do but emit an error message. */ +- bufsize = __snprintf (bufs, sizeof bufs, +- "out of memory[%d]", __getpid ()); ++ bl = __snprintf (bufs, sizeof bufs, ++ "out of memory[%d]", __getpid ()); ++ if (bl < 0 || bl >= sizeof bufs) ++ goto out; ++ ++ bufsize = bl; + buf = bufs; ++ msgoff = 0; + } + } + +-- +2.43.0 + diff --git a/packages/glibc/0044-syslog-Fix-integer-overflow-in-__vsyslog_internal-CV.patch b/packages/glibc/0044-syslog-Fix-integer-overflow-in-__vsyslog_internal-CV.patch new file mode 100644 index 00000000000..5529b3b8fe2 --- /dev/null +++ b/packages/glibc/0044-syslog-Fix-integer-overflow-in-__vsyslog_internal-CV.patch @@ -0,0 +1,41 @@ +From d37c2b20a4787463d192b32041c3406c2bd91de0 Mon Sep 17 00:00:00 2001 +From: Arjun Shankar +Date: Mon, 15 Jan 2024 17:44:45 +0100 +Subject: [PATCH] syslog: Fix integer overflow in __vsyslog_internal + (CVE-2023-6780) + +__vsyslog_internal calculated a buffer size by adding two integers, but +did not first check if the addition would overflow. This commit fixes +that. + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +(cherry picked from commit ddf542da94caf97ff43cc2875c88749880b7259b) +--- + misc/syslog.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/misc/syslog.c b/misc/syslog.c +index 53440e47ad..4af87f54fd 100644 +--- a/misc/syslog.c ++++ b/misc/syslog.c +@@ -41,6 +41,7 @@ static char sccsid[] = "@(#)syslog.c 8.4 (Berkeley) 3/18/94"; + #include + #include + #include ++#include + + static int LogType = SOCK_DGRAM; /* type of socket connection */ + static int LogFile = -1; /* fd for log */ +@@ -219,7 +220,7 @@ __vsyslog_internal (int pri, const char *fmt, va_list ap, + vl = __vsnprintf_internal (pos, len, fmt, apc, mode_flags); + va_end (apc); + +- if (vl < 0) ++ if (vl < 0 || vl >= INT_MAX - l) + goto out; + + if (vl >= len) +-- +2.43.0 + diff --git a/packages/glibc/glibc.spec b/packages/glibc/glibc.spec index 564c47a3bbf..7e17ca8a2de 100644 --- a/packages/glibc/glibc.spec +++ b/packages/glibc/glibc.spec @@ -46,6 +46,23 @@ Patch0024: 0024-Fix-leak-in-getaddrinfo-introduced-by-the-fix-for-CV.patch Patch0025: 0025-Document-CVE-2023-4806-and-CVE-2023-5156-in-NEWS.patch Patch0026: 0026-Propagate-GLIBC_TUNABLES-in-setxid-binaries.patch Patch0027: 0027-tunables-Terminate-if-end-of-input-is-reached-CVE-20.patch +Patch0028: 0028-Revert-elf-Remove-unused-l_text_end-field-from-struc.patch +Patch0029: 0029-Revert-elf-Always-call-destructors-in-reverse-constr.patch +Patch0030: 0030-Revert-elf-Move-l_init_called_next-to-old-place-of-l.patch +Patch0031: 0031-sysdeps-sem_open-Clear-O_CREAT-when-semaphore-file-i.patch +Patch0032: 0032-elf-Fix-wrong-break-removal-from-8ee878592c.patch +Patch0033: 0033-LoongArch-Delete-excessively-allocated-memory.patch +Patch0034: 0034-elf-Fix-TLS-modid-reuse-generation-assignment-BZ-290.patch +Patch0035: 0035-elf-Add-TLS-modid-reuse-test-for-bug-29039.patch +Patch0036: 0036-x86-64-Fix-the-dtv-field-load-for-x32-BZ-31184.patch +Patch0037: 0037-x86-64-Fix-the-tcb-field-load-for-x32-BZ-31185.patch +Patch0038: 0038-NEWS-Mention-bug-fixes-for-29039-30694-30709-30721.patch +Patch0039: 0039-NEWS-Mention-bug-fixes-for-30745-30843.patch +Patch0040: 0040-getaddrinfo-translate-ENOMEM-to-EAI_MEMORY-bug-31163.patch +Patch0041: 0041-libio-Check-remaining-buffer-size-in-_IO_wdo_write-b.patch +Patch0042: 0042-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch +Patch0043: 0043-syslog-Fix-heap-buffer-overflow-in-__vsyslog_interna.patch +Patch0044: 0044-syslog-Fix-integer-overflow-in-__vsyslog_internal-CV.patch # Fedora patches Patch1001: glibc-cs-path.patch