Re: RFC: Fix for CVE-2026-19548
Alan Modra <[email protected]>
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Aug 14, 2026 at 09:10:06AM +0930, Alan Modra wrote:
> On Thu, Aug 13, 2026 at 09:52:28AM +0100, Nick Clifton wrote:
> > Hi Guys,
> >
> > CVE-2026-19548 points out a potential use-after-free bug in the
> > add_archive_element() function in ld/ldmain.c. After looking at
> > it it seemed to me that the simplest solution was to keep a copy
> > of the my_archive pointer so that there is no need to dereference
> > the freed bfd structure. As is done in the attached, proposed
> > patch. Any comments ?
> >
> > Cheers
> > Nick
> >
> > PS. According to the SECURITY.txt statement this bug does not really
> > qualify for CVE status, but that is a separate issue from actually
> > fixing the bug.
> >
> > https://nvd.nist.gov/vuln/detail/CVE-2026-19548
>
> The bug report says:
> "The vulnerability is triggered when LTO plugins are active
> (link_info.lto_plugin_active is true) and the input object has
> abfd->my_archive == NULL"
>
> If my_archive is NULL the bfd isn't an archive member!
>
> How is it that add_archive_element is being called for something that
> isn't a member of an archive? Do you have a testcase?
>
> Hmm.. This is likely a bug in e34fd4bfa6d7. I see a bfd_release in
> _bfd_compute_and_push_armap that will lose the memory for
> ardata->symdefs set up in _bfd_load_armap.
Fix that.
ardata->symdefs set up by _bfd_load_armap was being released by
_bfd_compute_and_push_armap, and overwritten by later bfd_alloc calls.
_bfd_load_armap also unnecessarily copied a name.
PR ld/24600
* archive.c (_bfd_load_armap): Don't copy name.
(_bfd_compute_and_push_armap): Don't release bfd_alloc'd memory
when keep_symdefs. Tidy memory allocation, removing unnecessary
casts and temp vars.
diff --git a/bfd/archive.c b/bfd/archive.c
index 1bff31b6d09..d0a6177ac4d 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -1023,29 +1023,13 @@ _bfd_load_armap (bfd *arch, unsigned int elength ATTRIBUTE_UNUSED,
counter < ardata->symdef_count;
counter++, set++)
{
- bfd_size_type namelen = strlen (*map[counter].name) + 1;
- char *name = bfd_alloc (arch, namelen);
-
- if (name == NULL)
- {
- bfd_set_error (bfd_error_no_memory);
- goto release_symdefs;
- }
-
- memcpy (name, *map[counter].name, namelen);
- set->name = name;
+ set->name = *map[counter].name;
set->u.abfd = map[counter].abfd;
}
ardata->symdef_use_bfd = true;
arch->has_armap = true;
return true;
-
- release_symdefs:
- bfd_release (arch, ardata->symdefs);
- ardata->symdef_count = 0;
- ardata->symdefs = NULL;
- return false;
}
/* Iterate over members of archive ARCH starting from FIRST_ONE and
@@ -2463,24 +2447,22 @@ _bfd_compute_and_push_armap
{
char *first_name = NULL;
bfd *current;
- struct orl *map = NULL;
+ struct orl *map;
unsigned int orl_max = 1024; /* Fine initial default. */
unsigned int orl_count = 0;
int stridx = 0;
asymbol **syms = NULL;
long syms_max = 0;
bool ret;
- size_t amt;
static bool report_plugin_err = true;
- amt = orl_max * sizeof (struct orl);
- map = (struct orl *) bfd_malloc (amt);
+ map = bfd_malloc (orl_max * sizeof (*map));
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);
+ first_name = bfd_alloc (arch, 1);
if (first_name == NULL)
goto error_return;
@@ -2552,15 +2534,14 @@ _bfd_compute_and_push_armap
if (include_in_armap)
{
- bfd_size_type namelen;
+ size_t namelen;
struct orl *new_map;
/* This symbol will go into the archive header. */
if (orl_count == orl_max)
{
orl_max *= 2;
- amt = orl_max * sizeof (struct orl);
- new_map = (struct orl *) bfd_realloc (map, amt);
+ new_map = bfd_realloc (map, orl_max * sizeof (*map));
if (new_map == NULL)
goto error_return;
@@ -2577,20 +2558,19 @@ _bfd_compute_and_push_armap
(_("%pB: plugin needed to handle lto object"),
current);
}
- namelen = strlen (syms[src_count]->name);
- amt = sizeof (char *);
- map[orl_count].name = (char **) bfd_alloc (arch, amt);
+ namelen = strlen (syms[src_count]->name) + 1;
+ map[orl_count].name = bfd_alloc (arch, sizeof (char *));
if (map[orl_count].name == NULL)
goto error_return;
- *(map[orl_count].name) = (char *) bfd_alloc (arch,
- namelen + 1);
+ *(map[orl_count].name) = bfd_alloc (arch, namelen);
if (*(map[orl_count].name) == NULL)
goto error_return;
- strcpy (*(map[orl_count].name), syms[src_count]->name);
+ memcpy (*(map[orl_count].name), syms[src_count]->name,
+ namelen);
map[orl_count].abfd = current;
map[orl_count].namidx = stridx;
- stridx += namelen + 1;
+ stridx += namelen;
++orl_count;
}
}
@@ -2608,7 +2588,7 @@ _bfd_compute_and_push_armap
free (syms);
free (map);
- if (first_name != NULL)
+ if (!keep_symtab)
bfd_release (arch, first_name);
return ret;
--
Alan Modra