diff --git a/SPECS/binutils/CVE-2025-1147.patch b/SPECS/binutils/CVE-2025-1147.patch new file mode 100644 index 00000000000..b37bf9554d9 --- /dev/null +++ b/SPECS/binutils/CVE-2025-1147.patch @@ -0,0 +1,110 @@ +From 7be4186c22f89a87fff048c28910f5d26a0f61ce Mon Sep 17 00:00:00 2001 +From: Dmitry Klochkov +Date: Tue, 9 Sep 2025 12:06:25 +0200 +Subject: [PATCH] nm: fix treating an ifunc symbol as a stab if + '--ifunc-chars=--' is given + +If an ifunc symbol is processed in print_symbol(), a 'type' field of a +'syminfo' structure is set to any character specified by a user with an +'--ifunc-chars' option. But afterwards the 'type' field is used to +check whether a symbol is a stab in print_symbol_info_{bsd,sysv}() +functions in order to print additional stab related data. If the 'type' +field equals '-', a symbol is treated as a stab. If '--ifunc-chars=--' +is given, all ifunc symbols will be treated as stab symbols and +uninitialized stab related fields of the 'syminfo' structure will be +printed which can lead to segmentation fault. + +To fix this, check if a symbol is a stab before override the 'type' +field. Also, add a test case for this fix. + + PR binutils/32556 + * nm.c (extended_symbol_info): Add is_stab. + (print_symbol): Check if a symbol is a stab. + (print_symbol_info_bsd): Use info->is_stab. + (print_symbol_info_sysv): Use info->is_stab. + * testsuite/binutils-all/nm.exp: Test nm --ifunc-chars=--. + +Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32556 +Fixes: e6f6aa8d184 ("Add option to nm to change the characters displayed for ifunc symbols") +Signed-off-by: Dmitry Klochkov + +Upstream Patch Reference: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=patch;h=7be4186c22f89a87fff048c28910f5d26a0f61ce +--- + binutils/nm.c | 10 +++++++--- + binutils/testsuite/binutils-all/nm.exp | 17 +++++++++++++++++ + 2 files changed, 24 insertions(+), 3 deletions(-) + +diff --git a/binutils/nm.c b/binutils/nm.c +index f96cfa31..2370e1ca 100644 +--- a/binutils/nm.c ++++ b/binutils/nm.c +@@ -71,6 +71,7 @@ struct extended_symbol_info + bfd_vma ssize; + elf_symbol_type *elfinfo; + coff_symbol_type *coffinfo; ++ bool is_stab; + /* FIXME: We should add more fields for Type, Line, Section. */ + }; + #define SYM_VALUE(sym) (sym->sinfo->value) +@@ -1193,8 +1194,11 @@ print_symbol (bfd * abfd, + + bfd_get_symbol_info (abfd, sym, &syminfo); + ++ info.is_stab = false; ++ if (syminfo.type == '-') ++ info.is_stab = true; + /* PR 22967 - Distinguish between local and global ifunc symbols. */ +- if (syminfo.type == 'i' ++ else if (syminfo.type == 'i' + && sym->flags & BSF_GNU_INDIRECT_FUNCTION) + { + if (ifunc_type_chars == NULL || ifunc_type_chars[0] == 0) +@@ -1856,7 +1860,7 @@ print_symbol_info_bsd (struct extended_symbol_info *info, bfd *abfd) + + printf (" %c", SYM_TYPE (info)); + +- if (SYM_TYPE (info) == '-') ++ if (info->is_stab) + { + /* A stab. */ + printf (" "); +@@ -1885,7 +1889,7 @@ print_symbol_info_sysv (struct extended_symbol_info *info, bfd *abfd) + + printf ("| %c |", SYM_TYPE (info)); + +- if (SYM_TYPE (info) == '-') ++ if (info->is_stab) + { + /* A stab. */ + printf ("%18s| ", SYM_STAB_NAME (info)); /* (C) Type. */ +diff --git a/binutils/testsuite/binutils-all/nm.exp b/binutils/testsuite/binutils-all/nm.exp +index 91b519d9..4a1a5336 100644 +--- a/binutils/testsuite/binutils-all/nm.exp ++++ b/binutils/testsuite/binutils-all/nm.exp +@@ -323,6 +323,23 @@ if [is_elf_format] { + fail "$testname (local ifunc)" + } + ++ # PR 32556 ++ # Test nm --ifunc-chars=-- ++ ++ set got [binutils_run $NM "$NMFLAGS --ifunc-chars=-- $tmpfile"] ++ ++ if [regexp -line "^\\S+ - global_foo$" $got] then { ++ pass "$testname=-- (global ifunc)" ++ } else { ++ fail "$testname=-- (global ifunc)" ++ } ++ ++ if [regexp -line "^\\S+ - local_foo$" $got] then { ++ pass "$testname=-- (local ifunc)" ++ } else { ++ fail "$testname=-- (local ifunc)" ++ } ++ + if { $verbose < 1 } { + remote_file host delete "tmpdir/ifunc.o" + } +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-1148.patch b/SPECS/binutils/CVE-2025-1148.patch new file mode 100644 index 00000000000..a02ece5b53d --- /dev/null +++ b/SPECS/binutils/CVE-2025-1148.patch @@ -0,0 +1,592 @@ +From d4115c2c8d447e297ae353892de89192c1996211 Mon Sep 17 00:00:00 2001 +From: Alan Modra +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. +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=d4115c2c8d447e297ae353892de89192c1996211 +--- + 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 170e1ed7..343e6c0a 100644 +--- a/ld/ldexp.c ++++ b/ld/ldexp.c +@@ -1606,7 +1606,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; +@@ -1631,7 +1631,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 df7c9cbd..be5a20e2 100644 +--- a/ld/ldfile.c ++++ b/ld/ldfile.c +@@ -425,18 +425,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 (); + } +@@ -455,18 +448,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 081176ba..98c4030d 100644 +--- a/ld/ldgram.y ++++ b/ld/ldgram.y +@@ -508,7 +508,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; +@@ -526,7 +526,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; +@@ -547,7 +547,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; +@@ -560,7 +560,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; +@@ -569,7 +569,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; +@@ -580,7 +580,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; +@@ -589,7 +589,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; +@@ -889,7 +889,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; +@@ -898,7 +898,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; +@@ -1188,8 +1188,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 a357f802..1f658d16 100644 +--- a/ld/ldlang.c ++++ b/ld/ldlang.c +@@ -177,6 +177,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. */ + +@@ -266,15 +283,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 +@@ -705,7 +720,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; +@@ -736,8 +751,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); + } + + +@@ -1405,7 +1418,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; +@@ -1460,7 +1473,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; + } +@@ -2905,11 +2918,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; +@@ -3924,7 +3935,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); +@@ -4003,7 +4014,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; + } + +@@ -9004,7 +9015,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; +@@ -9194,7 +9205,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; +@@ -9374,13 +9385,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 +@@ -9395,7 +9403,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; +@@ -9432,7 +9440,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; +@@ -9514,15 +9523,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; +@@ -9562,7 +9563,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; + } + +@@ -9655,7 +9655,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) +@@ -9688,7 +9688,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); + +@@ -9699,8 +9699,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; + } +@@ -9764,8 +9762,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; + } +@@ -9788,7 +9786,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 463cce39..701b9ba3 100644 +--- a/ld/ldlang.h ++++ b/ld/ldlang.h +@@ -658,6 +658,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 1a6be1b6..24ebaec2 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; + } +@@ -388,32 +389,32 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* + + {FILENAMECHAR1}{NOCFILENAMECHAR}* { + /* Filename without commas, needed to parse mri stuff */ +- yylval.name = xstrdup (yytext); ++ yylval.name = stat_strdup (yytext); + return NAME; + } + + + {FILENAMECHAR1}{FILENAMECHAR}* { +- yylval.name = xstrdup (yytext); ++ yylval.name = stat_strdup (yytext); + return NAME; + } + "="{FILENAMECHAR1}{FILENAMECHAR}* { + /* Filename to be prefixed by --sysroot or when non-sysrooted, nothing. */ +- yylval.name = xstrdup (yytext); ++ yylval.name = stat_strdup (yytext); + return NAME; + } + "-l"{FILENAMECHAR}+ { +- yylval.name = xstrdup (yytext + 2); ++ yylval.name = stat_strdup (yytext + 2); + return LNAME; + } + {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. */ + "/DISCARD/" { +- yylval.name = xstrdup (yytext); ++ yylval.name = stat_strdup (yytext); + return NAME; + } + {WILDCHAR}* { +@@ -428,14 +429,14 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* + } + else + { +- yylval.name = xstrdup (yytext); ++ yylval.name = stat_strdup (yytext); + return NAME; + } + } + + "\""[^\"]*"\"" { + /* 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; + } + +@@ -454,10 +455,10 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)* + + extern { RTOKEN(EXTERN); } + +-{V_IDENTIFIER} { yylval.name = xstrdup (yytext); ++{V_IDENTIFIER} { yylval.name = stat_strdup (yytext); + return VERS_IDENTIFIER; } + +-{V_TAG} { yylval.name = xstrdup (yytext); ++{V_TAG} { yylval.name = stat_strdup (yytext); + return VERS_TAG; } + + "{" { BEGIN(VERS_SCRIPT); return *yytext; } +diff --git a/ld/lexsup.c b/ld/lexsup.c +index fe872231..ae2e91ed 100644 +--- a/ld/lexsup.c ++++ b/ld/lexsup.c +@@ -1947,16 +1947,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) +@@ -1980,17 +1970,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; +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-11839.patch b/SPECS/binutils/CVE-2025-11839.patch new file mode 100644 index 00000000000..33cd88e026a --- /dev/null +++ b/SPECS/binutils/CVE-2025-11839.patch @@ -0,0 +1,28 @@ +From 12ef7d5b7b02d0023db645d86eb9d0797bc747fe Mon Sep 17 00:00:00 2001 +From: Nick Clifton +Date: Mon, 3 Nov 2025 11:49:02 +0000 +Subject: [PATCH] Remove call to abort in the DGB debug format printing code, + thus allowing the display of a fuzzed input file to complete without + triggering an abort. + +PR 33448 +Upstream Patch Reference: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=patch;h=12ef7d5b7b02d0023db645d86eb9d0797bc747fe +--- + binutils/prdbg.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/binutils/prdbg.c b/binutils/prdbg.c +index fb351476..15f40d44 100644 +--- a/binutils/prdbg.c ++++ b/binutils/prdbg.c +@@ -2449,7 +2449,6 @@ tg_tag_type (void *p, const char *name, unsigned int id, + t = "union class "; + break; + default: +- abort (); + return false; + } + +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-69645.patch b/SPECS/binutils/CVE-2025-69645.patch new file mode 100644 index 00000000000..cd82fe43d6e --- /dev/null +++ b/SPECS/binutils/CVE-2025-69645.patch @@ -0,0 +1,126 @@ +From cdb728d4da6184631989b192f1022c219dea7677 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Sun, 30 Nov 2025 12:51:54 +1030 +Subject: [PATCH] PR 33637, abort in byte_get + +When DWARF5 support was added to binutils in commit 77145576fadc, +the loop over CUs in process_debug_info set do_types when finding a +DW_UT_type unit, in order to process the signature and type offset +entries. Unfortunately that broke debug_information/debug_info_p +handling, which previously was allocated and initialised for each unit +in .debug_info. debug_info_p was NULL when processing a DWARF4 +.debug_types section. After the 77145576fadc change it was possible +for debug_infp_p to be non-NULL but point to zeroed data, in +particular a zeroed offset_size. A zero for offset_size led to the +byte_get_little_endian abort triggered by the fuzzer testcase. + +I haven't investigated whether there is any need for a valid +offset_size when processing a non-fuzzed DWARF4 .debug_types section. +Presumably we'd have found that out in the last 6 years if that was +the case. We don't want to change debug_information[] for +.debug_types! + + PR 33637 + * dwarf.c (process_debug_info): Don't change DO_TYPES flag bit + depending on cu_unit_type. Instead test cu_unit_type along + with DO_TYPES to handle signature and type_offset for a type + unit. Move find_cu_tu_set_v2 call a little later. + +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=cdb728d4da6184631989b192f1022c219dea7677 +--- + binutils/dwarf.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/binutils/dwarf.c b/binutils/dwarf.c +index ea83e35a..25013132 100644 +--- a/binutils/dwarf.c ++++ b/binutils/dwarf.c +@@ -3707,8 +3707,6 @@ process_debug_info (struct dwarf_section * section, + + SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu); + +- this_set = find_cu_tu_set_v2 (cu_offset, do_types); +- + if (compunit.cu_version < 5) + { + compunit.cu_unit_type = DW_UT_compile; +@@ -3718,8 +3716,6 @@ process_debug_info (struct dwarf_section * section, + else + { + SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu); +- do_types = (compunit.cu_unit_type == DW_UT_type); +- + SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu); + } + +@@ -3733,6 +3729,7 @@ process_debug_info (struct dwarf_section * section, + SAFE_BYTE_GET_AND_INC (dwo_id, hdrptr, 8, end_cu); + } + ++ this_set = find_cu_tu_set_v2 (cu_offset, do_types); + if (this_set == NULL) + { + abbrev_base = 0; +@@ -3789,8 +3786,6 @@ process_debug_info (struct dwarf_section * section, + + SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end_cu); + +- this_set = find_cu_tu_set_v2 (cu_offset, do_types); +- + if (compunit.cu_version < 5) + { + compunit.cu_unit_type = DW_UT_compile; +@@ -3800,13 +3795,12 @@ process_debug_info (struct dwarf_section * section, + else + { + SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end_cu); +- do_types = (compunit.cu_unit_type == DW_UT_type); +- + SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end_cu); + } + + SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end_cu); + ++ this_set = find_cu_tu_set_v2 (cu_offset, do_types); + if (this_set == NULL) + { + abbrev_base = 0; +@@ -3838,7 +3832,7 @@ process_debug_info (struct dwarf_section * section, + compunit.cu_pointer_size = offset_size; + } + +- if (do_types) ++ if (do_types || compunit.cu_unit_type == DW_UT_type) + { + SAFE_BYTE_GET_AND_INC (signature, hdrptr, 8, end_cu); + SAFE_BYTE_GET_AND_INC (type_offset, hdrptr, offset_size, end_cu); +@@ -3853,7 +3847,7 @@ process_debug_info (struct dwarf_section * section, + if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info) + && num_debug_info_entries == 0 + && alloc_num_debug_info_entries > unit +- && ! do_types) ++ && !do_types) + { + free_debug_information (&debug_information[unit]); + memset (&debug_information[unit], 0, sizeof (*debug_information)); +@@ -3884,7 +3878,7 @@ process_debug_info (struct dwarf_section * section, + printf (_(" Abbrev Offset: %#" PRIx64 "\n"), + compunit.cu_abbrev_offset); + printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); +- if (do_types) ++ if (do_types || compunit.cu_unit_type == DW_UT_type) + { + printf (_(" Signature: %#" PRIx64 "\n"), signature); + printf (_(" Type Offset: %#" PRIx64 "\n"), type_offset); +@@ -4121,7 +4115,7 @@ process_debug_info (struct dwarf_section * section, + we need to process .debug_loc and .debug_ranges sections. */ + if ((do_loc || do_debug_loc || do_debug_ranges || do_debug_info) + && num_debug_info_entries == 0 +- && ! do_types) ++ && !do_types) + { + if (num_units > alloc_num_debug_info_entries) + num_debug_info_entries = alloc_num_debug_info_entries; +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-69646.patch b/SPECS/binutils/CVE-2025-69646.patch new file mode 100644 index 00000000000..184b7135abf --- /dev/null +++ b/SPECS/binutils/CVE-2025-69646.patch @@ -0,0 +1,387 @@ +From 598704a00cbac5e85c2bedd363357b5bf6fcee33 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Sat, 22 Nov 2025 09:22:10 +1030 +Subject: [PATCH] PR 33638, debug_rnglists output + +The fuzzed testcase in this PR continuously outputs an error about +the debug_rnglists header. Fixed by taking notice of the error and +stopping output. The patch also limits the length in all cases, not +just when a relocation is present, and limits the offset entry count +read from the header. I removed the warning and the test for relocs +because the code can't work reliably with unresolved relocs in the +length field. + + PR 33638 + * dwarf.c (display_debug_rnglists_list): Return bool. Rename + "inital_length" to plain "length". Verify length is large + enough to read header. Limit length to rest of section. + Similarly limit offset_entry_count. + (display_debug_ranges): Check display_debug_rnglists_unit_header + return status. Stop output on error. + +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=598704a00cbac5e85c2bedd363357b5bf6fcee33 +--- + binutils/dwarf.c | 264 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 201 insertions(+), 63 deletions(-) + +diff --git a/binutils/dwarf.c b/binutils/dwarf.c +index 25013132..6e31c7e1 100644 +--- a/binutils/dwarf.c ++++ b/binutils/dwarf.c +@@ -7964,7 +7964,7 @@ range_entry_compar (const void *ap, const void *bp) + return (a > b) - (b > a); + } + +-static void ++static unsigned char * + display_debug_ranges_list (unsigned char * start, + unsigned char * finish, + unsigned int pointer_size, +@@ -8011,6 +8011,7 @@ display_debug_ranges_list (unsigned char * start, + + putchar ('\n'); + } ++ return start; + } + + static unsigned char * +@@ -8247,23 +8248,123 @@ display_debug_rnglists (struct dwarf_section *section) + putchar ('\n'); + return 1; + } ++static bool ++display_debug_rnglists_unit_header (struct dwarf_section * section, ++ uint64_t * unit_offset, ++ unsigned char * poffset_size) ++{ ++ uint64_t start_offset = *unit_offset; ++ unsigned char * p = section->start + start_offset; ++ unsigned char * finish = section->start + section->size; ++ unsigned char * hdr; ++ uint64_t length; ++ unsigned char segment_selector_size; ++ unsigned int offset_entry_count; ++ unsigned int i; ++ unsigned short version; ++ unsigned char address_size = 0; ++ unsigned char offset_size; ++ ++ /* Get and check the length of the block. */ ++ SAFE_BYTE_GET_AND_INC (length, p, 4, finish); ++ ++ if (length == 0xffffffff) ++ { ++ /* This section is 64-bit DWARF 3. */ ++ SAFE_BYTE_GET_AND_INC (length, p, 8, finish); ++ *poffset_size = offset_size = 8; ++ } ++ else ++ *poffset_size = offset_size = 4; ++ ++ if (length < 8) ++ return false; ++ ++ /* Get the other fields in the header. */ ++ hdr = p; ++ SAFE_BYTE_GET_AND_INC (version, p, 2, finish); ++ SAFE_BYTE_GET_AND_INC (address_size, p, 1, finish); ++ SAFE_BYTE_GET_AND_INC (segment_selector_size, p, 1, finish); ++ SAFE_BYTE_GET_AND_INC (offset_entry_count, p, 4, finish); ++ ++ printf (_(" Table at Offset: %#" PRIx64 ":\n"), start_offset); ++ printf (_(" Length: %#" PRIx64 "\n"), length); ++ printf (_(" DWARF version: %u\n"), version); ++ printf (_(" Address size: %u\n"), address_size); ++ printf (_(" Segment size: %u\n"), segment_selector_size); ++ printf (_(" Offset entries: %u\n"), offset_entry_count); ++ ++ if (length > (size_t) (finish - hdr)) ++ length = finish - hdr; ++ ++ /* Report the next unit offset to the caller. */ ++ *unit_offset = (hdr - section->start) + length; ++ ++ /* Check the fields. */ ++ if (segment_selector_size != 0) ++ { ++ warn (_("The %s section contains " ++ "unsupported segment selector size: %d.\n"), ++ section->name, segment_selector_size); ++ return false; ++ } ++ ++ if (version < 5) ++ { ++ warn (_("Only DWARF version 5+ debug_rnglists info " ++ "is currently supported.\n")); ++ return false; ++ } ++ ++ uint64_t max_off_count = (length - 8) / offset_size; ++ if (offset_entry_count > max_off_count) ++ offset_entry_count = max_off_count; ++ if (offset_entry_count != 0) ++ { ++ printf (_("\n Offsets starting at %#tx:\n"), p - section->start); ++ ++ for (i = 0; i < offset_entry_count; i++) ++ { ++ uint64_t entry; ++ ++ SAFE_BYTE_GET_AND_INC (entry, p, offset_size, finish); ++ printf (_(" [%6u] %#" PRIx64 "\n"), i, entry); ++ } ++ } ++ ++ return true; ++} ++ ++static bool ++is_range_list_for_this_section (bool is_rnglists, unsigned int version) ++{ ++ if (is_rnglists && version > 4) ++ return true; ++ ++ if (!is_rnglists && version < 5) ++ return true; ++ ++ return false; ++} + + static int + display_debug_ranges (struct dwarf_section *section, +- void *file ATTRIBUTE_UNUSED) ++ void *file ATTRIBUTE_UNUSED) + { + unsigned char *start = section->start; + unsigned char *last_start = start; ++ unsigned char *last_end; + uint64_t bytes = section->size; + unsigned char *section_begin = start; + unsigned char *finish = start + bytes; + unsigned int num_range_list, i; + struct range_entry *range_entries; + struct range_entry *range_entry_fill; +- int is_rnglists = strstr (section->name, "debug_rnglists") != NULL; +- /* Initialize it due to a false compiler warning. */ +- unsigned char address_size = 0; ++ bool is_rnglists = strstr (section->name, "debug_rnglists") != NULL; + uint64_t last_offset = 0; ++ uint64_t next_rnglists_cu_offset = 0; ++ unsigned char offset_size; ++ bool ok_header = true; + + if (bytes == 0) + { +@@ -8272,32 +8373,28 @@ display_debug_ranges (struct dwarf_section *section, + } + + introduce (section, false); +- +- if (is_rnglists) +- return display_debug_rnglists (section); + + if (load_debug_info (file) == 0) + { + warn (_("Unable to load/parse the .debug_info section, so cannot interpret the %s section.\n"), +- section->name); ++ section->name); + return 0; + } + + num_range_list = 0; + for (i = 0; i < num_debug_info_entries; i++) +- num_range_list += debug_information [i].num_range_lists; ++ if (is_range_list_for_this_section (is_rnglists, debug_information[i].dwarf_version)) ++ num_range_list += debug_information[i].num_range_lists; + + if (num_range_list == 0) + { + /* This can happen when the file was compiled with -gsplit-debug +- which removes references to range lists from the primary .o file. */ +- printf (_("No range lists in .debug_info section.\n")); ++ which removes references to range lists from the primary .o file. */ ++ printf (_("No range lists referenced by .debug_info section.\n")); + return 1; + } + +- range_entries = (struct range_entry *) +- xmalloc (sizeof (*range_entries) * num_range_list); +- range_entry_fill = range_entries; ++ range_entry_fill = range_entries = XNEWVEC (struct range_entry, num_range_list); + + for (i = 0; i < num_debug_info_entries; i++) + { +@@ -8305,23 +8402,27 @@ display_debug_ranges (struct dwarf_section *section, + unsigned int j; + + for (j = 0; j < debug_info_p->num_range_lists; j++) +- { +- range_entry_fill->ranges_offset = debug_info_p->range_lists[j]; +- range_entry_fill->debug_info_p = debug_info_p; +- range_entry_fill++; +- } +- } +- ++ { ++ if (is_range_list_for_this_section (is_rnglists, debug_info_p->dwarf_version)) ++ { ++ range_entry_fill->ranges_offset = debug_info_p->range_lists[j]; ++ range_entry_fill->debug_info_p = debug_info_p; ++ range_entry_fill++; ++ } ++ } ++ } ++ ++ assert (range_entry_fill >= range_entries); ++ assert (num_range_list >= (unsigned int)(range_entry_fill - range_entries)); ++ num_range_list = range_entry_fill - range_entries; + qsort (range_entries, num_range_list, sizeof (*range_entries), +- range_entry_compar); +- +- if (dwarf_check != 0 && range_entries[0].ranges_offset != 0) +- warn (_("Range lists in %s section start at %#" PRIx64 "\n"), +- section->name, range_entries[0].ranges_offset); ++ range_entry_compar); + + putchar ('\n'); +- printf (_(" Offset Begin End\n")); ++ if (!is_rnglists) ++ printf (_(" Offset Begin End\n")); + ++ last_end = NULL; + for (i = 0; i < num_range_list; i++) + { + struct range_entry *range_entry = &range_entries[i]; +@@ -8331,56 +8432,93 @@ display_debug_ranges (struct dwarf_section *section, + unsigned char *next; + uint64_t base_address; + +- pointer_size = (is_rnglists ? address_size : debug_info_p->pointer_size); ++ pointer_size = debug_info_p->pointer_size; + offset = range_entry->ranges_offset; + base_address = debug_info_p->base_address; + + /* PR 17512: file: 001-101485-0.001:0.1. */ + if (pointer_size < 2 || pointer_size > 8) +- { +- warn (_("Corrupt pointer size (%d) in debug entry at offset %#" PRIx64 "\n"), +- pointer_size, offset); +- continue; +- } ++ { ++ warn (_("Corrupt pointer size (%d) in debug entry at offset %#" PRIx64 "\n"), ++ pointer_size, offset); ++ continue; ++ } + + if (offset > (size_t) (finish - section_begin)) +- { +- warn (_("Corrupt offset (%#" PRIx64 ") in range entry %u\n"), +- offset, i); +- continue; +- } +- +- next = section_begin + offset + debug_info_p->rnglists_base; +- ++ { ++ warn (_("Corrupt offset (%#" PRIx64 ") in range entry %u\n"), ++ offset, i); ++ continue; ++ } ++ ++ /* If we've moved on to the next compile unit in the rnglists section - dump the unit header(s). */ ++ if (is_rnglists && next_rnglists_cu_offset < offset) ++ { ++ while (ok_header && next_rnglists_cu_offset < offset) ++ ok_header = display_debug_rnglists_unit_header (section, ++ &next_rnglists_cu_offset, ++ &offset_size); ++ if (!ok_header) ++ break; ++ printf (_(" Offset Begin End\n")); ++ } ++ ++ next = section_begin + offset; /* Offset is from the section start, the base has already been added. */ ++ ++ if (i == 0) ++ { ++ last_end = section_begin; ++ if (is_rnglists) ++ last_end += 2 * offset_size - 4 + 2 + 1 + 1 + 4; ++ } + /* If multiple DWARF entities reference the same range then we will +- have multiple entries in the `range_entries' list for the same +- offset. Thanks to the sort above these will all be consecutive in +- the `range_entries' list, so we can easily ignore duplicates +- here. */ ++ have multiple entries in the `range_entries' list for the same ++ offset. Thanks to the sort above these will all be consecutive in ++ the `range_entries' list, so we can easily ignore duplicates ++ here. */ + if (i > 0 && last_offset == offset) +- continue; ++ continue; + last_offset = offset; + +- if (dwarf_check != 0 && i > 0) +- { +- if (start < next) +- warn (_("There is a hole [%#tx - %#tx] in %s section.\n"), +- start - section_begin, next - section_begin, section->name); +- else if (start > next) +- { +- if (next == last_start) +- continue; +- warn (_("There is an overlap [%#tx - %#tx] in %s section.\n"), +- start - section_begin, next - section_begin, section->name); +- } +- } ++ if (dwarf_check != 0) ++ { ++ if (start < next) ++ { ++ if (last_end != next) ++ warn (_("There is a hole [%#tx - %#tx] in %s section.\n"), ++ last_end - section_begin, next - section_begin, ++ section->name); ++ } ++ else if (start > next) ++ { ++ if (next == last_start) ++ continue; ++ warn (_("There is an overlap [%#tx - %#tx] in %s section.\n"), ++ start - section_begin, next - section_begin, section->name); ++ } ++ } + + start = next; + last_start = next; + +- display_debug_ranges_list +- (start, finish, pointer_size, offset, base_address); +- } ++ if (is_rnglists) ++ last_end ++ = display_debug_rnglists_list ++ (start, finish, pointer_size, offset, base_address, ++ debug_info_p->addr_base); ++ else ++ last_end ++ = display_debug_ranges_list ++ (start, finish, pointer_size, offset, base_address); ++ } ++ ++ /* Display trailing empty (or unreferenced) compile units, if any. */ ++ if (is_rnglists && ok_header) ++ while (next_rnglists_cu_offset < section->size) ++ if (!display_debug_rnglists_unit_header (section, ++ &next_rnglists_cu_offset, ++ &offset_size)) ++ break; + putchar ('\n'); + + free (range_entries); +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-69647.patch b/SPECS/binutils/CVE-2025-69647.patch new file mode 100644 index 00000000000..cdbdb018635 --- /dev/null +++ b/SPECS/binutils/CVE-2025-69647.patch @@ -0,0 +1,456 @@ +From 455446bbdc8675f34808187de2bbad4682016ff7 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Sat, 22 Nov 2025 09:52:18 +1030 +Subject: [PATCH] PR 33639 .debug_loclists output + +The fuzzed testcase in this PR prints an almost endless table of +offsets, due to a bogus offset count. Limit that count, and the total +length too. + PR 33639 + * dwarf.c (display_loclists_unit_header): Return error on + length too small to read header. Limit length to section + size. Limit offset count similarly. + +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=455446bbdc8675f34808187de2bbad4682016ff7 + +--- + binutils/dwarf.c | 336 +++++++++++++++++------------------------------ + 1 file changed, 118 insertions(+), 218 deletions(-) + +diff --git a/binutils/dwarf.c b/binutils/dwarf.c +index 3090af89..0523c308 100644 +--- a/binutils/dwarf.c ++++ b/binutils/dwarf.c +@@ -7005,202 +7005,82 @@ loc_offsets_compar (const void *ap, const void *bp) + return ret; + } + +-static int +-display_offset_entry_loclists (struct dwarf_section *section) +-{ +- unsigned char * start = section->start; +- unsigned char * const end = start + section->size; +- +- introduce (section, false); ++/* Reads and dumps the DWARFv5 loclists compiler unit header, ++ including the offset table. ++ Returns the offset of the next compile unit header. */ + +- do ++static uint64_t ++display_loclists_unit_header (struct dwarf_section * section, ++ uint64_t header_offset, ++ uint32_t * offset_count, ++ unsigned char ** loclists_start) ++{ ++ uint64_t length; ++ unsigned char *start = section->start + header_offset; ++ unsigned char *end = section->start + section->size; ++ unsigned short version; ++ unsigned char address_size; ++ unsigned char segment_selector_size; ++ bool is_64bit; ++ uint32_t i; ++ ++ SAFE_BYTE_GET_AND_INC (length, start, 4, end); ++ if (length == 0xffffffff) + { +- uint64_t length; +- unsigned short version; +- unsigned char address_size; +- unsigned char segment_selector_size; +- uint32_t offset_entry_count; +- uint32_t i; +- bool is_64bit; +- +- printf (_("Table at Offset %#tx\n"), start - section->start); +- +- SAFE_BYTE_GET_AND_INC (length, start, 4, end); +- if (length == 0xffffffff) +- { +- is_64bit = true; +- SAFE_BYTE_GET_AND_INC (length, start, 8, end); +- } +- else +- is_64bit = false; ++ is_64bit = true; ++ SAFE_BYTE_GET_AND_INC (length, start, 8, end); ++ } ++ else ++ is_64bit = false; ++ if (length < 8) ++ return (uint64_t) -1; + +- SAFE_BYTE_GET_AND_INC (version, start, 2, end); +- SAFE_BYTE_GET_AND_INC (address_size, start, 1, end); +- SAFE_BYTE_GET_AND_INC (segment_selector_size, start, 1, end); +- SAFE_BYTE_GET_AND_INC (offset_entry_count, start, 4, end); ++ printf (_("Table at Offset %#" PRIx64 "\n"), header_offset); ++ header_offset = start - section->start; + +- printf (_(" Length: %#" PRIx64 "\n"), length); +- printf (_(" DWARF version: %u\n"), version); +- printf (_(" Address size: %u\n"), address_size); +- printf (_(" Segment size: %u\n"), segment_selector_size); +- printf (_(" Offset entries: %u\n"), offset_entry_count); ++ SAFE_BYTE_GET_AND_INC (version, start, 2, end); ++ SAFE_BYTE_GET_AND_INC (address_size, start, 1, end); ++ SAFE_BYTE_GET_AND_INC (segment_selector_size, start, 1, end); ++ SAFE_BYTE_GET_AND_INC (*offset_count, start, 4, end); + +- if (version < 5) +- { +- warn (_("The %s section contains a corrupt or " +- "unsupported version number: %d.\n"), +- section->name, version); +- return 0; +- } ++ printf (_(" Length: %#" PRIx64 "\n"), length); ++ printf (_(" DWARF version: %u\n"), version); ++ printf (_(" Address size: %u\n"), address_size); ++ printf (_(" Segment size: %u\n"), segment_selector_size); ++ printf (_(" Offset entries: %u\n"), *offset_count); + +- if (segment_selector_size != 0) +- { +- warn (_("The %s section contains an " +- "unsupported segment selector size: %d.\n"), +- section->name, segment_selector_size); +- return 0; +- } ++ if (length > section->size - header_offset) ++ length = section->size - header_offset; + +- if (offset_entry_count == 0) +- { +- warn (_("The %s section contains a table without offset\n"), +- section->name); +- return 0; +- } ++ if (segment_selector_size != 0) ++ { ++ warn (_("The %s section contains an " ++ "unsupported segment selector size: %d.\n"), ++ section->name, segment_selector_size); ++ return (uint64_t) -1; ++ } + ++ uint64_t max_off_count = length >> (is_64bit ? 3 : 2); ++ if (*offset_count > max_off_count) ++ *offset_count = max_off_count; ++ if (*offset_count) ++ { + printf (_("\n Offset Entries starting at %#tx:\n"), + start - section->start); + +- for (i = 0; i < offset_entry_count; i++) ++ for (i = 0; i < *offset_count; i++) + { + uint64_t entry; + + SAFE_BYTE_GET_AND_INC (entry, start, is_64bit ? 8 : 4, end); + printf (_(" [%6u] %#" PRIx64 "\n"), i, entry); + } +- +- putchar ('\n'); +- +- uint32_t j; +- +- for (j = 1, i = 0; i < offset_entry_count;) +- { +- unsigned char lle; +- uint64_t base_address = 0; +- uint64_t begin; +- uint64_t finish; +- uint64_t off = start - section->start; +- +- if (j != i) +- { +- printf (_(" Offset Entry %u\n"), i); +- j = i; +- } +- +- printf (" "); +- print_hex (off, 4); +- +- SAFE_BYTE_GET_AND_INC (lle, start, 1, end); +- +- switch (lle) +- { +- case DW_LLE_end_of_list: +- printf (_("\n\n")); +- i ++; +- continue; +- +- case DW_LLE_base_addressx: +- READ_ULEB (base_address, start, end); +- print_hex (base_address, address_size); +- printf (_("(index into .debug_addr) ")); +- base_address = fetch_indexed_addr (base_address, address_size); +- print_hex (base_address, address_size); +- printf (_("(base address)\n")); +- continue; +- +- case DW_LLE_startx_endx: +- READ_ULEB (begin, start, end); +- begin = fetch_indexed_addr (begin, address_size); +- READ_ULEB (finish, start, end); +- finish = fetch_indexed_addr (finish, address_size); +- break; +- +- case DW_LLE_startx_length: +- READ_ULEB (begin, start, end); +- begin = fetch_indexed_addr (begin, address_size); +- READ_ULEB (finish, start, end); +- finish += begin; +- break; +- +- case DW_LLE_offset_pair: +- READ_ULEB (begin, start, end); +- begin += base_address; +- READ_ULEB (finish, start, end); +- finish += base_address; +- break; +- +- case DW_LLE_default_location: +- begin = finish = 0; +- break; +- +- case DW_LLE_base_address: +- SAFE_BYTE_GET_AND_INC (base_address, start, address_size, end); +- print_hex (base_address, address_size); +- printf (_("(base address)\n")); +- continue; +- +- case DW_LLE_start_end: +- SAFE_BYTE_GET_AND_INC (begin, start, address_size, end); +- SAFE_BYTE_GET_AND_INC (finish, start, address_size, end); +- break; +- +- case DW_LLE_start_length: +- SAFE_BYTE_GET_AND_INC (begin, start, address_size, end); +- READ_ULEB (finish, start, end); +- finish += begin; +- break; +- +- default: +- error (_("Invalid location list entry type %d\n"), lle); +- return 0; +- } +- +- if (start == end) +- { +- warn (_("Location list starting at offset %#" PRIx64 +- " is not terminated.\n"), off); +- break; +- } +- +- print_hex (begin, address_size); +- print_hex (finish, address_size); +- +- if (begin == finish) +- fputs (_("(start == end)"), stdout); +- else if (begin > finish) +- fputs (_("(start > end)"), stdout); +- +- /* Read the counted location descriptions. */ +- READ_ULEB (length, start, end); +- +- if (length > (size_t) (end - start)) +- { +- warn (_("Location list starting at offset %#" PRIx64 +- " is not terminated.\n"), off); +- break; +- } +- +- (void) decode_location_expression (start, address_size, address_size, +- version, length, 0, section); +- start += length; +- putchar ('\n'); +- } +- +- putchar ('\n'); + } +- while (start < end); + +- return 1; ++ putchar ('\n'); ++ *loclists_start = start; ++ ++ return header_offset + length; + } + + static int +@@ -7221,8 +7101,8 @@ display_debug_loc (struct dwarf_section *section, void *file) + unsigned int *array = NULL; + const char *suffix = strrchr (section->name, '.'); + bool is_dwo = false; +- int is_loclists = strstr (section->name, "debug_loclists") != NULL; +- uint64_t header_size = 0; ++ bool is_loclists = strstr (section->name, "debug_loclists") != NULL; ++ uint64_t next_header_offset = 0; + + if (suffix && strcmp (suffix, ".dwo") == 0) + is_dwo = true; +@@ -7270,10 +7150,10 @@ display_debug_loc (struct dwarf_section *section, void *file) + + SAFE_BYTE_GET_AND_INC (offset_entry_count, hdrptr, 4, end); + +- if (offset_entry_count != 0) +- return display_offset_entry_loclists (section); ++ /*if (offset_entry_count != 0) ++ return display_offset_entry_loclists (section);*/ + +- header_size = hdrptr - section_begin; ++ //header_size = hdrptr - section_begin; + } + + if (load_debug_info (file) == 0) +@@ -7328,14 +7208,6 @@ display_debug_loc (struct dwarf_section *section, void *file) + if (!seen_first_offset) + error (_("No location lists in .debug_info section!\n")); + +- if (debug_information [first].num_loc_offsets > 0 +- && debug_information [first].loc_offsets [0] != header_size +- && debug_information [first].loc_views [0] != header_size) +- warn (_("Location lists in %s section start at %#" PRIx64 +- " rather than %#" PRIx64 "\n"), +- section->name, debug_information [first].loc_offsets [0], +- header_size); +- + if (!locs_sorted) + array = (unsigned int *) xcmalloc (num_loc_list, sizeof (unsigned int)); + +@@ -7344,7 +7216,8 @@ display_debug_loc (struct dwarf_section *section, void *file) + if (reloc_at (section, 0)) + printf (_(" Warning: This section has relocations - addresses seen here may not be accurate.\n\n")); + +- printf (_(" Offset Begin End Expression\n")); ++ if (!is_loclists) ++ printf (_(" Offset Begin End Expression\n")); + + for (i = first; i < num_debug_info_entries; i++) + { +@@ -7352,56 +7225,83 @@ display_debug_loc (struct dwarf_section *section, void *file) + uint64_t base_address; + unsigned int k; + int has_frame_base; +- ++ debug_info *debug_info_p = debug_information + i; ++ uint32_t offset_count; ++ ++ /* .debug_loclists section is loaded into debug_information as ++ DWARF-5 debug info and .debug_loc section is loaded into ++ debug_information as pre-DWARF-5 debug info. When dumping ++ .debug_loc section, we should only process pre-DWARF-5 debug ++ info in debug_information. When dumping .debug_loclists ++ section, we should only process DWARF-5 info in ++ debug_information. */ ++ if ((debug_info_p->dwarf_version >= 5) != is_loclists) ++ continue; ++ + if (!locs_sorted) + { +- for (k = 0; k < debug_information [i].num_loc_offsets; k++) ++ for (k = 0; k < debug_info_p->num_loc_offsets; k++) + array[k] = k; +- loc_offsets = debug_information [i].loc_offsets; +- loc_views = debug_information [i].loc_views; +- qsort (array, debug_information [i].num_loc_offsets, ++ loc_offsets = debug_info_p->loc_offsets; ++ loc_views = debug_info_p->loc_views; ++ qsort (array, debug_info_p->num_loc_offsets, + sizeof (*array), loc_offsets_compar); + } + + /* .debug_loclists has a per-unit header. + Update start if we are detecting it. */ +- if (debug_information [i].dwarf_version == 5) ++ if (debug_info_p->dwarf_version >= 5) + { + j = locs_sorted ? 0 : array [0]; + +- if (debug_information [i].num_loc_offsets) +- offset = debug_information [i].loc_offsets [j]; ++ if (debug_info_p->num_loc_offsets) ++ offset = debug_info_p->loc_offsets [j]; + +- if (debug_information [i].num_loc_views) +- voffset = debug_information [i].loc_views [j]; ++ if (debug_info_p->num_loc_views) ++ voffset = debug_info_p->loc_views [j]; + +- /* Assume that the size of the header is constant across CUs. */ +- if (((start - section_begin) + header_size == offset) +- || ((start -section_begin) + header_size == voffset)) +- start += header_size; ++ /* Parse and dump unit headers in loclists. ++ This will misbehave if the order of CUs in debug_info ++ doesn't match the one in loclists. */ ++ if (next_header_offset < offset) ++ { ++ while (next_header_offset < offset) ++ { ++ next_header_offset = display_loclists_unit_header ++ (section, next_header_offset, &offset_count, &start); ++ ++ if (next_header_offset == (uint64_t)-1) ++ /* Header parsing error. */ ++ return 0; ++ } ++ ++ printf (_("\ ++ Offset Begin End Expression\n")); ++ } + } + + int adjacent_view_loclists = 1; +- for (k = 0; k < debug_information [i].num_loc_offsets; k++) ++ ++ for (k = 0; k < debug_info_p->num_loc_offsets; k++) + { + j = locs_sorted ? k : array[k]; + if (k +- && (debug_information [i].loc_offsets [locs_sorted +- ? k - 1 : array [k - 1]] +- == debug_information [i].loc_offsets [j]) +- && (debug_information [i].loc_views [locs_sorted +- ? k - 1 : array [k - 1]] +- == debug_information [i].loc_views [j])) ++ && (debug_info_p->loc_offsets [locs_sorted ++ ? k - 1 : array [k - 1]] ++ == debug_info_p->loc_offsets [j]) ++ && (debug_info_p->loc_views [locs_sorted ++ ? k - 1 : array [k - 1]] ++ == debug_info_p->loc_views [j])) + continue; +- has_frame_base = debug_information [i].have_frame_base [j]; +- offset = debug_information [i].loc_offsets [j]; ++ has_frame_base = debug_info_p->have_frame_base [j]; ++ offset = debug_info_p->loc_offsets [j]; + next = section_begin + offset; +- voffset = debug_information [i].loc_views [j]; ++ voffset = debug_info_p->loc_views [j]; + if (voffset != (uint64_t) -1) + vnext = section_begin + voffset; + else + vnext = NULL; +- base_address = debug_information [i].base_address; ++ base_address = debug_info_p->base_address; + + if (vnext && vnext < next) + { +@@ -7457,8 +7357,8 @@ display_debug_loc (struct dwarf_section *section, void *file) + if (is_dwo) + warn (_("DWO is not yet supported.\n")); + else +- display_loclists_list (section, &start, i, offset, base_address, +- &vstart, has_frame_base); ++ display_loclists_list (section, &start, debug_info_p, offset, ++ base_address, &vstart, has_frame_base); + } + + /* FIXME: this arrangement is quite simplistic. Nothing +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-69649.patch b/SPECS/binutils/CVE-2025-69649.patch new file mode 100644 index 00000000000..45d562d63f4 --- /dev/null +++ b/SPECS/binutils/CVE-2025-69649.patch @@ -0,0 +1,35 @@ +From 66a3492ce68e1ae45b2489bd9a815c39ea5d7f66 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Mon, 8 Dec 2025 15:58:33 +1030 +Subject: [PATCH] PR 33697, fuzzer segfault + + PR 33697 + * readelf.c (process_relocs): Don't segfault on no sections. + +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=66a3492ce68e1ae45b2489bd9a815c39ea5d7f66 +--- + binutils/readelf.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/binutils/readelf.c b/binutils/readelf.c +index 97d72d0b..00539539 100644 +--- a/binutils/readelf.c ++++ b/binutils/readelf.c +@@ -8490,10 +8490,10 @@ process_relocs (Filedata * filedata) + size_t i; + bool found = false; + +- for (i = 0, section = filedata->section_headers; +- i < filedata->file_header.e_shnum; +- i++, section++) +- { ++ section = filedata->section_headers; ++ if (section != NULL) ++ for (i = 0; i < filedata->file_header.e_shnum; i++, section++) ++ { + if ( section->sh_type != SHT_RELA + && section->sh_type != SHT_REL + && section->sh_type != SHT_RELR) +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2025-69652.patch b/SPECS/binutils/CVE-2025-69652.patch new file mode 100644 index 00000000000..33d03d5b38b --- /dev/null +++ b/SPECS/binutils/CVE-2025-69652.patch @@ -0,0 +1,36 @@ +From 44b79abd0fa12e7947252eb4c6e5d16ed6033e01 Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Mon, 8 Dec 2025 16:04:44 +1030 +Subject: [PATCH] PR 33701, abort in byte_get_little_endian + + PR 33701 + * dwarf.c (process_debug_info): Set debug_info_p NULL when + DEBUG_INFO_UNAVAILABLE. + +Upstream Patch Reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=44b79abd0fa12e7947252eb4c6e5d16ed6033e01 +--- + binutils/dwarf.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/binutils/dwarf.c b/binutils/dwarf.c +index 6e31c7e1..3090af89 100644 +--- a/binutils/dwarf.c ++++ b/binutils/dwarf.c +@@ -4047,9 +4047,11 @@ process_debug_info (struct dwarf_section * section, + break; + } + +- debug_info *debug_info_p = +- (debug_information && unit < alloc_num_debug_info_entries) +- ? debug_information + unit : NULL; ++ debug_info *debug_info_p = NULL; ++ if (debug_information ++ && num_debug_info_entries != DEBUG_INFO_UNAVAILABLE ++ && unit < alloc_num_debug_info_entries) ++ debug_info_p = debug_information + unit; + + assert (!debug_info_p + || (debug_info_p->num_loc_offsets +-- +2.45.4 + diff --git a/SPECS/binutils/CVE-2026-4647.patch b/SPECS/binutils/CVE-2026-4647.patch new file mode 100644 index 00000000000..c253cf82202 --- /dev/null +++ b/SPECS/binutils/CVE-2026-4647.patch @@ -0,0 +1,225 @@ +From b21ee69896bdd3d221a83818ebfb05cc7d7fe7dc Mon Sep 17 00:00:00 2001 +From: Alan Modra +Date: Fri, 13 Mar 2026 17:28:28 +1030 +Subject: [PATCH] PR33919 Out-of-bounds read in XCOFF relocation processing + + PR 33919 + * coff-rs6000.c (xcoff_calculate_relocation): Don't use explicit + array size. + (xcoff_complain_overflow): Likewise. + (xcoff_rtype2howto): Return a NULL howto rather than aborting. + (_bfd_xcoff_reloc_name_lookup): Use ARRAY_SIZE. + (xcoff_ppc_relocate_section): Sanity check reloc r_type before + accessing xcoff_howto_table. Print r_type using %#x. Remove + now redundant later reloc r_type sanity check. + * coff64-rs6000.c: Similarly. + * libxcoff.h (XCOFF_MAX_CALCULATE_RELOCATION): Don't define. + (XCOFF_MAX_COMPLAIN_OVERFLOW): Don't define. + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=9e99dbc1f19ffaf18d0250788951706066ebe7f2 +--- + bfd/coff-rs6000.c | 36 ++++++++++++++++++------------- + bfd/coff64-rs6000.c | 33 +++++++++++++++++----------- + bfd/libxcoff.h | 3 --- + 3 files changed, 41 insertions(+), 31 deletions(-) + +diff --git a/binutils-2.41/bfd/coff-rs6000.c b/binutils-2.41/bfd/coff-rs6000.c +index a692c1ae..1711d62b 100644 +--- a/bfd/coff-rs6000.c ++++ b/bfd/coff-rs6000.c +@@ -155,8 +155,7 @@ static xcoff_complain_function xcoff_complain_overflow_bitfield_func; + static xcoff_complain_function xcoff_complain_overflow_signed_func; + static xcoff_complain_function xcoff_complain_overflow_unsigned_func; + +-xcoff_reloc_function *const +-xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = ++xcoff_reloc_function *const xcoff_calculate_relocation[] = + { + xcoff_reloc_type_pos, /* R_POS (0x00) */ + xcoff_reloc_type_neg, /* R_NEG (0x01) */ +@@ -210,8 +209,7 @@ xcoff_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = + xcoff_reloc_type_toc, /* R_TOCL (0x31) */ + }; + +-xcoff_complain_function *const +-xcoff_complain_overflow[XCOFF_MAX_COMPLAIN_OVERFLOW] = ++xcoff_complain_function *const xcoff_complain_overflow[] = + { + xcoff_complain_overflow_dont_func, + xcoff_complain_overflow_bitfield_func, +@@ -1158,8 +1156,11 @@ reloc_howto_type xcoff_howto_table[] = + void + xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal) + { +- if (internal->r_type > R_TOCL) +- abort (); ++ if (internal->r_type >= ARRAY_SIZE (xcoff_howto_table)) ++ { ++ relent->howto = NULL; ++ return; ++ } + + /* Default howto layout works most of the time */ + relent->howto = &xcoff_howto_table[internal->r_type]; +@@ -1183,7 +1184,7 @@ xcoff_rtype2howto (arelent *relent, struct internal_reloc *internal) + if (relent->howto->dst_mask != 0 + && (relent->howto->bitsize + != ((unsigned int) internal->r_size & 0x1f) + 1)) +- abort (); ++ relent->howto = NULL; + } + + reloc_howto_type * +@@ -1236,9 +1237,7 @@ _bfd_xcoff_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + { + unsigned int i; + +- for (i = 0; +- i < sizeof (xcoff_howto_table) / sizeof (xcoff_howto_table[0]); +- i++) ++ for (i = 0; i < ARRAY_SIZE (xcoff_howto_table); i++) + if (xcoff_howto_table[i].name != NULL + && strcasecmp (xcoff_howto_table[i].name, r_name) == 0) + return &xcoff_howto_table[i]; +@@ -3774,6 +3773,14 @@ xcoff_ppc_relocate_section (bfd *output_bfd, + the csect including the symbol which it references. */ + if (rel->r_type == R_REF) + continue; ++ if (rel->r_type >= ARRAY_SIZE (xcoff_howto_table)) ++ { ++ /* xgettext:c-format */ ++ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), ++ input_bfd, rel->r_type); ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } + + /* Retrieve default value in HOWTO table and fix up according + to r_size field, if it can be different. +@@ -3793,7 +3800,7 @@ xcoff_ppc_relocate_section (bfd *output_bfd, + + default: + _bfd_error_handler +- (_("%pB: relocation (%d) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"), ++ (_("%pB: relocation (%#x) at 0x%" PRIx64 " has wrong r_rsize (0x%x)\n"), + input_bfd, rel->r_type, (uint64_t) rel->r_vaddr, rel->r_size); + return false; + } +@@ -3869,10 +3876,9 @@ xcoff_ppc_relocate_section (bfd *output_bfd, + } + } + +- if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION +- || !((*xcoff_calculate_relocation[rel->r_type]) +- (input_bfd, input_section, output_bfd, rel, sym, &howto, val, +- addend, &relocation, contents, info))) ++ if (!((*xcoff_calculate_relocation[rel->r_type]) ++ (input_bfd, input_section, output_bfd, rel, sym, &howto, val, ++ addend, &relocation, contents, info))) + return false; + + /* address */ +diff --git a/binutils-2.41/bfd/coff64-rs6000.c b/binutils-2.41/bfd/coff64-rs6000.c +index d76c99a3..28052a87 100644 +--- a/bfd/coff64-rs6000.c ++++ b/bfd/coff64-rs6000.c +@@ -177,8 +177,7 @@ static bool xcoff64_bad_format_hook + /* Relocation functions */ + static xcoff_reloc_function xcoff64_reloc_type_br; + +-xcoff_reloc_function *const +-xcoff64_calculate_relocation[XCOFF_MAX_CALCULATE_RELOCATION] = ++xcoff_reloc_function *const xcoff64_calculate_relocation[] = + { + xcoff_reloc_type_pos, /* R_POS (0x00) */ + xcoff_reloc_type_neg, /* R_NEG (0x01) */ +@@ -1439,8 +1438,11 @@ reloc_howto_type xcoff64_howto_table[] = + void + xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) + { +- if (internal->r_type > R_TOCL) +- abort (); ++ if (internal->r_type >= ARRAY_SIZE (xcoff64_howto_table)) ++ { ++ relent->howto = NULL; ++ return; ++ } + + /* Default howto layout works most of the time */ + relent->howto = &xcoff64_howto_table[internal->r_type]; +@@ -1473,7 +1475,7 @@ xcoff64_rtype2howto (arelent *relent, struct internal_reloc *internal) + if (relent->howto->dst_mask != 0 + && (relent->howto->bitsize + != ((unsigned int) internal->r_size & 0x3f) + 1)) +- abort (); ++ relent->howto = NULL; + } + + reloc_howto_type * +@@ -1528,9 +1530,7 @@ xcoff64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + { + unsigned int i; + +- for (i = 0; +- i < sizeof (xcoff64_howto_table) / sizeof (xcoff64_howto_table[0]); +- i++) ++ for (i = 0; i < ARRAY_SIZE (xcoff64_howto_table); i++) + if (xcoff64_howto_table[i].name != NULL + && strcasecmp (xcoff64_howto_table[i].name, r_name) == 0) + return &xcoff64_howto_table[i]; +@@ -1574,6 +1574,14 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, + the csect including the symbol which it references. */ + if (rel->r_type == R_REF) + continue; ++ if (rel->r_type >= ARRAY_SIZE (xcoff64_howto_table)) ++ { ++ /* xgettext:c-format */ ++ _bfd_error_handler (_("%pB: unsupported relocation type %#x"), ++ input_bfd, rel->r_type); ++ bfd_set_error (bfd_error_bad_value); ++ return false; ++ } + + /* Retrieve default value in HOWTO table and fix up according + to r_size field, if it can be different. +@@ -1595,7 +1603,7 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, + + default: + _bfd_error_handler +- (_("%pB: relocation (%d) at (0x%" PRIx64 ") has wrong" ++ (_("%pB: relocation (%#x) at (0x%" PRIx64 ") has wrong" + " r_rsize (0x%x)\n"), + input_bfd, rel->r_type, rel->r_vaddr, rel->r_size); + return false; +@@ -1668,10 +1676,9 @@ xcoff64_ppc_relocate_section (bfd *output_bfd, + } + } + +- if (rel->r_type >= XCOFF_MAX_CALCULATE_RELOCATION +- || !((*xcoff64_calculate_relocation[rel->r_type]) +- (input_bfd, input_section, output_bfd, rel, sym, &howto, val, +- addend, &relocation, contents, info))) ++ if (!((*xcoff64_calculate_relocation[rel->r_type]) ++ (input_bfd, input_section, output_bfd, rel, sym, &howto, val, ++ addend, &relocation, contents, info))) + return false; + + /* address */ +diff --git a/binutils-2.41/bfd/libxcoff.h b/binutils-2.41/bfd/libxcoff.h +index cc2dd2ac..67033d54 100644 +--- a/bfd/libxcoff.h ++++ b/bfd/libxcoff.h +@@ -215,9 +215,6 @@ struct xcoff_backend_data_rec + #define bfd_xcoff_text_align_power(a) ((xcoff_data (a)->text_align_power)) + #define bfd_xcoff_data_align_power(a) ((xcoff_data (a)->data_align_power)) + +-/* xcoff*_ppc_relocate_section macros */ +-#define XCOFF_MAX_CALCULATE_RELOCATION (0x32) +-#define XCOFF_MAX_COMPLAIN_OVERFLOW (4) + /* N_ONES produces N one bits, without overflowing machine arithmetic. */ + #ifdef N_ONES + #undef N_ONES +-- +2.45.4 + diff --git a/SPECS/binutils/binutils.spec b/SPECS/binutils/binutils.spec index 9b3af78c48d..04479243527 100644 --- a/SPECS/binutils/binutils.spec +++ b/SPECS/binutils/binutils.spec @@ -21,7 +21,7 @@ Summary: Contains a linker, an assembler, and other tools Name: binutils Version: 2.41 -Release: 10%{?dist} +Release: 11%{?dist} License: GPLv2+ Vendor: Microsoft Corporation Distribution: Azure Linux @@ -37,7 +37,7 @@ Patch3: CVE-2025-1178.patch Patch4: CVE-2025-1181.patch Patch5: CVE-2025-1182.patch Patch6: CVE-2025-0840.patch -Patch7: CVE-2025-1744.patch +Patch7: CVE-2025-1744.patch Patch8: CVE-2025-5245.patch Patch9: CVE-2025-5244.patch Patch10: CVE-2025-7546.patch @@ -47,6 +47,15 @@ Patch13: CVE-2025-11082.patch Patch14: CVE-2025-11083.patch Patch15: CVE-2025-11412.patch Patch16: CVE-2025-11414.patch +Patch17: CVE-2025-69645.patch +Patch18: CVE-2025-69646.patch +Patch19: CVE-2025-69649.patch +Patch20: CVE-2025-69652.patch +Patch21: CVE-2025-1147.patch +Patch22: CVE-2025-1148.patch +Patch23: CVE-2025-11839.patch +Patch24: CVE-2025-69647.patch +Patch25: CVE-2026-4647.patch Provides: bundled(libiberty) # Moving macro before the "SourceX" tags breaks PR checks parsing the specs. @@ -336,6 +345,9 @@ find %{buildroot} -type f -name "*.la" -delete -print %do_files aarch64-linux-gnu %{build_aarch64} %changelog +* Wed Mar 11 2026 Azure Linux Security Servicing Account - 2.41-11 +- Patch for CVE-2025-69652, CVE-2025-69649, CVE-2025-69646, CVE-2025-69645, CVE-2025-11839, CVE-2025-1148, CVE-2025-1147, CVE-2025-69647, CVE-2026-4647 + * Thu Oct 16 2025 Azure Linux Security Servicing Account - 2.41-10 - Patch for CVE-2025-11414, CVE-2025-11412 diff --git a/SPECS/curl/CVE-2026-1965.patch b/SPECS/curl/CVE-2026-1965.patch new file mode 100644 index 00000000000..80b794851ec --- /dev/null +++ b/SPECS/curl/CVE-2026-1965.patch @@ -0,0 +1,139 @@ +From 441e8ee4df3e576bf23c30eb31b9fef8c55f5663 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Thu, 12 Mar 2026 11:59:23 +0000 +Subject: [PATCH] url: fix reuse of connections using HTTP Negotiate; + Follow-up: fix copy+paste mistake in url_match_auth_nego + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/34fa034d9a390c4bd65e2d05262755ec8646ac12.patch https://github.com/curl/curl/commit/f1a39f221d57354990e3eeeddc3404aede2aff70.patch +--- + lib/url.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 85 insertions(+), 5 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 436edd8..d62eefa 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -853,6 +853,8 @@ struct url_conn_match { + BIT(may_multiplex); + BIT(want_ntlm_http); + BIT(want_proxy_ntlm_http); ++ BIT(want_nego_http); ++ BIT(want_proxy_nego_http); + + BIT(wait_pipe); + BIT(force_reuse); +@@ -861,6 +863,64 @@ struct url_conn_match { + BIT(seen_multiplex_conn); + }; + ++#if defined(USE_SPNEGO) ++static bool url_match_auth_nego(struct connectdata *conn, ++ struct url_conn_match *m) ++{ ++ /* If we are looking for an HTTP+Negotiate connection, check if this is ++ already authenticating with the right credentials. If not, keep looking ++ so that we can reuse Negotiate connections if possible. */ ++ if(m->want_nego_http) { ++ if(Curl_timestrcmp(m->needle->user, conn->user) || ++ Curl_timestrcmp(m->needle->passwd, conn->passwd)) ++ return FALSE; ++ } ++ else if(conn->http_negotiate_state != GSS_AUTHNONE) { ++ /* Connection is using Negotiate auth but we do not want Negotiate */ ++ return FALSE; ++ } ++ ++#ifndef CURL_DISABLE_PROXY ++ /* Same for Proxy Negotiate authentication */ ++ if(m->want_proxy_nego_http) { ++ /* Both conn->http_proxy.user and conn->http_proxy.passwd can be ++ * NULL */ ++ if(!conn->http_proxy.user || !conn->http_proxy.passwd) ++ return FALSE; ++ ++ if(Curl_timestrcmp(m->needle->http_proxy.user, ++ conn->http_proxy.user) || ++ Curl_timestrcmp(m->needle->http_proxy.passwd, ++ conn->http_proxy.passwd)) ++ return FALSE; ++ } ++ else if(conn->proxy_negotiate_state != GSS_AUTHNONE) { ++ /* Proxy connection is using Negotiate auth but we do not want Negotiate */ ++ return FALSE; ++ } ++#endif ++ if(m->want_nego_http || m->want_proxy_nego_http) { ++ /* Credentials are already checked, we may use this connection. We MUST ++ * use a connection where it has already been fully negotiated. If it has ++ * not, we keep on looking for a better one. */ ++ m->found = conn; ++ if((m->want_nego_http && ++ (conn->http_negotiate_state != GSS_AUTHNONE)) || ++ (m->want_proxy_nego_http && ++ (conn->proxy_negotiate_state != GSS_AUTHNONE))) { ++ /* We must use this connection, no other */ ++ m->force_reuse = TRUE; ++ return TRUE; ++ } ++ return FALSE; /* get another */ ++ } ++ return TRUE; ++} ++#else ++#define url_match_auth_nego(c, m) ((void)c, (void)m, TRUE) ++#endif ++ ++ + static bool url_match_conn(struct connectdata *conn, void *userdata) + { + struct url_conn_match *match = userdata; +@@ -1156,6 +1216,13 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) + * If it has not, we keep on looking for a better one. */ + match->found = conn; + ++ ++ if(!url_match_auth_nego(conn, match)) ++ return FALSE; ++ else if(match->force_reuse) ++ return TRUE; ++ ++ + if((match->want_ntlm_http && + (conn->http_ntlm_state != NTLMSTATE_NONE)) || + (match->want_proxy_ntlm_http && +@@ -1251,13 +1318,26 @@ ConnectionExists(struct Curl_easy *data, + match.may_multiplex = xfer_may_multiplex(data, needle); + + #ifdef USE_NTLM +- match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) && +- (needle->handler->protocol & PROTO_FAMILY_HTTP)); ++ match.want_ntlm_http = ++ (data->state.authhost.want & CURLAUTH_NTLM) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); + #ifndef CURL_DISABLE_PROXY + match.want_proxy_ntlm_http = +- (needle->bits.proxy_user_passwd && +- (data->state.authproxy.want & CURLAUTH_NTLM) && +- (needle->handler->protocol & PROTO_FAMILY_HTTP)); ++ needle->bits.proxy_user_passwd && ++ (data->state.authproxy.want & CURLAUTH_NTLM) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); ++#endif ++#endif ++ ++#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) ++ match.want_nego_http = ++ (data->state.authhost.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); ++#ifndef CURL_DISABLE_PROXY ++ match.want_proxy_nego_http = ++ needle->bits.proxy_user_passwd && ++ (data->state.authproxy.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); + #endif + #endif + +-- +2.45.4 + diff --git a/SPECS/curl/CVE-2026-3783.patch b/SPECS/curl/CVE-2026-3783.patch new file mode 100644 index 00000000000..2b532a1c318 --- /dev/null +++ b/SPECS/curl/CVE-2026-3783.patch @@ -0,0 +1,149 @@ +From e3d7401a32a46516c9e5ee877e613e62ed35bddc Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 6 Mar 2026 23:13:07 +0100 +Subject: [PATCH] http: only send bearer if auth is allowed + +Verify with test 2006 + +Closes #20843 + +Upstream Patch reference: https://github.com/curl/curl/commit/e3d7401a32a46516c9e5ee877e613e62ed35bddc.patch +--- + lib/http.c | 1 + + tests/data/Makefile.am | 2 +- + tests/data/test2006 | 98 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 100 insertions(+), 1 deletion(-) + create mode 100644 tests/data/test2006 + +diff --git a/lib/http.c b/lib/http.c +index 35e7085..4de1667 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -650,6 +650,7 @@ output_auth_headers(struct Curl_easy *data, + if(authstatus->picked == CURLAUTH_BEARER) { + /* Bearer */ + if((!proxy && data->set.str[STRING_BEARER] && ++ Curl_auth_allowed_to_host(data) && + !Curl_checkheaders(data, STRCONST("Authorization")))) { + auth = "Bearer"; + result = http_output_bearer(data); +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 776b593..26e015f 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -238,7 +238,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \ + test1955 test1956 test1957 test1958 test1959 test1960 test1964 \ + test1970 test1971 test1972 test1973 test1974 test1975 test1976 \ + \ +-test2000 test2001 test2002 test2003 test2004 \ ++test2000 test2001 test2002 test2003 test2004 test2006 \ + \ + test2023 \ + test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ +diff --git a/tests/data/test2006 b/tests/data/test2006 +new file mode 100644 +index 0000000..4b8b269 +--- /dev/null ++++ b/tests/data/test2006 +@@ -0,0 +1,98 @@ ++ ++ ++ ++ ++netrc ++HTTP ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 301 Follow this you fool ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 6 ++Connection: close ++Location: http://b.com/%TESTNUMBER0002 ++ ++-foo- ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 7 ++Connection: close ++ ++target ++ ++ ++ ++HTTP/1.1 301 Follow this you fool ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 6 ++Connection: close ++Location: http://b.com/%TESTNUMBER0002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 7 ++Connection: close ++ ++target ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++proxy ++ ++ ++.netrc default with redirect plus oauth2-bearer ++ ++ ++--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER --oauth2-bearer SECRET_TOKEN -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/ ++ ++ ++default login testuser password testpass ++ ++ ++ ++ ++ ++GET http://a.com/ HTTP/1.1 ++Host: a.com ++Authorization: Bearer SECRET_TOKEN ++User-Agent: curl/%VERSION ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://b.com/%TESTNUMBER0002 HTTP/1.1 ++Host: b.com ++User-Agent: curl/%VERSION ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +-- +2.43.0 + diff --git a/SPECS/curl/CVE-2026-3784.patch b/SPECS/curl/CVE-2026-3784.patch new file mode 100644 index 00000000000..1beb78b5fc7 --- /dev/null +++ b/SPECS/curl/CVE-2026-3784.patch @@ -0,0 +1,166 @@ +From 184dadb0109bf038832b9f5d4d49aa757e52d41a Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Thu, 12 Mar 2026 12:18:02 +0000 +Subject: [PATCH] proxy-auth: additional tests + +Also eliminate the special handling for socks proxy match. + +Closes #20837 + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/5f13a7645e565c5c1a06f3ef86e97afb856fb364.patch +--- + lib/url.c | 30 ++++++++---------------------- + tests/http/test_13_proxy_auth.py | 20 ++++++++++++++++++++ + tests/http/testenv/curl.py | 18 +++++++++++++++--- + 3 files changed, 43 insertions(+), 25 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index d62eefa..88f559a 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -678,30 +678,16 @@ proxy_info_matches(const struct proxy_info *data, + { + if((data->proxytype == needle->proxytype) && + (data->port == needle->port) && +- strcasecompare(data->host.name, needle->host.name)) +- return TRUE; ++ strcasecompare(data->host.name, needle->host.name)) { + ++ if(Curl_timestrcmp(data->user, needle->user) || ++ Curl_timestrcmp(data->passwd, needle->passwd)) ++ return FALSE; ++ return TRUE; ++ } + return FALSE; + } + +-static bool +-socks_proxy_info_matches(const struct proxy_info *data, +- const struct proxy_info *needle) +-{ +- if(!proxy_info_matches(data, needle)) +- return FALSE; +- +- /* the user information is case-sensitive +- or at least it is not defined as case-insensitive +- see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */ +- +- /* curl_strequal does a case insensitive comparison, +- so do not use it here! */ +- if(Curl_timestrcmp(data->user, needle->user) || +- Curl_timestrcmp(data->passwd, needle->passwd)) +- return FALSE; +- return TRUE; +-} + #else + /* disabled, will not get called */ + #define proxy_info_matches(x,y) FALSE +@@ -1032,8 +1018,8 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) + return FALSE; + + if(needle->bits.socksproxy && +- !socks_proxy_info_matches(&needle->socks_proxy, +- &conn->socks_proxy)) ++ !proxy_info_matches(&needle->socks_proxy, ++ &conn->socks_proxy)) + return FALSE; + + if(needle->bits.httpproxy) { +diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py +index 0979fbb..f2cda54 100644 +--- a/tests/http/test_13_proxy_auth.py ++++ b/tests/http/test_13_proxy_auth.py +@@ -152,3 +152,23 @@ class TestProxyAuth: + protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') + assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ + if tunnel == 'h2' else 'HTTP/1.1' ++ ++ def test_13_10_tunnels_mixed_auth(self, env: Env, httpd, configures_httpd): ++ self.httpd_configure(env, httpd) ++ curl = CurlClient(env=env) ++ url1 = f'http://localhost:{env.http_port}/data.json?1' ++ url2 = f'http://localhost:{env.http_port}/data.json?2' ++ url3 = f'http://localhost:{env.http_port}/data.json?3' ++ xargs1 = curl.get_proxy_args(proxys=False, tunnel=True) ++ xargs1.extend(['--proxy-user', 'proxy:proxy']) # good auth ++ xargs2 = curl.get_proxy_args(proxys=False, tunnel=True) ++ xargs2.extend(['--proxy-user', 'ungood:ungood']) # bad auth ++ xargs3 = curl.get_proxy_args(proxys=False, tunnel=True) ++ # no auth ++ r = curl.http_download(urls=[url1, url2, url3], alpn_proto='http/1.1', with_stats=True, ++ url_options={url1: xargs1, url2: xargs2, url3: xargs3}) ++ # only url1 succeeds, others fail, no connection reuse ++ assert r.stats[0]['http_code'] == 200, f'{r.dump_logs()}' ++ assert r.stats[1]['http_code'] == 0, f'{r.dump_logs()}' ++ assert r.stats[2]['http_code'] == 0, f'{r.dump_logs()}' ++ assert r.total_connects == 3, f'{r.dump_logs()}' +diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py +index ee224d9..d4c3874 100644 +--- a/tests/http/testenv/curl.py ++++ b/tests/http/testenv/curl.py +@@ -539,7 +539,8 @@ class CurlClient: + with_profile: bool = False, + with_tcpdump: bool = False, + no_save: bool = False, +- extra_args: Optional[List[str]] = None): ++ extra_args: Optional[List[str]] = None, ++ url_options: Optional[Dict[str,List[str]]] = None): + if extra_args is None: + extra_args = [] + if no_save: +@@ -559,6 +560,7 @@ class CurlClient: + ]) + return self._raw(urls, alpn_proto=alpn_proto, options=extra_args, + with_stats=with_stats, ++ url_options=url_options, + with_headers=with_headers, + with_profile=with_profile, + with_tcpdump=with_tcpdump) +@@ -820,6 +822,7 @@ class CurlClient: + + def _raw(self, urls, intext='', timeout=None, options=None, insecure=False, + alpn_proto: Optional[str] = None, ++ url_options=None, + force_resolve=True, + with_stats=False, + with_headers=True, +@@ -829,7 +832,8 @@ class CurlClient: + args = self._complete_args( + urls=urls, timeout=timeout, options=options, insecure=insecure, + alpn_proto=alpn_proto, force_resolve=force_resolve, +- with_headers=with_headers, def_tracing=def_tracing) ++ with_headers=with_headers, def_tracing=def_tracing, ++ url_options=url_options) + r = self._run(args, intext=intext, with_stats=with_stats, + with_profile=with_profile, with_tcpdump=with_tcpdump) + if r.exit_code == 0 and with_headers: +@@ -839,8 +843,10 @@ class CurlClient: + def _complete_args(self, urls, timeout=None, options=None, + insecure=False, force_resolve=True, + alpn_proto: Optional[str] = None, ++ url_options=None, + with_headers: bool = True, + def_tracing: bool = True): ++ url_sep = [] + if not isinstance(urls, list): + urls = [urls] + +@@ -860,7 +866,13 @@ class CurlClient: + active_options = options[options.index('--next') + 1:] + + for url in urls: +- u = urlparse(urls[0]) ++ args.extend(url_sep) ++ if url_options is not None: ++ url_sep = ['--next'] ++ ++ u = urlparse(url) ++ if url_options is not None and url in url_options: ++ args.extend(url_options[url]) + if options: + args.extend(options) + if alpn_proto is not None: +-- +2.45.4 + diff --git a/SPECS/curl/curl.spec b/SPECS/curl/curl.spec index 1bcef69a899..7cb93f8747d 100644 --- a/SPECS/curl/curl.spec +++ b/SPECS/curl/curl.spec @@ -1,7 +1,7 @@ Summary: An URL retrieval utility and library Name: curl Version: 8.11.1 -Release: 5%{?dist} +Release: 6%{?dist} License: curl Vendor: Microsoft Corporation Distribution: Azure Linux @@ -13,6 +13,9 @@ Patch1: CVE-2025-0167.patch Patch2: CVE-2025-0725.patch Patch3: CVE-2025-10148.patch Patch4: CVE-2025-14017.patch +Patch5: CVE-2026-1965.patch +Patch6: CVE-2026-3783.patch +Patch7: CVE-2026-3784.patch BuildRequires: cmake BuildRequires: krb5-devel BuildRequires: libnghttp2-devel @@ -103,13 +106,16 @@ find %{buildroot} -type f -name "*.la" -delete -print %{_libdir}/libcurl.so.* %changelog +* Thu Mar 12 2026 Azure Linux Security Servicing Account - 8.11.1-6 +- Patch for CVE-2026-3784, CVE-2026-3783, CVE-2026-1965 + * Fri Jan 09 2026 Azure Linux Security Servicing Account - 8.11.1-5 - Patch for CVE-2025-14017 * Thu Sep 11 2025 Azure Linux Security Servicing Account - 8.11.1-4 - Patch for CVE-2025-10148 -* Thu Feb 13 2025 Kanishk Bansal - 8.11.1-3 +* Thu Feb 27 2025 Kanishk Bansal - 8.11.1-3 - Fix CVE-2025-0665, CVE-2025-0167, CVE-2025-0725 * Wed Feb 26 2025 Tobias Brick - 8.11.1-2 diff --git a/SPECS/rubygem-faraday/CVE-2026-25765.patch b/SPECS/rubygem-faraday/CVE-2026-25765.patch new file mode 100644 index 00000000000..d3ef49d0113 --- /dev/null +++ b/SPECS/rubygem-faraday/CVE-2026-25765.patch @@ -0,0 +1,88 @@ +From e45ae8f935f6f87b91929b2ba48b57e5ba174435 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Thu, 2 Apr 2026 15:18:26 +0000 +Subject: [PATCH] build_exclusive_url: Guard against protocol-relative URLs by + normalising to relative path; update rubocop todo and add specs + (GHSA-33mh-2634-fwr2) + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/lostisland/faraday/commit/a6d3a3a0bf59c2ab307d0abd91bc126aef5561bc.patch +--- + .rubocop_todo.yml | 2 +- + lib/faraday/connection.rb | 3 +++ + spec/faraday/connection_spec.rb | 33 +++++++++++++++++++++++++++++++++ + 3 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml +index fbec6de..3c75338 100644 +--- a/.rubocop_todo.yml ++++ b/.rubocop_todo.yml +@@ -31,7 +31,7 @@ Metrics/AbcSize: + # Offense count: 4 + # Configuration parameters: CountComments, CountAsOne. + Metrics/ClassLength: +- Max: 230 ++ Max: 235 + + # Offense count: 9 + # Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods. +diff --git a/lib/faraday/connection.rb b/lib/faraday/connection.rb +index 1984f87..7056572 100644 +--- a/lib/faraday/connection.rb ++++ b/lib/faraday/connection.rb +@@ -473,6 +473,9 @@ module Faraday + if url && !base.path.end_with?('/') + base.path = "#{base.path}/" # ensure trailing slash + end ++ # Ensure relative url will be parsed correctly (such as `service:search` or `//evil.com`) ++ url = "./#{url}" if url.respond_to?(:start_with?) && ++ (!url.start_with?('http://', 'https://', '/', './', '../') || url.start_with?('//')) + url = url.to_s.gsub(':', '%3A') if URI.parse(url.to_s).opaque + uri = url ? base + url : base + if params +diff --git a/spec/faraday/connection_spec.rb b/spec/faraday/connection_spec.rb +index d4ccb23..51392f1 100644 +--- a/spec/faraday/connection_spec.rb ++++ b/spec/faraday/connection_spec.rb +@@ -310,6 +310,39 @@ + expect(uri.to_s).to eq('http://service.com/api/service%3Asearch?limit=400') + end + end ++ context 'with protocol-relative URL (GHSA-33mh-2634-fwr2)' do ++ it 'does not allow host override with //evil.com/path' do ++ conn.url_prefix = 'http://httpbingo.org/api' ++ uri = conn.build_exclusive_url('//evil.com/path') ++ expect(uri.host).to eq('httpbingo.org') ++ end ++ ++ it 'does not allow host override with //evil.com:8080/path' do ++ conn.url_prefix = 'http://httpbingo.org/api' ++ uri = conn.build_exclusive_url('//evil.com:8080/path') ++ expect(uri.host).to eq('httpbingo.org') ++ end ++ ++ it 'does not allow host override with //user:pass@evil.com/path' do ++ conn.url_prefix = 'http://httpbingo.org/api' ++ uri = conn.build_exclusive_url('//user:pass@evil.com/path') ++ expect(uri.host).to eq('httpbingo.org') ++ end ++ ++ it 'does not allow host override with ///evil.com' do ++ conn.url_prefix = 'http://httpbingo.org/api' ++ uri = conn.build_exclusive_url('///evil.com') ++ expect(uri.host).to eq('httpbingo.org') ++ end ++ ++ it 'still allows single-slash absolute paths' do ++ conn.url_prefix = 'http://httpbingo.org/api' ++ uri = conn.build_exclusive_url('/safe/path') ++ expect(uri.host).to eq('httpbingo.org') ++ expect(uri.path).to eq('/safe/path') ++ end ++ end ++ + + context 'with a custom `default_uri_parser`' do + let(:url) { 'http://httpbingo.org' } +-- +2.45.4 diff --git a/SPECS/rubygem-faraday/rubygem-faraday.spec b/SPECS/rubygem-faraday/rubygem-faraday.spec index cd3e7e8eee0..df795cfee8e 100644 --- a/SPECS/rubygem-faraday/rubygem-faraday.spec +++ b/SPECS/rubygem-faraday/rubygem-faraday.spec @@ -3,13 +3,14 @@ Summary: HTTP/REST API client library Name: rubygem-faraday Version: 2.7.10 -Release: 1%{?dist} +Release: 2%{?dist} License: MIT Vendor: Microsoft Corporation Distribution: Azure Linux Group: Development/Languages URL: https://lostisland.github.io/faraday/ Source0: https://github.com/lostisland/faraday/archive/refs/tags/v%{version}.tar.gz#/%{gem_name}-%{version}.tar.gz +Patch0: CVE-2026-25765.patch BuildRequires: ruby Requires: rubygem-multipart-post < 3 Requires: rubygem-ruby2_keywords @@ -22,7 +23,7 @@ many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle. %prep -%setup -q -n %{gem_name}-%{version} +%autosetup -n %{gem_name}-%{version} -p1 %build gem build %{gem_name} @@ -36,6 +37,9 @@ gem install -V --local --force --install-dir %{buildroot}/%{gemdir} %{gem_name}- %{gemdir} %changelog +* Thu Apr 02 2026 Azure Linux Security Servicing Account - 2.7.10-2 +- Patch for CVE-2026-25765 + * Thu Nov 02 2023 CBL-Mariner Servicing Account - 2.7.10-1 - Auto-upgrade to 2.7.10 - Azure Linux 3.0 - package upgrades diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index 1acef6be698..10b7a339aa2 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -13,8 +13,8 @@ zlib-devel-1.3.2-1.azl3.aarch64.rpm file-5.45-1.azl3.aarch64.rpm file-devel-5.45-1.azl3.aarch64.rpm file-libs-5.45-1.azl3.aarch64.rpm -binutils-2.41-10.azl3.aarch64.rpm -binutils-devel-2.41-10.azl3.aarch64.rpm +binutils-2.41-11.azl3.aarch64.rpm +binutils-devel-2.41-11.azl3.aarch64.rpm gmp-6.3.0-1.azl3.aarch64.rpm gmp-devel-6.3.0-1.azl3.aarch64.rpm mpfr-4.2.1-1.azl3.aarch64.rpm @@ -199,9 +199,9 @@ krb5-1.21.3-3.azl3.aarch64.rpm krb5-devel-1.21.3-3.azl3.aarch64.rpm nghttp2-1.61.0-3.azl3.aarch64.rpm nghttp2-devel-1.61.0-3.azl3.aarch64.rpm -curl-8.11.1-5.azl3.aarch64.rpm -curl-devel-8.11.1-5.azl3.aarch64.rpm -curl-libs-8.11.1-5.azl3.aarch64.rpm +curl-8.11.1-6.azl3.aarch64.rpm +curl-devel-8.11.1-6.azl3.aarch64.rpm +curl-libs-8.11.1-6.azl3.aarch64.rpm createrepo_c-1.0.3-1.azl3.aarch64.rpm libxml2-2.11.5-9.azl3.aarch64.rpm libxml2-devel-2.11.5-9.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index 8544fcea09d..32414c6acab 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -13,8 +13,8 @@ zlib-devel-1.3.2-1.azl3.x86_64.rpm file-5.45-1.azl3.x86_64.rpm file-devel-5.45-1.azl3.x86_64.rpm file-libs-5.45-1.azl3.x86_64.rpm -binutils-2.41-10.azl3.x86_64.rpm -binutils-devel-2.41-10.azl3.x86_64.rpm +binutils-2.41-11.azl3.x86_64.rpm +binutils-devel-2.41-11.azl3.x86_64.rpm gmp-6.3.0-1.azl3.x86_64.rpm gmp-devel-6.3.0-1.azl3.x86_64.rpm mpfr-4.2.1-1.azl3.x86_64.rpm @@ -199,9 +199,9 @@ krb5-1.21.3-3.azl3.x86_64.rpm krb5-devel-1.21.3-3.azl3.x86_64.rpm nghttp2-1.61.0-3.azl3.x86_64.rpm nghttp2-devel-1.61.0-3.azl3.x86_64.rpm -curl-8.11.1-5.azl3.x86_64.rpm -curl-devel-8.11.1-5.azl3.x86_64.rpm -curl-libs-8.11.1-5.azl3.x86_64.rpm +curl-8.11.1-6.azl3.x86_64.rpm +curl-devel-8.11.1-6.azl3.x86_64.rpm +curl-libs-8.11.1-6.azl3.x86_64.rpm createrepo_c-1.0.3-1.azl3.x86_64.rpm libxml2-2.11.5-9.azl3.x86_64.rpm libxml2-devel-2.11.5-9.azl3.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 50f4d6903fb..7fa772b6fea 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -30,9 +30,9 @@ bash-5.2.15-3.azl3.aarch64.rpm bash-debuginfo-5.2.15-3.azl3.aarch64.rpm bash-devel-5.2.15-3.azl3.aarch64.rpm bash-lang-5.2.15-3.azl3.aarch64.rpm -binutils-2.41-10.azl3.aarch64.rpm -binutils-debuginfo-2.41-10.azl3.aarch64.rpm -binutils-devel-2.41-10.azl3.aarch64.rpm +binutils-2.41-11.azl3.aarch64.rpm +binutils-debuginfo-2.41-11.azl3.aarch64.rpm +binutils-devel-2.41-11.azl3.aarch64.rpm bison-3.8.2-1.azl3.aarch64.rpm bison-debuginfo-3.8.2-1.azl3.aarch64.rpm bzip2-1.0.8-1.azl3.aarch64.rpm @@ -67,10 +67,10 @@ cracklib-lang-2.9.11-1.azl3.aarch64.rpm createrepo_c-1.0.3-1.azl3.aarch64.rpm createrepo_c-debuginfo-1.0.3-1.azl3.aarch64.rpm createrepo_c-devel-1.0.3-1.azl3.aarch64.rpm -curl-8.11.1-5.azl3.aarch64.rpm -curl-debuginfo-8.11.1-5.azl3.aarch64.rpm -curl-devel-8.11.1-5.azl3.aarch64.rpm -curl-libs-8.11.1-5.azl3.aarch64.rpm +curl-8.11.1-6.azl3.aarch64.rpm +curl-debuginfo-8.11.1-6.azl3.aarch64.rpm +curl-devel-8.11.1-6.azl3.aarch64.rpm +curl-libs-8.11.1-6.azl3.aarch64.rpm Cython-debuginfo-3.0.5-2.azl3.aarch64.rpm debugedit-5.0-2.azl3.aarch64.rpm debugedit-debuginfo-5.0-2.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index b58aafe892d..d76fb36545d 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -32,10 +32,10 @@ bash-5.2.15-3.azl3.x86_64.rpm bash-debuginfo-5.2.15-3.azl3.x86_64.rpm bash-devel-5.2.15-3.azl3.x86_64.rpm bash-lang-5.2.15-3.azl3.x86_64.rpm -binutils-2.41-10.azl3.x86_64.rpm -binutils-aarch64-linux-gnu-2.41-10.azl3.x86_64.rpm -binutils-debuginfo-2.41-10.azl3.x86_64.rpm -binutils-devel-2.41-10.azl3.x86_64.rpm +binutils-2.41-11.azl3.x86_64.rpm +binutils-aarch64-linux-gnu-2.41-11.azl3.x86_64.rpm +binutils-debuginfo-2.41-11.azl3.x86_64.rpm +binutils-devel-2.41-11.azl3.x86_64.rpm bison-3.8.2-1.azl3.x86_64.rpm bison-debuginfo-3.8.2-1.azl3.x86_64.rpm bzip2-1.0.8-1.azl3.x86_64.rpm @@ -70,12 +70,12 @@ cracklib-lang-2.9.11-1.azl3.x86_64.rpm createrepo_c-1.0.3-1.azl3.x86_64.rpm createrepo_c-debuginfo-1.0.3-1.azl3.x86_64.rpm createrepo_c-devel-1.0.3-1.azl3.x86_64.rpm -cross-binutils-common-2.41-10.azl3.noarch.rpm +cross-binutils-common-2.41-11.azl3.noarch.rpm cross-gcc-common-13.2.0-7.azl3.noarch.rpm -curl-8.11.1-5.azl3.x86_64.rpm -curl-debuginfo-8.11.1-5.azl3.x86_64.rpm -curl-devel-8.11.1-5.azl3.x86_64.rpm -curl-libs-8.11.1-5.azl3.x86_64.rpm +curl-8.11.1-6.azl3.x86_64.rpm +curl-debuginfo-8.11.1-6.azl3.x86_64.rpm +curl-devel-8.11.1-6.azl3.x86_64.rpm +curl-libs-8.11.1-6.azl3.x86_64.rpm Cython-debuginfo-3.0.5-2.azl3.x86_64.rpm debugedit-5.0-2.azl3.x86_64.rpm debugedit-debuginfo-5.0-2.azl3.x86_64.rpm