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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.