Commit: Fix CVE-2026-19582
Nick Clifton <[email protected]>
| Newsgroups | gmane.comp.gnu.binutils |
|---|---|
| Message-ID | <[email protected]> |
Hi Guys, I am applying the attached patch to fix CVE-2026-19582. This is an annoying, not really valid as a CVE, bug which is based upon the fact that peXXigen.c:rsrc_sort_entries() uses a fixed size static buffer for constructing error messages. A specially crafted (and invalid) PE format input file could trigger a buffer overflow potentially causing the linker to crash. The fix I have chosen is to change the buffer into a rsrc_string structure and to use this to keep track of the space remaining whilst constructing the error message. Which is a lot of faff for a case that will almost certainly never arise. But hey ho, the bug has been reported and now it is fixed. Cheers Nick https://bugzilla.redhat.com/show_bug.cgi?id=2513754
peXXigen.c.patch
(text/x-patch, 7.9 KB)
diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c
index 9794ecdaabe..17a94c461fe 100644
--- a/bfd/peXXigen.c
+++ b/bfd/peXXigen.c
@@ -3811,92 +3811,152 @@ rsrc_cmp (bool is_name, rsrc_entry * a, rsrc_entry * b)
return res;
}
-static void
-rsrc_print_name (char * buffer, rsrc_string string)
+static bool
+rsrc_string_print_str (rsrc_string buffer, const char * format, char * context)
+{
+ if (buffer.string == NULL || buffer.len == 0)
+ return false;
+
+ int printed = snprintf ((char *) buffer.string, buffer.len, format, context);
+
+ if (printed >= (int) buffer.len)
+ {
+ buffer.len = 0;
+ return false;
+ }
+
+ buffer.string += printed;
+ buffer.len -= printed;
+ return true;
+}
+
+static bool
+rsrc_string_print_int (rsrc_string buffer, const char * format, int context)
+{
+ if (buffer.string == NULL || buffer.len == 0)
+ return false;
+
+ int printed = snprintf ((char *) buffer.string, buffer.len, format, context);
+
+ if (printed >= (int) buffer.len)
+ {
+ buffer.len = 0;
+ return false;
+ }
+
+ buffer.string += printed;
+ buffer.len -= printed;
+ return true;
+}
+
+static bool
+rsrc_print_name (rsrc_string buffer, rsrc_string string)
{
unsigned int i;
bfd_byte * name = string.string;
for (i = string.len; i--; name += 2)
- sprintf (buffer + strlen (buffer), "%.1s", name);
+ {
+ if (! rsrc_string_print_str (buffer, "%.1s", (char *) name))
+ return false;
+ }
+
+ return true;
}
-static const char *
-rsrc_resource_name (rsrc_entry *entry, rsrc_directory *dir, char *buffer)
+static bool
+rsrc_resource_name (rsrc_entry *entry, rsrc_directory *dir, rsrc_string buffer)
{
bool is_string = false;
+ bool res = true;
- buffer[0] = 0;
+ if (buffer.string == NULL || buffer.len == 0)
+ return false;
+
+ buffer.string[0] = 0;
- if (dir != NULL && dir->entry != NULL && dir->entry->parent != NULL
+ if (dir != NULL
+ && dir->entry != NULL
+ && dir->entry->parent != NULL
&& dir->entry->parent->entry != NULL)
{
- strcpy (buffer, "type: ");
+ res &= rsrc_string_print_str (buffer, "%s", "type: ");
+
if (dir->entry->parent->entry->is_name)
- rsrc_print_name (buffer + strlen (buffer),
- dir->entry->parent->entry->name_id.name);
+ {
+ res &= rsrc_print_name (buffer, dir->entry->parent->entry->name_id.name);
+ }
else
{
unsigned int id = dir->entry->parent->entry->name_id.id;
- sprintf (buffer + strlen (buffer), "%x", id);
+ res &= rsrc_string_print_int (buffer, "%x", id);
+
switch (id)
{
- case 1: strcat (buffer, " (CURSOR)"); break;
- case 2: strcat (buffer, " (BITMAP)"); break;
- case 3: strcat (buffer, " (ICON)"); break;
- case 4: strcat (buffer, " (MENU)"); break;
- case 5: strcat (buffer, " (DIALOG)"); break;
- case 6: strcat (buffer, " (STRING)"); is_string = true; break;
- case 7: strcat (buffer, " (FONTDIR)"); break;
- case 8: strcat (buffer, " (FONT)"); break;
- case 9: strcat (buffer, " (ACCELERATOR)"); break;
- case 10: strcat (buffer, " (RCDATA)"); break;
- case 11: strcat (buffer, " (MESSAGETABLE)"); break;
- case 12: strcat (buffer, " (GROUP_CURSOR)"); break;
- case 14: strcat (buffer, " (GROUP_ICON)"); break;
- case 16: strcat (buffer, " (VERSION)"); break;
- case 17: strcat (buffer, " (DLGINCLUDE)"); break;
- case 19: strcat (buffer, " (PLUGPLAY)"); break;
- case 20: strcat (buffer, " (VXD)"); break;
- case 21: strcat (buffer, " (ANICURSOR)"); break;
- case 22: strcat (buffer, " (ANIICON)"); break;
- case 23: strcat (buffer, " (HTML)"); break;
- case 24: strcat (buffer, " (MANIFEST)"); break;
- case 240: strcat (buffer, " (DLGINIT)"); break;
- case 241: strcat (buffer, " (TOOLBAR)"); break;
+ case 1: res &= rsrc_string_print_str (buffer, "%s", " (CURSOR)"); break;
+ case 2: res &= rsrc_string_print_str (buffer, "%s", " (BITMAP)"); break;
+ case 3: res &= rsrc_string_print_str (buffer, "%s", " (ICON)"); break;
+ case 4: res &= rsrc_string_print_str (buffer, "%s", " (MENU)"); break;
+ case 5: res &= rsrc_string_print_str (buffer, "%s", " (DIALOG)"); break;
+ case 6: res &= rsrc_string_print_str (buffer, "%s", " (STRING)"); is_string = true; break;
+ case 7: res &= rsrc_string_print_str (buffer, "%s", " (FONTDIR)"); break;
+ case 8: res &= rsrc_string_print_str (buffer, "%s", " (FONT)"); break;
+ case 9: res &= rsrc_string_print_str (buffer, "%s", " (ACCELERATOR)"); break;
+ case 10: res &= rsrc_string_print_str (buffer, "%s", " (RCDATA)"); break;
+ case 11: res &= rsrc_string_print_str (buffer, "%s", " (MESSAGETABLE)"); break;
+ case 12: res &= rsrc_string_print_str (buffer, "%s", " (GROUP_CURSOR)"); break;
+ case 14: res &= rsrc_string_print_str (buffer, "%s", " (GROUP_ICON)"); break;
+ case 16: res &= rsrc_string_print_str (buffer, "%s", " (VERSION)"); break;
+ case 17: res &= rsrc_string_print_str (buffer, "%s", " (DLGINCLUDE)"); break;
+ case 19: res &= rsrc_string_print_str (buffer, "%s", " (PLUGPLAY)"); break;
+ case 20: res &= rsrc_string_print_str (buffer, "%s", " (VXD)"); break;
+ case 21: res &= rsrc_string_print_str (buffer, "%s", " (ANICURSOR)"); break;
+ case 22: res &= rsrc_string_print_str (buffer, "%s", " (ANIICON)"); break;
+ case 23: res &= rsrc_string_print_str (buffer, "%s", " (HTML)"); break;
+ case 24: res &= rsrc_string_print_str (buffer, "%s", " (MANIFEST)"); break;
+ case 240: res &= rsrc_string_print_str (buffer, "%s", " (DLGINIT)"); break;
+ case 241: res &= rsrc_string_print_str (buffer, "%s", " (TOOLBAR)"); break;
}
}
}
if (dir != NULL && dir->entry != NULL)
{
- strcat (buffer, " name: ");
+ res &= rsrc_string_print_str (buffer, "%s", " name: ");
+
if (dir->entry->is_name)
- rsrc_print_name (buffer + strlen (buffer), dir->entry->name_id.name);
+ {
+ res &= rsrc_print_name (buffer, dir->entry->name_id.name);
+ }
else
{
unsigned int id = dir->entry->name_id.id;
- sprintf (buffer + strlen (buffer), "%x", id);
+ res &= rsrc_string_print_int (buffer, "%x", id);
if (is_string)
- sprintf (buffer + strlen (buffer), " (resource id range: %d - %d)",
- (id - 1) << 4, (id << 4) - 1);
+ {
+ res &= rsrc_string_print_str (buffer, "%s", " (resource id range: ");
+ res &= rsrc_string_print_int (buffer, "%d", (id - 1) << 4);
+ res &= rsrc_string_print_str (buffer, "%s", " - ");
+ res &= rsrc_string_print_int (buffer, "%d", (id << 4) - 1);
+ res &= rsrc_string_print_str (buffer, "%s", ")");
+ }
}
}
if (entry != NULL)
{
- strcat (buffer, " lang: ");
+ res &= rsrc_string_print_str (buffer, "%s", " lang: ");
if (entry->is_name)
- rsrc_print_name (buffer + strlen (buffer), entry->name_id.name);
+ res &= rsrc_print_name (buffer, entry->name_id.name);
else
- sprintf (buffer + strlen (buffer), "%x", entry->name_id.id);
+ res &= rsrc_string_print_int (buffer, "%x", entry->name_id.id);
}
- return buffer;
+ return res;
}
/* *sigh* Windows resource strings are special. Only the top 28-bits of
@@ -4156,11 +4216,20 @@ rsrc_sort_entries (rsrc_dir_chain *chain,
_bfd_error_handler (_(".rsrc merge failure: duplicate leaf"));
else
{
- char buff[256];
-
- _bfd_error_handler (_(".rsrc merge failure: duplicate leaf: %s"),
- rsrc_resource_name (entry, dir, buff));
+#define RSRC_RES_NAME_LEN 256
+ char buff[RSRC_RES_NAME_LEN];
+ rsrc_string buffer;
+
+ buffer.string = (bfd_byte *) buff;
+ buffer.len = RSRC_RES_NAME_LEN;
+
+ if (rsrc_resource_name (entry, dir, buffer))
+ _bfd_error_handler (_(".rsrc merge failure: duplicate leaf: %s"),
+ buffer.string);
+ else
+ _bfd_error_handler (_(".rsrc merge failure: duplicate leaf"));
}
+
bfd_set_error (bfd_error_file_truncated);
return;
}