]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
elf: Bound the tunable cache string table against the mapping size
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 6 Jul 2026 19:56:12 +0000 (16:56 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Mon, 13 Jul 2026 14:26:31 +0000 (11:26 -0300)
_dl_load_cache_tunables bounds each entry's string offsets against
[s_start, start + cache_new->len_strings], but len_strings is an
unvalidated 32-bit field from ld.so.cache and s_start/s_end were int.  A
corrupt cache with an oversized len_strings could make s_end exceed the
mapping (or overflow), letting an offset point outside the mmap; the
following strcmp/__strdup would then read unmapped memory.

Compute the offsets as size_t and clamp s_end to cachesize, matching how
the regular library lookup bounds string offsets against the mapping size.

Checked on x86_64-linux-gnu and i686-linux-gnu.

Reviewed-by: DJ Delorie <dj@redhat.com>
elf/dl-cache.c

index d05afe270043b0b8569ba2f28278a5e37db2b2d5..5d8d3cae908843d6b16cd50e811dfb5c9d787980 100644 (file)
@@ -17,6 +17,7 @@
    <https://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
+#include <intprops.h>
 #include <unistd.h>
 #include <ldsodefs.h>
 #include <sys/mman.h>
@@ -649,9 +650,16 @@ _dl_load_cache_tunables (const char **data)
       != (void *) & tec[count])
     return NULL;
 
-  /* Validate each entry.  */
-  int s_start = (const char *) (&cache_new->libs[cache_new->nlibs]) - *data;
-  int s_end = s_start + cache_new->len_strings;
+  /* Validate each entry.  The string table lies between the file entries
+     and the end of the mapping; clamp its end to CACHESIZE so that a bogus
+     len_strings cannot make an offset point outside the mapped file.  */
+  size_t s_start = (const char *) (&cache_new->libs[cache_new->nlibs]) - *data;
+  size_t s_end;
+  if (s_start >= cachesize
+      || INT_ADD_WRAPV (s_start, cache_new->len_strings, &s_end))
+    return NULL;
+  if (s_end > cachesize)
+    s_end = cachesize;
   for (i = 0; i < count; i ++)
     {
       if (thc->tunables[i].name_offset < s_start