[to-be-committed] PR ld/24600: BFD: Fix use-after-free from `_bfd_load_armap'
Maciej W. Rozycki
macro@orcam.me.uk
Fri Aug 14 16:21:04 GMT 2026
Fix an issue in commit e34fd4bfa6d7 ("PR ld/24600: BFD: Add general
linker support for mapless archives") where the symbol map created by
`_bfd_load_armap' has its entries discarded by a call to `bfd_release'
after return to `_bfd_compute_and_push_armap' where all objalloc memory
is freed that came starting from the dummy `first_name' allocation.
An observation here is that `_bfd_compute_and_push_armap' only makes
temporary use of its allocations, so there's no point in attaching them
to the archive BFD. Switch to using local objalloc then, the release of
which does not affect allocations made by `_bfd_load_armap'.
This has been found by Alan Modra in the context of CVE-2026-19548,
<https://nvd.nist.gov/vuln/detail/CVE-2026-19548>.
PR ld/24600
* archive.c (_bfd_compute_and_push_armap): Use local objalloc for
symbol names.
---
Hi,
This has passed regression-testing across my usual 263 targets.
Nick, I can see the function result casts have been removed and added
back and forth, most recently with your commit a50b1753d42f ("Updated
soruces in bfd/* to compile cleanly with -Wc++-compat."). Do we still
care about this scenario? With this change I assumed we do not, but I'm
happy to add them back.
I saw Alan's fix which takes a different approach and makes temporary
allocations from `_bfd_compute_and_push_armap' permanent, however at the
cost of keeping intermediate pointer allocations forever. This variant
discards them after use at the cost of temporary higher memory usage in
`_bfd_load_armap'. I'm happy to discuss pros and cons.
Otherwise I'm going to check this in shortly unless I hear objections.
NB this code dates back to commit 5ee3886b48fb from 1994.
Maciej
---
bfd/archive.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
binutils-bfd-compute-and-push-armap-objalloc.diff
Index: binutils-gdb/bfd/archive.c
===================================================================
--- binutils-gdb.orig/bfd/archive.c
+++ binutils-gdb/bfd/archive.c
@@ -135,6 +135,7 @@ SUBSECTION
#include "bfd.h"
#include "libiberty.h"
#include "libbfd.h"
+#include "objalloc.h"
#include "aout/ar.h"
#include "aout/ranlib.h"
#include "safe-ctype.h"
@@ -2461,7 +2462,7 @@ _bfd_compute_and_push_armap
(bfd *arch, unsigned int elength, bool keep_symtab,
bool (*push_armap) (bfd *, unsigned int, struct orl *, unsigned int, int))
{
- char *first_name = NULL;
+ struct objalloc *names;
bfd *current;
struct orl *map = NULL;
unsigned int orl_max = 1024; /* Fine initial default. */
@@ -2473,17 +2474,17 @@ _bfd_compute_and_push_armap
size_t amt;
static bool report_plugin_err = true;
+ /* We put the symbol names on our scratch objalloc, and then discard
+ them when done. */
+ names = objalloc_create ();
+ if (names == NULL)
+ goto objalloc_error_return;
+
amt = orl_max * sizeof (struct orl);
map = (struct orl *) bfd_malloc (amt);
if (map == NULL)
goto error_return;
- /* We put the symbol names on the arch objalloc, and then discard
- them when done. */
- first_name = (char *) bfd_alloc (arch, 1);
- if (first_name == NULL)
- goto error_return;
-
/* Drop all the files called __.SYMDEF, we're going to make our own. */
while (arch->archive_head
&& strcmp (bfd_get_filename (arch->archive_head), "__.SYMDEF") == 0)
@@ -2579,13 +2580,13 @@ _bfd_compute_and_push_armap
}
namelen = strlen (syms[src_count]->name);
amt = sizeof (char *);
- map[orl_count].name = (char **) bfd_alloc (arch, amt);
+ map[orl_count].name = objalloc_alloc (names, amt);
if (map[orl_count].name == NULL)
- goto error_return;
- *(map[orl_count].name) = (char *) bfd_alloc (arch,
- namelen + 1);
+ goto objalloc_error_return;
+ *(map[orl_count].name) = objalloc_alloc (names,
+ namelen + 1);
if (*(map[orl_count].name) == NULL)
- goto error_return;
+ goto objalloc_error_return;
strcpy (*(map[orl_count].name), syms[src_count]->name);
map[orl_count].abfd = current;
map[orl_count].namidx = stridx;
@@ -2608,16 +2609,16 @@ _bfd_compute_and_push_armap
free (syms);
free (map);
- if (first_name != NULL)
- bfd_release (arch, first_name);
+ objalloc_free (names);
return ret;
+ objalloc_error_return:
+ bfd_set_error (bfd_error_no_memory);
error_return:
free (syms);
free (map);
- if (first_name != NULL)
- bfd_release (arch, first_name);
+ objalloc_free (names);
return false;
}
More information about the Binutils
mailing list