summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-3.patch
blob: 6a838ea3eaff8df460c09066c440ef0a0cc76a4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
From 31d6c13defeba7716ebc9d5c8f81f2f35fe39980 Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
Date: Tue, 14 Jun 2022 12:46:42 +0930
Subject: [PATCH] PR29230, segv in lookup_symbol_in_variable_table

The PR23230 testcase uses indexed strings without specifying
SW_AT_str_offsets_base.  In this case we left u.str with garbage (from
u.val) which then led to a segfault when attempting to access the
string.  Fix that by clearing u.str.  The patch also adds missing
sanity checks in the recently committed read_indexed_address and
read_indexed_string functions.

	PR 29230
	* dwarf2.c (read_indexed_address): Return uint64_t.  Sanity check idx.
	(read_indexed_string): Use uint64_t for str_offset.  Sanity check idx.
	(read_attribute_value): Clear u.str for indexed string forms when
	DW_AT_str_offsets_base is not yet read or missing.

Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=31d6c13defeba7716ebc9d5c8f81f2f35fe39980]

CVE: CVE-2023-1579

Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com>

---
 bfd/dwarf2.c | 51 ++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 42 insertions(+), 9 deletions(-)

diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index 51018e1ab45..aaa2d84887f 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -1353,13 +1353,13 @@ is_addrx_form (enum dwarf_form form)

 /* Returns the address in .debug_addr section using DW_AT_addr_base.
    Used to implement DW_FORM_addrx*.  */
-static bfd_vma
+static uint64_t
 read_indexed_address (uint64_t idx, struct comp_unit *unit)
 {
   struct dwarf2_debug *stash = unit->stash;
   struct dwarf2_debug_file *file = unit->file;
-  size_t addr_base = unit->dwarf_addr_offset;
   bfd_byte *info_ptr;
+  size_t offset;

   if (stash == NULL)
     return 0;
@@ -1369,12 +1369,23 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit)
 		     &file->dwarf_addr_buffer, &file->dwarf_addr_size))
     return 0;

-  info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size;
+  if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
+    return 0;
+
+  offset += unit->dwarf_addr_offset;
+  if (offset < unit->dwarf_addr_offset
+      || offset > file->dwarf_addr_size
+      || file->dwarf_addr_size - offset < unit->offset_size)
+    return 0;
+
+  info_ptr = file->dwarf_addr_buffer + offset;

   if (unit->offset_size == 4)
     return bfd_get_32 (unit->abfd, info_ptr);
-  else
+  else if (unit->offset_size == 8)
     return bfd_get_64 (unit->abfd, info_ptr);
+  else
+    return 0;
 }

 /* Returns the string using DW_AT_str_offsets_base.
@@ -1385,7 +1396,8 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
   struct dwarf2_debug *stash = unit->stash;
   struct dwarf2_debug_file *file = unit->file;
   bfd_byte *info_ptr;
-  unsigned long str_offset;
+  uint64_t str_offset;
+  size_t offset;

   if (stash == NULL)
     return NULL;
@@ -1401,15 +1413,26 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
 		     &file->dwarf_str_offsets_size))
     return NULL;

-  info_ptr = (file->dwarf_str_offsets_buffer
-	      + unit->dwarf_str_offset
-	      + idx * unit->offset_size);
+  if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
+    return NULL;
+
+  offset += unit->dwarf_str_offset;
+  if (offset < unit->dwarf_str_offset
+      || offset > file->dwarf_str_offsets_size
+      || file->dwarf_str_offsets_size - offset < unit->offset_size)
+    return NULL;
+
+  info_ptr = file->dwarf_str_offsets_buffer + offset;

   if (unit->offset_size == 4)
     str_offset = bfd_get_32 (unit->abfd, info_ptr);
-  else
+  else if (unit->offset_size == 8)
     str_offset = bfd_get_64 (unit->abfd, info_ptr);
+  else
+    return NULL;

+  if (str_offset >= file->dwarf_str_size)
+    return NULL;
   return (const char *) file->dwarf_str_buffer + str_offset;
 }

@@ -1534,27 +1557,37 @@ read_attribute_value (struct attribute *  attr,
 	 is not yet read.  */
       if (unit->dwarf_str_offset != 0)
 	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      else
+	attr->u.str = NULL;
       break;
     case DW_FORM_strx2:
       attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
       if (unit->dwarf_str_offset != 0)
 	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      else
+	attr->u.str = NULL;
       break;
     case DW_FORM_strx3:
       attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
       if (unit->dwarf_str_offset != 0)
 	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      else
+	attr->u.str = NULL;
       break;
     case DW_FORM_strx4:
       attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
       if (unit->dwarf_str_offset != 0)
 	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      else
+	attr->u.str = NULL;
       break;
     case DW_FORM_strx:
       attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
 					   false, info_ptr_end);
       if (unit->dwarf_str_offset != 0)
 	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      else
+	attr->u.str = NULL;
       break;
     case DW_FORM_exprloc:
     case DW_FORM_block:
--
2.31.1