@@ -36,5 +36,6 @@ SRC_URI = "\
file://0013-Define-alignof-using-_Alignof-when-using-C11-or-newe.patch \
file://0014-Remove-duplicate-pe-dll.o-entry-deom-targ_extra_ofil.patch \
file://0015-CVE-2025-1153.patch \
+ file://0016-CVE-2025-1148.patch \
"
S = "${WORKDIR}/git"
new file mode 100644
@@ -0,0 +1,596 @@
+From d4115c2c8d447e297ae353892de89192c1996211 Mon Sep 17 00:00:00 2001
+From: Alan Modra <amodra@gmail.com>
+Date: Sat, 11 Jan 2025 16:19:09 +1030
+Subject: [PATCH] Replace xmalloc with stat_alloc in ld parser
+
+A few place dealing with ld script handling made some attempt to free
+memory, but this was generally ignored and would be quite a lot of
+work to implement. Instead, use the stat_obstack rather than
+mallocing in many more cases.
+
+ * ldexp.c (exp_get_fill): Use stat_alloc for fill.
+ * ldfile.c (ldfile_try_open_bfd): Don't free yylval fields.
+ * ldgram.y: Replace xmalloc with stat_alloc throughout.
+ * ldlang.c (stat_memdup, stat_strdup): New functions.
+ (ldirname): Use stat_memdup. Don't strdup ".".
+ (output_section_callback_sort): Use stat_alloc.
+ (output_section_callback_tree_to_list): Don't free.
+ (lang_memory_region_lookup): Use stat_strdup.
+ (lang_memory_region_alias): Likewise.
+ (add_excluded_libs): Use stat_alloc and stat_memdup.
+ (ldlang_add_undef, ldlang_add_require_defined): Use stat_strdup.
+ (lang_add_nocrossref, lang_leave_overlay): Use stat_alloc.
+ (realsymbol): Use stat_strdup for return value and always
+ free symbol.
+ (lang_new_vers_pattern, lang_new_vers_node): Use stat_alloc.
+ (lang_finalize_version_expr_head): Don't free. Delete FIXME.
+ (lang_register_vers_node): Don't free.
+ (lang_add_vers_depend): Use stat_alloc.
+ (lang_do_version_exports_section): Likewise.
+ (lang_add_unique): Use stat_alloc and stat_strdup.
+ (lang_append_dynamic_list): Use stat_alloc.
+ * ldlang.h (stat_memdup, stat_strdup): Declare.
+ * ldlex.l: Replace xstrdup with stat_strdup throughout.
+ Replace xmemdup with stat_memdup too.
+ * lexsup.c (parse_args): Don't free export list or dynamic
+ list.
+
+(cherry picked from commit: d4115c2c8d447e297ae353892de89192c1996211)
+
+Upstream-Status: Backport [https://sourceware.org/cgit/binutils-gdb/commit/?id=d4115c2c8d447e297ae353892de89192c1996211]
+CVE: CVE-2025-1148
+
+Signed-off-by: Harish Sadineni <Harish.Sadineni@windriver.com>
+
+---
+ ld/ldexp.c | 4 +--
+ ld/ldfile.c | 17 ++---------
+ ld/ldgram.y | 21 ++++++-------
+ ld/ldlang.c | 87 ++++++++++++++++++++++++++---------------------------
+ ld/ldlang.h | 4 +++
+ ld/ldlex.l | 23 +++++++-------
+ ld/lexsup.c | 22 +-------------
+ 7 files changed, 74 insertions(+), 104 deletions(-)
+
+diff --git a/ld/ldexp.c b/ld/ldexp.c
+index 035cef60448..87d882e5066 100644
+--- a/ld/ldexp.c
++++ b/ld/ldexp.c
+@@ -1630,7 +1630,7 @@ exp_get_fill (etree_type *tree, fill_type *def, char *name)
+ {
+ unsigned char *dst;
+ unsigned char *s;
+- fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1);
++ fill = stat_alloc ((len + 1) / 2 + sizeof (*fill) - 1);
+ fill->size = (len + 1) / 2;
+ dst = fill->data;
+ s = (unsigned char *) expld.result.str;
+@@ -1655,7 +1655,7 @@ exp_get_fill (etree_type *tree, fill_type *def, char *name)
+ }
+ else
+ {
+- fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1);
++ fill = stat_alloc (4 + sizeof (*fill) - 1);
+ val = expld.result.value;
+ fill->data[0] = (val >> 24) & 0xff;
+ fill->data[1] = (val >> 16) & 0xff;
+diff --git a/ld/ldfile.c b/ld/ldfile.c
+index 12551504ae6..404af5fba14 100644
+--- a/ld/ldfile.c
++++ b/ld/ldfile.c
+@@ -438,18 +438,11 @@ ldfile_try_open_bfd (const char *attempt,
+ if (token == ',')
+ {
+ if ((token = yylex ()) != NAME)
+- {
+- free (arg1);
+- continue;
+- }
++ continue;
+ arg2 = yylval.name;
+ if ((token = yylex ()) != ','
+ || (token = yylex ()) != NAME)
+- {
+- free (arg1);
+- free (arg2);
+- continue;
+- }
++ continue;
+ arg3 = yylval.name;
+ token = yylex ();
+ }
+@@ -468,18 +461,12 @@ ldfile_try_open_bfd (const char *attempt,
+ if (strcmp (arg, lang_get_output_target ()) != 0)
+ skip = 1;
+ }
+- free (arg1);
+- free (arg2);
+- free (arg3);
+ break;
+ case NAME:
+ case LNAME:
+ case VERS_IDENTIFIER:
+ case VERS_TAG:
+- free (yylval.name);
+- break;
+ case INT:
+- free (yylval.bigint.str);
+ break;
+ }
+ token = yylex ();
+diff --git a/ld/ldgram.y b/ld/ldgram.y
+index 6d516db38c7..9bb98de2f0a 100644
+--- a/ld/ldgram.y
++++ b/ld/ldgram.y
+@@ -543,7 +543,7 @@ section_name_spec:
+ sect_flag_list: NAME
+ {
+ struct flag_info_list *n;
+- n = ((struct flag_info_list *) xmalloc (sizeof *n));
++ n = stat_alloc (sizeof *n);
+ if ($1[0] == '!')
+ {
+ n->with = without_flags;
+@@ -561,7 +561,7 @@ sect_flag_list: NAME
+ | sect_flag_list '&' NAME
+ {
+ struct flag_info_list *n;
+- n = ((struct flag_info_list *) xmalloc (sizeof *n));
++ n = stat_alloc (sizeof *n);
+ if ($3[0] == '!')
+ {
+ n->with = without_flags;
+@@ -582,7 +582,7 @@ sect_flags:
+ INPUT_SECTION_FLAGS '(' sect_flag_list ')'
+ {
+ struct flag_info *n;
+- n = ((struct flag_info *) xmalloc (sizeof *n));
++ n = stat_alloc (sizeof *n);
+ n->flag_list = $3;
+ n->flags_initialized = false;
+ n->not_with_flags = 0;
+@@ -595,7 +595,7 @@ exclude_name_list:
+ exclude_name_list wildcard_name
+ {
+ struct name_list *tmp;
+- tmp = (struct name_list *) xmalloc (sizeof *tmp);
++ tmp = stat_alloc (sizeof *tmp);
+ tmp->name = $2;
+ tmp->next = $1;
+ $$ = tmp;
+@@ -604,7 +604,7 @@ exclude_name_list:
+ wildcard_name
+ {
+ struct name_list *tmp;
+- tmp = (struct name_list *) xmalloc (sizeof *tmp);
++ tmp = stat_alloc (sizeof *tmp);
+ tmp->name = $1;
+ tmp->next = NULL;
+ $$ = tmp;
+@@ -615,7 +615,7 @@ section_name_list:
+ section_name_list opt_comma section_name_spec
+ {
+ struct wildcard_list *tmp;
+- tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
++ tmp = stat_alloc (sizeof *tmp);
+ tmp->next = $1;
+ tmp->spec = $3;
+ $$ = tmp;
+@@ -624,7 +624,7 @@ section_name_list:
+ section_name_spec
+ {
+ struct wildcard_list *tmp;
+- tmp = (struct wildcard_list *) xmalloc (sizeof *tmp);
++ tmp = stat_alloc (sizeof *tmp);
+ tmp->next = NULL;
+ tmp->spec = $1;
+ $$ = tmp;
+@@ -926,7 +926,7 @@ nocrossref_list:
+ {
+ struct lang_nocrossref *n;
+
+- n = (struct lang_nocrossref *) xmalloc (sizeof *n);
++ n = stat_alloc (sizeof *n);
+ n->name = $1;
+ n->next = $2;
+ $$ = n;
+@@ -935,7 +935,7 @@ nocrossref_list:
+ {
+ struct lang_nocrossref *n;
+
+- n = (struct lang_nocrossref *) xmalloc (sizeof *n);
++ n = stat_alloc (sizeof *n);
+ n->name = $1;
+ n->next = $3;
+ $$ = n;
+@@ -1225,8 +1225,7 @@ phdr_opt:
+ {
+ struct lang_output_section_phdr_list *n;
+
+- n = ((struct lang_output_section_phdr_list *)
+- xmalloc (sizeof *n));
++ n = stat_alloc (sizeof *n);
+ n->name = $3;
+ n->used = false;
+ n->next = $1;
+diff --git a/ld/ldlang.c b/ld/ldlang.c
+index 74c0271973f..f613fc91f0a 100644
+--- a/ld/ldlang.c
++++ b/ld/ldlang.c
+@@ -188,6 +188,23 @@ stat_alloc (size_t size)
+ return obstack_alloc (&stat_obstack, size);
+ }
+
++void *
++stat_memdup (const void *src, size_t copy_size, size_t alloc_size)
++{
++ void *ret = obstack_alloc (&stat_obstack, alloc_size);
++ memcpy (ret, src, copy_size);
++ if (alloc_size > copy_size)
++ memset ((char *) ret + copy_size, 0, alloc_size - copy_size);
++ return ret;
++}
++
++char *
++stat_strdup (const char *str)
++{
++ size_t len = strlen (str) + 1;
++ return stat_memdup (str, len, len);
++}
++
+ /* Code for handling simple wildcards without going through fnmatch,
+ which can be expensive because of charset translations etc. */
+
+@@ -277,15 +294,13 @@ static char *
+ ldirname (const char *name)
+ {
+ const char *base = lbasename (name);
+- char *dirname;
+
+ while (base > name && IS_DIR_SEPARATOR (base[-1]))
+ --base;
+- if (base == name)
+- return strdup (".");
+- dirname = strdup (name);
+- dirname[base - name] = '\0';
+- return dirname;
++ size_t len = base - name;
++ if (len == 0)
++ return ".";
++ return stat_memdup (name, len, len + 1);
+ }
+
+ /* If PATTERN is of the form archive:file, return a pointer to the
+@@ -733,7 +748,7 @@ output_section_callback_sort (lang_wild_statement_type *ptr,
+ if (wont_add_section_p (section, os))
+ return;
+
+- node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
++ node = stat_alloc (sizeof (*node));
+ node->left = 0;
+ node->right = 0;
+ node->section = section;
+@@ -764,8 +779,6 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr,
+
+ if (tree->right)
+ output_section_callback_tree_to_list (ptr, tree->right, output);
+-
+- free (tree);
+ }
+
+
+@@ -1454,7 +1467,7 @@ lang_memory_region_lookup (const char *const name, bool create)
+
+ new_region = stat_alloc (sizeof (lang_memory_region_type));
+
+- new_region->name_list.name = xstrdup (name);
++ new_region->name_list.name = stat_strdup (name);
+ new_region->name_list.next = NULL;
+ new_region->next = NULL;
+ new_region->origin_exp = NULL;
+@@ -1509,7 +1522,7 @@ lang_memory_region_alias (const char *alias, const char *region_name)
+
+ /* Add alias to region name list. */
+ n = stat_alloc (sizeof (lang_memory_region_name));
+- n->name = xstrdup (alias);
++ n->name = stat_strdup (alias);
+ n->next = region->name_list.next;
+ region->name_list.next = n;
+ }
+@@ -2989,11 +3002,9 @@ add_excluded_libs (const char *list)
+ end = strpbrk (p, ",:");
+ if (end == NULL)
+ end = p + strlen (p);
+- entry = (struct excluded_lib *) xmalloc (sizeof (*entry));
++ entry = stat_alloc (sizeof (*entry));
+ entry->next = excluded_libs;
+- entry->name = (char *) xmalloc (end - p + 1);
+- memcpy (entry->name, p, end - p);
+- entry->name[end - p] = '\0';
++ entry->name = stat_memdup (p, end - p, end - p + 1);
+ excluded_libs = entry;
+ if (*end == '\0')
+ break;
+@@ -4017,7 +4028,7 @@ ldlang_add_undef (const char *const name, bool cmdline ATTRIBUTE_UNUSED)
+ new_undef->next = ldlang_undef_chain_list_head;
+ ldlang_undef_chain_list_head = new_undef;
+
+- new_undef->name = xstrdup (name);
++ new_undef->name = stat_strdup (name);
+
+ if (link_info.output_bfd != NULL)
+ insert_undefined (new_undef->name);
+@@ -4096,7 +4107,7 @@ ldlang_add_require_defined (const char *const name)
+ ldlang_add_undef (name, true);
+ ptr = stat_alloc (sizeof (*ptr));
+ ptr->next = require_defined_symbol_list;
+- ptr->name = strdup (name);
++ ptr->name = stat_strdup (name);
+ require_defined_symbol_list = ptr;
+ }
+
+@@ -9183,7 +9194,7 @@ lang_add_nocrossref (lang_nocrossref_type *l)
+ {
+ struct lang_nocrossrefs *n;
+
+- n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
++ n = stat_alloc (sizeof *n);
+ n->next = nocrossref_list;
+ n->list = l;
+ n->onlyfirst = false;
+@@ -9366,7 +9377,7 @@ lang_leave_overlay (etree_type *lma_expr,
+ {
+ lang_nocrossref_type *nc;
+
+- nc = (lang_nocrossref_type *) xmalloc (sizeof *nc);
++ nc = stat_alloc (sizeof *nc);
+ nc->name = l->os->name;
+ nc->next = nocrossref;
+ nocrossref = nc;
+@@ -9546,13 +9557,10 @@ realsymbol (const char *pattern)
+ if (changed)
+ {
+ *s = '\0';
+- return symbol;
+- }
+- else
+- {
+- free (symbol);
+- return pattern;
++ pattern = stat_strdup (symbol);
+ }
++ free (symbol);
++ return pattern;
+ }
+
+ /* This is called for each variable name or match expression. NEW_NAME is
+@@ -9567,7 +9575,7 @@ lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
+ {
+ struct bfd_elf_version_expr *ret;
+
+- ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
++ ret = stat_alloc (sizeof *ret);
+ ret->next = orig;
+ ret->symver = 0;
+ ret->script = 0;
+@@ -9604,7 +9612,8 @@ lang_new_vers_node (struct bfd_elf_version_expr *globals,
+ {
+ struct bfd_elf_version_tree *ret;
+
+- ret = (struct bfd_elf_version_tree *) xcalloc (1, sizeof *ret);
++ ret = stat_alloc (sizeof (*ret));
++ memset (ret, 0, sizeof (*ret));
+ ret->globals.list = globals;
+ ret->locals.list = locals;
+ ret->match = lang_vers_match;
+@@ -9686,15 +9695,7 @@ lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
+ }
+ while (e1 && strcmp (e1->pattern, e->pattern) == 0);
+
+- if (last == NULL)
+- {
+- /* This is a duplicate. */
+- /* FIXME: Memory leak. Sometimes pattern is not
+- xmalloced alone, but in larger chunk of memory. */
+- /* free (e->pattern); */
+- free (e);
+- }
+- else
++ if (last != NULL)
+ {
+ e->next = last->next;
+ last->next = e;
+@@ -9734,7 +9735,6 @@ lang_register_vers_node (const char *name,
+ {
+ einfo (_("%X%P: anonymous version tag cannot be combined"
+ " with other version tags\n"));
+- free (version);
+ return;
+ }
+
+@@ -9827,7 +9827,7 @@ lang_add_vers_depend (struct bfd_elf_version_deps *list, const char *name)
+ struct bfd_elf_version_deps *ret;
+ struct bfd_elf_version_tree *t;
+
+- ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
++ ret = stat_alloc (sizeof *ret);
+ ret->next = list;
+
+ for (t = link_info.version_info; t != NULL; t = t->next)
+@@ -9860,7 +9860,7 @@ lang_do_version_exports_section (void)
+ continue;
+
+ len = sec->size;
+- contents = (char *) xmalloc (len);
++ contents = stat_alloc (len);
+ if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len))
+ einfo (_("%X%P: unable to read .exports section contents\n"), sec);
+
+@@ -9871,8 +9871,6 @@ lang_do_version_exports_section (void)
+ p = strchr (p, '\0') + 1;
+ }
+
+- /* Do not free the contents, as we used them creating the regex. */
+-
+ /* Do not include this section in the link. */
+ sec->flags |= SEC_EXCLUDE | SEC_KEEP;
+ }
+@@ -9936,8 +9934,8 @@ lang_add_unique (const char *name)
+ if (strcmp (ent->name, name) == 0)
+ return;
+
+- ent = (struct unique_sections *) xmalloc (sizeof *ent);
+- ent->name = xstrdup (name);
++ ent = stat_alloc (sizeof *ent);
++ ent->name = stat_strdup (name);
+ ent->next = unique_section_list;
+ unique_section_list = ent;
+ }
+@@ -9960,7 +9958,8 @@ lang_append_dynamic_list (struct bfd_elf_dynamic_list **list_p,
+ {
+ struct bfd_elf_dynamic_list *d;
+
+- d = (struct bfd_elf_dynamic_list *) xcalloc (1, sizeof *d);
++ d = stat_alloc (sizeof (*d));
++ memset (d, 0, sizeof (*d));
+ d->head.list = dynamic;
+ d->match = lang_vers_match;
+ *list_p = d;
+diff --git a/ld/ldlang.h b/ld/ldlang.h
+index 91779a584b4..b074d6f5e37 100644
+--- a/ld/ldlang.h
++++ b/ld/ldlang.h
+@@ -664,6 +664,10 @@ extern void lang_for_each_statement_worker
+ (void (*) (lang_statement_union_type *), lang_statement_union_type *);
+ extern void *stat_alloc
+ (size_t);
++extern void * stat_memdup
++ (const void *, size_t, size_t);
++extern char *stat_strdup
++ (const char *);
+ extern void strip_excluded_output_sections
+ (void);
+ extern void lang_clear_os_map
+diff --git a/ld/ldlex.l b/ld/ldlex.l
+index e704a979722..58eca1b2fe7 100644
+--- a/ld/ldlex.l
++++ b/ld/ldlex.l
+@@ -188,7 +188,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+ && (yytext[1] == 'x'
+ || yytext[1] == 'X'))
+ {
+- yylval.bigint.str = xstrdup (yytext + 2);
++ yylval.bigint.str
++ = stat_strdup (yytext + 2);
+ }
+ return INT;
+ }
+@@ -391,32 +392,32 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+
+ <MRI>{FILENAMECHAR1}{NOCFILENAMECHAR}* {
+ /* Filename without commas, needed to parse mri stuff */
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+
+
+ <SCRIPT,INPUTLIST>{FILENAMECHAR1}{FILENAMECHAR}* {
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+ <INPUTLIST>"="{FILENAMECHAR1}{FILENAMECHAR}* {
+ /* Filename to be prefixed by --sysroot or when non-sysrooted, nothing. */
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+ <INPUTLIST>"-l"{FILENAMECHAR}+ {
+- yylval.name = xstrdup (yytext + 2);
++ yylval.name = stat_strdup (yytext + 2);
+ return LNAME;
+ }
+ <EXPRESSION>{SYMBOLNAMECHAR1}{SYMBOLNAMECHAR}* {
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+ /* The following rule is to prevent a fill expression on the output
+ section before /DISCARD/ interpreting the '/' as a divide. */
+ <EXPRESSION>"/DISCARD/" {
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+ <WILD>{WILDCHAR}* {
+@@ -431,14 +432,14 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+ }
+ else
+ {
+- yylval.name = xstrdup (yytext);
++ yylval.name = stat_strdup (yytext);
+ return NAME;
+ }
+ }
+
+ <SCRIPT,EXPRESSION,WILD,VERS_NODE,INPUTLIST>"\""[^\"]*"\"" {
+ /* No matter the state, quotes give what's inside. */
+- yylval.name = xmemdup (yytext + 1, yyleng - 2, yyleng - 1);
++ yylval.name = stat_memdup (yytext + 1, yyleng - 2, yyleng - 1);
+ return NAME;
+ }
+
+@@ -457,10 +458,10 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
+
+ <VERS_NODE>extern { RTOKEN(EXTERN); }
+
+-<VERS_NODE>{V_IDENTIFIER} { yylval.name = xstrdup (yytext);
++<VERS_NODE>{V_IDENTIFIER} { yylval.name = stat_strdup (yytext);
+ return VERS_IDENTIFIER; }
+
+-<VERS_SCRIPT>{V_TAG} { yylval.name = xstrdup (yytext);
++<VERS_SCRIPT>{V_TAG} { yylval.name = stat_strdup (yytext);
+ return VERS_TAG; }
+
+ <VERS_START>"{" { BEGIN(VERS_SCRIPT); return *yytext; }
+diff --git a/ld/lexsup.c b/ld/lexsup.c
+index 5399aa45b72..58b9bdd4974 100644
+--- a/ld/lexsup.c
++++ b/ld/lexsup.c
+@@ -1989,16 +1989,6 @@ parse_args (unsigned argc, char **argv)
+ if (opt_dynamic_list != dynamic_list_data)
+ opt_dynamic_list = dynamic_list;
+ }
+- else
+- {
+- /* Free the export list. */
+- for (; head->next != NULL; head = next)
+- {
+- next = head->next;
+- free (head);
+- }
+- free (export_list);
+- }
+ }
+
+ switch (opt_dynamic_list)
+@@ -2022,17 +2012,7 @@ parse_args (unsigned argc, char **argv)
+ break;
+ case symbolic:
+ link_info.symbolic = true;
+- if (link_info.dynamic_list)
+- {
+- struct bfd_elf_version_expr *ent, *next;
+- for (ent = link_info.dynamic_list->head.list; ent; ent = next)
+- {
+- next = ent->next;
+- free (ent);
+- }
+- free (link_info.dynamic_list);
+- link_info.dynamic_list = NULL;
+- }
++ link_info.dynamic_list = NULL;
+ break;
+ case symbolic_functions:
+ link_info.dynamic = true;