]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
readelf: ubsan unsigned offset overflow
authorAlan Modra <amodra@gmail.com>
Wed, 11 Feb 2026 11:41:58 +0000 (22:11 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 11 Feb 2026 11:47:09 +0000 (22:17 +1030)
PR 33897
* dwarf.c (display_debug_frames): Don't calculate "look_for"
until we have checked that cie_off is valid.

binutils/dwarf.c

index 3c2ba3099fbff375d249c11f3ce5b760cd6ae312..3be02345afbf2f2945ac702b804e33a8f0b2ef79 100644 (file)
@@ -10952,7 +10952,6 @@ display_debug_frames (struct dwarf_section *section,
        }
       else
        {
-         unsigned char *look_for;
          unsigned long segment_selector;
          uint64_t cie_off;
 
@@ -10964,70 +10963,74 @@ display_debug_frames (struct dwarf_section *section,
              cie_off = start - 4 - section_start - cie_off;
            }
 
-         look_for = section_start + cie_off;
-         if (cie_off <= (size_t) (saved_start - section_start))
-           {
-             for (cie = chunks; cie ; cie = cie->next)
-               if (cie->chunk_start == look_for)
-                 break;
-           }
-         else if (cie_off >= section->size)
+         if (cie_off >= section->size)
            cie = NULL;
          else
            {
-             for (cie = forward_refs; cie ; cie = cie->next)
-               if (cie->chunk_start == look_for)
-                 break;
-             if (!cie)
+             unsigned char *look_for = section_start + cie_off;
+             if (cie_off <= (size_t) (saved_start - section_start))
                {
-                 unsigned int off_size;
-                 unsigned char *cie_scan;
-
-                 cie_scan = look_for;
-                 off_size = 4;
-                 SAFE_BYTE_GET_AND_INC (length, cie_scan, 4, end);
-                 if (length == 0xffffffff)
-                   {
-                     SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
-                     off_size = 8;
-                   }
-                 if (length != 0 && length <= (size_t) (end - cie_scan))
+                 for (cie = chunks; cie ; cie = cie->next)
+                   if (cie->chunk_start == look_for)
+                     break;
+               }
+             else
+               {
+                 for (cie = forward_refs; cie ; cie = cie->next)
+                   if (cie->chunk_start == look_for)
+                     break;
+                 if (!cie)
                    {
-                     uint64_t c_id;
-                     unsigned char *cie_end = cie_scan + length;
-
-                     SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size,
-                                            cie_end);
-                     if (is_eh
-                         ? c_id == 0
-                         : ((off_size == 4 && c_id == DW_CIE_ID)
-                            || (off_size == 8 && c_id == DW64_CIE_ID)))
-                       {
-                         int version;
-                         unsigned int mreg;
+                     unsigned int off_size;
+                     unsigned char *cie_scan;
 
-                         read_cie (cie_scan, cie_end, &cie, &version,
-                                   &augmentation_data_len, &augmentation_data);
-                         /* PR 17512: file: 3450-2098-0.004.  */
-                         if (cie == NULL)
-                           {
-                             warn (_("Failed to read CIE information\n"));
-                             break;
-                           }
-                         cie->next = forward_refs;
-                         forward_refs = cie;
-                         cie->chunk_start = look_for;
-                         mreg = max_regs > 0 ? max_regs - 1 : 0;
-                         if (mreg < cie->ra)
-                           mreg = cie->ra;
-                         if (frame_need_space (cie, mreg) < 0)
+                     cie_scan = look_for;
+                     off_size = 4;
+                     SAFE_BYTE_GET_AND_INC (length, cie_scan, 4, end);
+                     if (length == 0xffffffff)
+                       {
+                         SAFE_BYTE_GET_AND_INC (length, cie_scan, 8, end);
+                         off_size = 8;
+                       }
+                     if (length != 0 && length <= (size_t) (end - cie_scan))
+                       {
+                         uint64_t c_id;
+                         unsigned char *cie_end = cie_scan + length;
+
+                         SAFE_BYTE_GET_AND_INC (c_id, cie_scan, off_size,
+                                                cie_end);
+                         if (is_eh
+                             ? c_id == 0
+                             : ((off_size == 4 && c_id == DW_CIE_ID)
+                                || (off_size == 8 && c_id == DW64_CIE_ID)))
                            {
-                             warn (_("Invalid max register\n"));
-                             break;
+                             int version;
+                             unsigned int mreg;
+
+                             read_cie (cie_scan, cie_end, &cie, &version,
+                                       &augmentation_data_len,
+                                       &augmentation_data);
+                             /* PR 17512: file: 3450-2098-0.004.  */
+                             if (cie == NULL)
+                               {
+                                 warn (_("Failed to read CIE information\n"));
+                                 break;
+                               }
+                             cie->next = forward_refs;
+                             forward_refs = cie;
+                             cie->chunk_start = look_for;
+                             mreg = max_regs > 0 ? max_regs - 1 : 0;
+                             if (mreg < cie->ra)
+                               mreg = cie->ra;
+                             if (frame_need_space (cie, mreg) < 0)
+                               {
+                                 warn (_("Invalid max register\n"));
+                                 break;
+                               }
+                             if (cie->fde_encoding)
+                               encoded_ptr_size
+                                 = size_of_encoded_value (cie->fde_encoding);
                            }
-                         if (cie->fde_encoding)
-                           encoded_ptr_size
-                             = size_of_encoded_value (cie->fde_encoding);
                        }
                    }
                }