public inbox for openembedded-core@lists.openembedded.org
 help / color / mirror / Atom feed
* [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648
@ 2026-04-22 13:03 Adarsh Jagadish Kamini
  2026-04-27 15:33 ` Fabien Thomas
  0 siblings, 1 reply; 4+ messages in thread
From: Adarsh Jagadish Kamini @ 2026-04-22 13:03 UTC (permalink / raw)
  To: openembedded-core; +Cc: Adarsh Jagadish Kamini

From: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>

Backport upstream fix for CVE-2025-69648 [1].

[1] https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33

Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
---
 .../binutils/binutils-2.42.inc                |   1 +
 .../binutils/binutils/CVE-2025-69648.patch    | 190 ++++++++++++++++++
 2 files changed, 191 insertions(+)
 create mode 100644 meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch

diff --git a/meta/recipes-devtools/binutils/binutils-2.42.inc b/meta/recipes-devtools/binutils/binutils-2.42.inc
index a337a3e850..6c1f9dc870 100644
--- a/meta/recipes-devtools/binutils/binutils-2.42.inc
+++ b/meta/recipes-devtools/binutils/binutils-2.42.inc
@@ -72,5 +72,6 @@ SRC_URI = "\
      file://0029-CVE-2025-11839.patch \
      file://0030-CVE-2025-11840.patch \
      file://CVE-2025-69647.patch \
+     file://CVE-2025-69648.patch \
 "
 S  = "${WORKDIR}/git"
diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
new file mode 100644
index 0000000000..e04d7ed6c2
--- /dev/null
+++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
@@ -0,0 +1,190 @@
+From 7df481dd76c05c89782721e9df5468be829c356b Mon Sep 17 00:00:00 2001
+From: Alan Modra <amodra@gmail.com>
+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.
+
+CVE: CVE-2025-69648
+Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33]
+
+(cherry picked from commit 598704a00cbac5e85c2bedd363357b5bf6fcee33)
+Signed-off-by: Deepak Rathore <deeratho@cisco.com>
+Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
+---
+ binutils/dwarf.c | 67 ++++++++++++++++++++++++------------------------
+ 1 file changed, 34 insertions(+), 33 deletions(-)
+
+diff --git a/binutils/dwarf.c b/binutils/dwarf.c
+index f4bcb677761..b4fb56351ec 100644
+--- a/binutils/dwarf.c
++++ b/binutils/dwarf.c
+@@ -8282,7 +8282,7 @@ display_debug_rnglists_list (unsigned char * start,
+   return start;
+ }
+ 
+-static int
++static bool
+ display_debug_rnglists_unit_header (struct dwarf_section *  section,
+ 				    uint64_t *              unit_offset,
+ 				    unsigned char *         poffset_size)
+@@ -8290,7 +8290,8 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
+   uint64_t        start_offset = *unit_offset;
+   unsigned char * p = section->start + start_offset;
+   unsigned char * finish = section->start + section->size;
+-  uint64_t        initial_length;
++  unsigned char * hdr;
++  uint64_t        length;
+   unsigned char   segment_selector_size;
+   unsigned int    offset_entry_count;
+   unsigned int    i;
+@@ -8299,66 +8300,59 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
+   unsigned char   offset_size;
+ 
+   /* Get and check the length of the block.  */
+-  SAFE_BYTE_GET_AND_INC (initial_length, p, 4, finish);
++  SAFE_BYTE_GET_AND_INC (length, p, 4, finish);
+ 
+-  if (initial_length == 0xffffffff)
++  if (length == 0xffffffff)
+     {
+       /* This section is 64-bit DWARF 3.  */
+-      SAFE_BYTE_GET_AND_INC (initial_length, p, 8, finish);
++      SAFE_BYTE_GET_AND_INC (length, p, 8, finish);
+       *poffset_size = offset_size = 8;
+     }
+   else
+     *poffset_size = offset_size = 4;
+ 
+-  if (initial_length > (size_t) (finish - p))
+-    {
+-      /* If the length field has a relocation against it, then we should
+-	 not complain if it is inaccurate (and probably negative).
+-	 It is copied from .debug_line handling code.  */
+-      if (reloc_at (section, (p - section->start) - offset_size))
+-	initial_length = finish - p;
+-      else
+-	{
+-	  warn (_("The length field (%#" PRIx64
+-		  ") in the debug_rnglists header is wrong"
+-		  " - the section is too small\n"),
+-		initial_length);
+-	  return 0;
+-	}
+-    }
+-
+-  /* Report the next unit offset to the caller.  */
+-  *unit_offset = (p - section->start) + initial_length;
++  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"), initial_length);
++  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 0;
++      return false;
+     }
+ 
+   if (version < 5)
+     {
+       warn (_("Only DWARF version 5+ debug_rnglists info "
+ 	      "is currently supported.\n"));
+-      return 0;
++      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);
+@@ -8372,7 +8366,7 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
+ 	}
+     }
+ 
+-  return 1;
++  return true;
+ }
+ 
+ static bool
+@@ -8404,6 +8398,7 @@ display_debug_ranges (struct dwarf_section *section,
+   uint64_t last_offset = 0;
+   uint64_t next_rnglists_cu_offset = 0;
+   unsigned char offset_size;
++  bool ok_header = true;
+ 
+   if (bytes == 0)
+     {
+@@ -8493,8 +8488,12 @@ display_debug_ranges (struct dwarf_section *section,
+       /* 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 (next_rnglists_cu_offset < offset)
+-	    display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
++	  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"));
+ 	}
+ 
+@@ -8548,10 +8547,12 @@ display_debug_ranges (struct dwarf_section *section,
+     }
+ 
+   /* Display trailing empty (or unreferenced) compile units, if any.  */
+-  if (is_rnglists)
++  if (is_rnglists && ok_header)
+     while (next_rnglists_cu_offset < section->size)
+-      display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
+-
++      if (!display_debug_rnglists_unit_header (section,
++					       &next_rnglists_cu_offset,
++					       &offset_size))
++	break;
+   putchar ('\n');
+ 
+   free (range_entries);
+-- 
+2.35.6
+
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648
  2026-04-22 13:03 [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648 Adarsh Jagadish Kamini
@ 2026-04-27 15:33 ` Fabien Thomas
  2026-04-28  8:42   ` Adarsh Jagadish Kamini
  0 siblings, 1 reply; 4+ messages in thread
From: Fabien Thomas @ 2026-04-27 15:33 UTC (permalink / raw)
  To: adarsh.jagadish.kamini, openembedded-core

On Wed Apr 22, 2026 at 3:03 PM CEST, Adarsh Jagadish Kamini via lists.openembedded.org wrote:
> From: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
>
> Backport upstream fix for CVE-2025-69648 [1].
>
> [1] https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33
>
> Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
> ---
>  .../binutils/binutils-2.42.inc                |   1 +
>  .../binutils/binutils/CVE-2025-69648.patch    | 190 ++++++++++++++++++
>  2 files changed, 191 insertions(+)
>  create mode 100644 meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
>
> diff --git a/meta/recipes-devtools/binutils/binutils-2.42.inc b/meta/recipes-devtools/binutils/binutils-2.42.inc
> index a337a3e850..6c1f9dc870 100644
> --- a/meta/recipes-devtools/binutils/binutils-2.42.inc
> +++ b/meta/recipes-devtools/binutils/binutils-2.42.inc
> @@ -72,5 +72,6 @@ SRC_URI = "\
>       file://0029-CVE-2025-11839.patch \
>       file://0030-CVE-2025-11840.patch \
>       file://CVE-2025-69647.patch \
> +     file://CVE-2025-69648.patch \
>  "
>  S  = "${WORKDIR}/git"
> diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
> new file mode 100644
> index 0000000000..e04d7ed6c2
> --- /dev/null
> +++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
> @@ -0,0 +1,190 @@
> +From 7df481dd76c05c89782721e9df5468be829c356b Mon Sep 17 00:00:00 2001
> +From: Alan Modra <amodra@gmail.com>
> +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.
> +
> +CVE: CVE-2025-69648
> +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33]
> +
> +(cherry picked from commit 598704a00cbac5e85c2bedd363357b5bf6fcee33)
> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
> +Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
> +---
> + binutils/dwarf.c | 67 ++++++++++++++++++++++++------------------------
> + 1 file changed, 34 insertions(+), 33 deletions(-)
> +
> +diff --git a/binutils/dwarf.c b/binutils/dwarf.c
> +index f4bcb677761..b4fb56351ec 100644
> +--- a/binutils/dwarf.c
> ++++ b/binutils/dwarf.c
> +@@ -8282,7 +8282,7 @@ display_debug_rnglists_list (unsigned char * start,
> +   return start;
> + }
> + 
> +-static int
> ++static bool
> + display_debug_rnglists_unit_header (struct dwarf_section *  section,
> + 				    uint64_t *              unit_offset,
> + 				    unsigned char *         poffset_size)
> +@@ -8290,7 +8290,8 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +   uint64_t        start_offset = *unit_offset;
> +   unsigned char * p = section->start + start_offset;
> +   unsigned char * finish = section->start + section->size;
> +-  uint64_t        initial_length;
> ++  unsigned char * hdr;
> ++  uint64_t        length;
> +   unsigned char   segment_selector_size;
> +   unsigned int    offset_entry_count;
> +   unsigned int    i;
> +@@ -8299,66 +8300,59 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +   unsigned char   offset_size;
> + 
> +   /* Get and check the length of the block.  */
> +-  SAFE_BYTE_GET_AND_INC (initial_length, p, 4, finish);
> ++  SAFE_BYTE_GET_AND_INC (length, p, 4, finish);
> + 
> +-  if (initial_length == 0xffffffff)
> ++  if (length == 0xffffffff)
> +     {
> +       /* This section is 64-bit DWARF 3.  */
> +-      SAFE_BYTE_GET_AND_INC (initial_length, p, 8, finish);
> ++      SAFE_BYTE_GET_AND_INC (length, p, 8, finish);
> +       *poffset_size = offset_size = 8;
> +     }
> +   else
> +     *poffset_size = offset_size = 4;
> + 
> +-  if (initial_length > (size_t) (finish - p))
> +-    {
> +-      /* If the length field has a relocation against it, then we should
> +-	 not complain if it is inaccurate (and probably negative).
> +-	 It is copied from .debug_line handling code.  */
> +-      if (reloc_at (section, (p - section->start) - offset_size))
> +-	initial_length = finish - p;
> +-      else
> +-	{
> +-	  warn (_("The length field (%#" PRIx64
> +-		  ") in the debug_rnglists header is wrong"
> +-		  " - the section is too small\n"),
> +-		initial_length);
> +-	  return 0;
> +-	}
> +-    }
> +-
> +-  /* Report the next unit offset to the caller.  */
> +-  *unit_offset = (p - section->start) + initial_length;
> ++  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"), initial_length);
> ++  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 0;
> ++      return false;
> +     }
> + 
> +   if (version < 5)
> +     {
> +       warn (_("Only DWARF version 5+ debug_rnglists info "
> + 	      "is currently supported.\n"));
> +-      return 0;
> ++      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);
> +@@ -8372,7 +8366,7 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> + 	}
> +     }
> + 
> +-  return 1;
> ++  return true;
> + }
> + 
> + static bool
> +@@ -8404,6 +8398,7 @@ display_debug_ranges (struct dwarf_section *section,
> +   uint64_t last_offset = 0;
> +   uint64_t next_rnglists_cu_offset = 0;
> +   unsigned char offset_size;
> ++  bool ok_header = true;
> + 
> +   if (bytes == 0)
> +     {
> +@@ -8493,8 +8488,12 @@ display_debug_ranges (struct dwarf_section *section,
> +       /* 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 (next_rnglists_cu_offset < offset)
> +-	    display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
> ++	  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"));
> + 	}
> + 
> +@@ -8548,10 +8547,12 @@ display_debug_ranges (struct dwarf_section *section,
> +     }
> + 
> +   /* Display trailing empty (or unreferenced) compile units, if any.  */
> +-  if (is_rnglists)
> ++  if (is_rnglists && ok_header)
> +     while (next_rnglists_cu_offset < section->size)
> +-      display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
> +-
> ++      if (!display_debug_rnglists_unit_header (section,
> ++					       &next_rnglists_cu_offset,
> ++					       &offset_size))
> ++	break;
> +   putchar ('\n');
> + 
> +   free (range_entries);
> +-- 
> +2.35.6
> +

Hello Adarsh,

I'm filling in for Yoann while he's on leave.

Thank you for these pathes. A few notes, however: for future binutils projects, 
please include links to the CVE (ideally NVD or NIST), as well as the link 
to the Bugzilla entry mentioned in the patch that indicates that the patch 
is resolved and in which version (especially when there are “duplicates”).

All of these elements make it easier for us to validate the patch.

And for this second patch, I see a Signed-off-by: Deepak Rathore <deeratho@cisco.com>
Are there two of you from different companies who made this backport, 
or is this a mistake?

Thank for your reply.
--
Fabien Thomas
Smile ECS



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648
  2026-04-27 15:33 ` Fabien Thomas
@ 2026-04-28  8:42   ` Adarsh Jagadish Kamini
  2026-04-28 13:02     ` Fabien Thomas
  0 siblings, 1 reply; 4+ messages in thread
From: Adarsh Jagadish Kamini @ 2026-04-28  8:42 UTC (permalink / raw)
  To: Fabien Thomas, openembedded-core@lists.openembedded.org

[-- Attachment #1: Type: text/plain, Size: 10428 bytes --]

Hi,
The original patch was submitted to whinlatter by Deepak. So, I kept it to pass the credits.

Thanks!
________________________________
From: Fabien Thomas <fabien.thomas@smile.fr>
Sent: Monday, April 27, 2026 17:33
To: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>; openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org>
Subject: Re: [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648

On Wed Apr 22, 2026 at 3:03 PM CEST, Adarsh Jagadish Kamini via lists.openembedded.org wrote:
> From: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
>
> Backport upstream fix for CVE-2025-69648 [1].
>
> [1] https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33
>
> Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
> ---
>  .../binutils/binutils-2.42.inc                |   1 +
>  .../binutils/binutils/CVE-2025-69648.patch    | 190 ++++++++++++++++++
>  2 files changed, 191 insertions(+)
>  create mode 100644 meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
>
> diff --git a/meta/recipes-devtools/binutils/binutils-2.42.inc b/meta/recipes-devtools/binutils/binutils-2.42.inc
> index a337a3e850..6c1f9dc870 100644
> --- a/meta/recipes-devtools/binutils/binutils-2.42.inc
> +++ b/meta/recipes-devtools/binutils/binutils-2.42.inc
> @@ -72,5 +72,6 @@ SRC_URI = "\
>       file://0029-CVE-2025-11839.patch \
>       file://0030-CVE-2025-11840.patch \
>       file://CVE-2025-69647.patch \
> +     file://CVE-2025-69648.patch \
>  "
>  S  = "${WORKDIR}/git"
> diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
> new file mode 100644
> index 0000000000..e04d7ed6c2
> --- /dev/null
> +++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
> @@ -0,0 +1,190 @@
> +From 7df481dd76c05c89782721e9df5468be829c356b Mon Sep 17 00:00:00 2001
> +From: Alan Modra <amodra@gmail.com>
> +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.
> +
> +CVE: CVE-2025-69648
> +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33]
> +
> +(cherry picked from commit 598704a00cbac5e85c2bedd363357b5bf6fcee33)
> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
> +Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
> +---
> + binutils/dwarf.c | 67 ++++++++++++++++++++++++------------------------
> + 1 file changed, 34 insertions(+), 33 deletions(-)
> +
> +diff --git a/binutils/dwarf.c b/binutils/dwarf.c
> +index f4bcb677761..b4fb56351ec 100644
> +--- a/binutils/dwarf.c
> ++++ b/binutils/dwarf.c
> +@@ -8282,7 +8282,7 @@ display_debug_rnglists_list (unsigned char * start,
> +   return start;
> + }
> +
> +-static int
> ++static bool
> + display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +                                  uint64_t *              unit_offset,
> +                                  unsigned char *         poffset_size)
> +@@ -8290,7 +8290,8 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +   uint64_t        start_offset = *unit_offset;
> +   unsigned char * p = section->start + start_offset;
> +   unsigned char * finish = section->start + section->size;
> +-  uint64_t        initial_length;
> ++  unsigned char * hdr;
> ++  uint64_t        length;
> +   unsigned char   segment_selector_size;
> +   unsigned int    offset_entry_count;
> +   unsigned int    i;
> +@@ -8299,66 +8300,59 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +   unsigned char   offset_size;
> +
> +   /* Get and check the length of the block.  */
> +-  SAFE_BYTE_GET_AND_INC (initial_length, p, 4, finish);
> ++  SAFE_BYTE_GET_AND_INC (length, p, 4, finish);
> +
> +-  if (initial_length == 0xffffffff)
> ++  if (length == 0xffffffff)
> +     {
> +       /* This section is 64-bit DWARF 3.  */
> +-      SAFE_BYTE_GET_AND_INC (initial_length, p, 8, finish);
> ++      SAFE_BYTE_GET_AND_INC (length, p, 8, finish);
> +       *poffset_size = offset_size = 8;
> +     }
> +   else
> +     *poffset_size = offset_size = 4;
> +
> +-  if (initial_length > (size_t) (finish - p))
> +-    {
> +-      /* If the length field has a relocation against it, then we should
> +-     not complain if it is inaccurate (and probably negative).
> +-     It is copied from .debug_line handling code.  */
> +-      if (reloc_at (section, (p - section->start) - offset_size))
> +-    initial_length = finish - p;
> +-      else
> +-    {
> +-      warn (_("The length field (%#" PRIx64
> +-              ") in the debug_rnglists header is wrong"
> +-              " - the section is too small\n"),
> +-            initial_length);
> +-      return 0;
> +-    }
> +-    }
> +-
> +-  /* Report the next unit offset to the caller.  */
> +-  *unit_offset = (p - section->start) + initial_length;
> ++  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"), initial_length);
> ++  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 0;
> ++      return false;
> +     }
> +
> +   if (version < 5)
> +     {
> +       warn (_("Only DWARF version 5+ debug_rnglists info "
> +            "is currently supported.\n"));
> +-      return 0;
> ++      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);
> +@@ -8372,7 +8366,7 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
> +      }
> +     }
> +
> +-  return 1;
> ++  return true;
> + }
> +
> + static bool
> +@@ -8404,6 +8398,7 @@ display_debug_ranges (struct dwarf_section *section,
> +   uint64_t last_offset = 0;
> +   uint64_t next_rnglists_cu_offset = 0;
> +   unsigned char offset_size;
> ++  bool ok_header = true;
> +
> +   if (bytes == 0)
> +     {
> +@@ -8493,8 +8488,12 @@ display_debug_ranges (struct dwarf_section *section,
> +       /* 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 (next_rnglists_cu_offset < offset)
> +-        display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
> ++      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"));
> +      }
> +
> +@@ -8548,10 +8547,12 @@ display_debug_ranges (struct dwarf_section *section,
> +     }
> +
> +   /* Display trailing empty (or unreferenced) compile units, if any.  */
> +-  if (is_rnglists)
> ++  if (is_rnglists && ok_header)
> +     while (next_rnglists_cu_offset < section->size)
> +-      display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
> +-
> ++      if (!display_debug_rnglists_unit_header (section,
> ++                                           &next_rnglists_cu_offset,
> ++                                           &offset_size))
> ++    break;
> +   putchar ('\n');
> +
> +   free (range_entries);
> +--
> +2.35.6
> +

Hello Adarsh,

I'm filling in for Yoann while he's on leave.

Thank you for these pathes. A few notes, however: for future binutils projects,
please include links to the CVE (ideally NVD or NIST), as well as the link
to the Bugzilla entry mentioned in the patch that indicates that the patch
is resolved and in which version (especially when there are “duplicates”).

All of these elements make it easier for us to validate the patch.

And for this second patch, I see a Signed-off-by: Deepak Rathore <deeratho@cisco.com>
Are there two of you from different companies who made this backport,
or is this a mistake?

Thank for your reply.
--
Fabien Thomas
Smile ECS


[-- Attachment #2: Type: text/html, Size: 18441 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648
  2026-04-28  8:42   ` Adarsh Jagadish Kamini
@ 2026-04-28 13:02     ` Fabien Thomas
  0 siblings, 0 replies; 4+ messages in thread
From: Fabien Thomas @ 2026-04-28 13:02 UTC (permalink / raw)
  To: Adarsh Jagadish Kamini, Fabien Thomas,
	openembedded-core@lists.openembedded.org

On Tue Apr 28, 2026 at 10:42 AM CEST, Adarsh Jagadish Kamini wrote:
> Hi,
> The original patch was submitted to whinlatter by Deepak. So, I kept it to pass the credits.

Oh, right, good point.
Noted, thanks.

>
> Thanks!
> ________________________________
> From: Fabien Thomas <fabien.thomas@smile.fr>
> Sent: Monday, April 27, 2026 17:33
> To: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>; openembedded-core@lists.openembedded.org <openembedded-core@lists.openembedded.org>
> Subject: Re: [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648
>
> On Wed Apr 22, 2026 at 3:03 PM CEST, Adarsh Jagadish Kamini via lists.openembedded.org wrote:
>> From: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
>>
>> Backport upstream fix for CVE-2025-69648 [1].
>>
>> [1] https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33
>>
>> Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
>> ---
>>  .../binutils/binutils-2.42.inc                |   1 +
>>  .../binutils/binutils/CVE-2025-69648.patch    | 190 ++++++++++++++++++
>>  2 files changed, 191 insertions(+)
>>  create mode 100644 meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
>>
>> diff --git a/meta/recipes-devtools/binutils/binutils-2.42.inc b/meta/recipes-devtools/binutils/binutils-2.42.inc
>> index a337a3e850..6c1f9dc870 100644
>> --- a/meta/recipes-devtools/binutils/binutils-2.42.inc
>> +++ b/meta/recipes-devtools/binutils/binutils-2.42.inc
>> @@ -72,5 +72,6 @@ SRC_URI = "\
>>       file://0029-CVE-2025-11839.patch \
>>       file://0030-CVE-2025-11840.patch \
>>       file://CVE-2025-69647.patch \
>> +     file://CVE-2025-69648.patch \
>>  "
>>  S  = "${WORKDIR}/git"
>> diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
>> new file mode 100644
>> index 0000000000..e04d7ed6c2
>> --- /dev/null
>> +++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-69648.patch
>> @@ -0,0 +1,190 @@
>> +From 7df481dd76c05c89782721e9df5468be829c356b Mon Sep 17 00:00:00 2001
>> +From: Alan Modra <amodra@gmail.com>
>> +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.
>> +
>> +CVE: CVE-2025-69648
>> +Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=598704a00cbac5e85c2bedd363357b5bf6fcee33]
>> +
>> +(cherry picked from commit 598704a00cbac5e85c2bedd363357b5bf6fcee33)
>> +Signed-off-by: Deepak Rathore <deeratho@cisco.com>
>> +Signed-off-by: Adarsh Jagadish Kamini <adarsh.jagadish.kamini@est.tech>
>> +---
>> + binutils/dwarf.c | 67 ++++++++++++++++++++++++------------------------
>> + 1 file changed, 34 insertions(+), 33 deletions(-)
>> +
>> +diff --git a/binutils/dwarf.c b/binutils/dwarf.c
>> +index f4bcb677761..b4fb56351ec 100644
>> +--- a/binutils/dwarf.c
>> ++++ b/binutils/dwarf.c
>> +@@ -8282,7 +8282,7 @@ display_debug_rnglists_list (unsigned char * start,
>> +   return start;
>> + }
>> +
>> +-static int
>> ++static bool
>> + display_debug_rnglists_unit_header (struct dwarf_section *  section,
>> +                                  uint64_t *              unit_offset,
>> +                                  unsigned char *         poffset_size)
>> +@@ -8290,7 +8290,8 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
>> +   uint64_t        start_offset = *unit_offset;
>> +   unsigned char * p = section->start + start_offset;
>> +   unsigned char * finish = section->start + section->size;
>> +-  uint64_t        initial_length;
>> ++  unsigned char * hdr;
>> ++  uint64_t        length;
>> +   unsigned char   segment_selector_size;
>> +   unsigned int    offset_entry_count;
>> +   unsigned int    i;
>> +@@ -8299,66 +8300,59 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
>> +   unsigned char   offset_size;
>> +
>> +   /* Get and check the length of the block.  */
>> +-  SAFE_BYTE_GET_AND_INC (initial_length, p, 4, finish);
>> ++  SAFE_BYTE_GET_AND_INC (length, p, 4, finish);
>> +
>> +-  if (initial_length == 0xffffffff)
>> ++  if (length == 0xffffffff)
>> +     {
>> +       /* This section is 64-bit DWARF 3.  */
>> +-      SAFE_BYTE_GET_AND_INC (initial_length, p, 8, finish);
>> ++      SAFE_BYTE_GET_AND_INC (length, p, 8, finish);
>> +       *poffset_size = offset_size = 8;
>> +     }
>> +   else
>> +     *poffset_size = offset_size = 4;
>> +
>> +-  if (initial_length > (size_t) (finish - p))
>> +-    {
>> +-      /* If the length field has a relocation against it, then we should
>> +-     not complain if it is inaccurate (and probably negative).
>> +-     It is copied from .debug_line handling code.  */
>> +-      if (reloc_at (section, (p - section->start) - offset_size))
>> +-    initial_length = finish - p;
>> +-      else
>> +-    {
>> +-      warn (_("The length field (%#" PRIx64
>> +-              ") in the debug_rnglists header is wrong"
>> +-              " - the section is too small\n"),
>> +-            initial_length);
>> +-      return 0;
>> +-    }
>> +-    }
>> +-
>> +-  /* Report the next unit offset to the caller.  */
>> +-  *unit_offset = (p - section->start) + initial_length;
>> ++  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"), initial_length);
>> ++  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 0;
>> ++      return false;
>> +     }
>> +
>> +   if (version < 5)
>> +     {
>> +       warn (_("Only DWARF version 5+ debug_rnglists info "
>> +            "is currently supported.\n"));
>> +-      return 0;
>> ++      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);
>> +@@ -8372,7 +8366,7 @@ display_debug_rnglists_unit_header (struct dwarf_section *  section,
>> +      }
>> +     }
>> +
>> +-  return 1;
>> ++  return true;
>> + }
>> +
>> + static bool
>> +@@ -8404,6 +8398,7 @@ display_debug_ranges (struct dwarf_section *section,
>> +   uint64_t last_offset = 0;
>> +   uint64_t next_rnglists_cu_offset = 0;
>> +   unsigned char offset_size;
>> ++  bool ok_header = true;
>> +
>> +   if (bytes == 0)
>> +     {
>> +@@ -8493,8 +8488,12 @@ display_debug_ranges (struct dwarf_section *section,
>> +       /* 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 (next_rnglists_cu_offset < offset)
>> +-        display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
>> ++      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"));
>> +      }
>> +
>> +@@ -8548,10 +8547,12 @@ display_debug_ranges (struct dwarf_section *section,
>> +     }
>> +
>> +   /* Display trailing empty (or unreferenced) compile units, if any.  */
>> +-  if (is_rnglists)
>> ++  if (is_rnglists && ok_header)
>> +     while (next_rnglists_cu_offset < section->size)
>> +-      display_debug_rnglists_unit_header (section, &next_rnglists_cu_offset, &offset_size);
>> +-
>> ++      if (!display_debug_rnglists_unit_header (section,
>> ++                                           &next_rnglists_cu_offset,
>> ++                                           &offset_size))
>> ++    break;
>> +   putchar ('\n');
>> +
>> +   free (range_entries);
>> +--
>> +2.35.6
>> +
>
> Hello Adarsh,
>
> I'm filling in for Yoann while he's on leave.
>
> Thank you for these pathes. A few notes, however: for future binutils projects,
> please include links to the CVE (ideally NVD or NIST), as well as the link
> to the Bugzilla entry mentioned in the patch that indicates that the patch
> is resolved and in which version (especially when there are “duplicates”).
>
> All of these elements make it easier for us to validate the patch.
>
> And for this second patch, I see a Signed-off-by: Deepak Rathore <deeratho@cisco.com>
> Are there two of you from different companies who made this backport,
> or is this a mistake?
>
> Thank for your reply.
> --
> Fabien Thomas
> Smile ECS




-- 
Fabien Thomas
Smile ECS


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-28 13:03 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-22 13:03 [OE-core][scarthgap][PATCH 2/4] binutils: fix CVE-2025-69648 Adarsh Jagadish Kamini
2026-04-27 15:33 ` Fabien Thomas
2026-04-28  8:42   ` Adarsh Jagadish Kamini
2026-04-28 13:02     ` Fabien Thomas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox