RFC: Fix for CVE-2026-19548

Alan Modra amodra@gmail.com
Fri Aug 14 01:26:55 GMT 2026


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


More information about the Binutils mailing list