summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch
blob: 1e9c03e70e61070b84b85e638fe5538a3cbb61cc (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
From f67741e172bf342291fe3abd2b395899ce6433a0 Mon Sep 17 00:00:00 2001
From: "Potharla, Rupesh" <Rupesh.Potharla@amd.com>
Date: Tue, 24 May 2022 00:01:49 +0000
Subject: [PATCH] bfd: Add Support for DW_FORM_strx* and DW_FORM_addrx*

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

CVE: CVE-2023-1579

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

---
 bfd/dwarf2.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 268 insertions(+), 14 deletions(-)

diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
index f6b0183720b..45e286754e4 100644
--- a/bfd/dwarf2.c
+++ b/bfd/dwarf2.c
@@ -189,6 +189,18 @@ struct dwarf2_debug_file
   /* Length of the loaded .debug_str section.  */
   bfd_size_type dwarf_str_size;

+  /* Pointer to the .debug_str_offsets section loaded into memory.  */
+  bfd_byte *dwarf_str_offsets_buffer;
+
+  /* Length of the loaded .debug_str_offsets section.  */
+  bfd_size_type dwarf_str_offsets_size;
+
+  /* Pointer to the .debug_addr section loaded into memory.  */
+  bfd_byte *dwarf_addr_buffer;
+
+  /* Length of the loaded .debug_addr section.  */
+  bfd_size_type dwarf_addr_size;
+
   /* Pointer to the .debug_line_str section loaded into memory.  */
   bfd_byte *dwarf_line_str_buffer;

@@ -382,6 +394,12 @@ struct comp_unit
   /* Used when iterating over trie leaves to know which units we have
      already seen in this iteration.  */
   bool mark;
+
+ /* Base address of debug_addr section.  */
+  size_t dwarf_addr_offset;
+
+  /* Base address of string offset table.  */
+  size_t dwarf_str_offset;
 };

 /* This data structure holds the information of an abbrev.  */
@@ -424,6 +442,8 @@ const struct dwarf_debug_section dwarf_debug_sections[] =
   { ".debug_static_vars",	".zdebug_static_vars" },
   { ".debug_str",		".zdebug_str", },
   { ".debug_str",		".zdebug_str", },
+  { ".debug_str_offsets",	".zdebug_str_offsets", },
+  { ".debug_addr",		".zdebug_addr", },
   { ".debug_line_str",		".zdebug_line_str", },
   { ".debug_types",		".zdebug_types" },
   /* GNU DWARF 1 extensions */
@@ -458,6 +478,8 @@ enum dwarf_debug_section_enum
   debug_static_vars,
   debug_str,
   debug_str_alt,
+  debug_str_offsets,
+  debug_addr,
   debug_line_str,
   debug_types,
   debug_sfnames,
@@ -1307,12 +1329,92 @@ is_int_form (const struct attribute *attr)
     }
 }

+/* Returns true if the form is strx[1-4].  */
+
+static inline bool
+is_strx_form (enum dwarf_form form)
+{
+  return (form == DW_FORM_strx
+	  || form == DW_FORM_strx1
+	  || form == DW_FORM_strx2
+	  || form == DW_FORM_strx3
+	  || form == DW_FORM_strx4);
+}
+
+/* Return true if the form is addrx[1-4].  */
+
+static inline bool
+is_addrx_form (enum dwarf_form form)
+{
+  return (form == DW_FORM_addrx
+	  || form == DW_FORM_addrx1
+	  || form == DW_FORM_addrx2
+	  || form == DW_FORM_addrx3
+	  || form == DW_FORM_addrx4);
+}
+
+/* Returns the address in .debug_addr section using DW_AT_addr_base.
+   Used to implement DW_FORM_addrx*.  */
+static bfd_vma
+read_indexed_address (bfd_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;
+
+  if (stash == NULL)
+    return 0;
+
+  if (!read_section (unit->abfd, &stash->debug_sections[debug_addr],
+		     file->syms, 0,
+		     &file->dwarf_addr_buffer, &file->dwarf_addr_size))
+    return 0;
+
+  info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size;
+
+  if (unit->offset_size == 4)
+    return bfd_get_32 (unit->abfd, info_ptr);
+  else
+    return bfd_get_64 (unit->abfd, info_ptr);
+}
+
+/* Returns the string using DW_AT_str_offsets_base.
+   Used to implement DW_FORM_strx*.  */
 static const char *
-read_indexed_string (bfd_uint64_t idx ATTRIBUTE_UNUSED,
-		     struct comp_unit * unit ATTRIBUTE_UNUSED)
+read_indexed_string (bfd_uint64_t idx,
+		     struct comp_unit *unit)
 {
-  /* FIXME: Add support for indexed strings.  */
-  return "<indexed strings not yet supported>";
+  struct dwarf2_debug *stash = unit->stash;
+  struct dwarf2_debug_file *file = unit->file;
+  bfd_byte *info_ptr;
+  unsigned long str_offset;
+
+  if (stash == NULL)
+    return NULL;
+
+  if (!read_section (unit->abfd, &stash->debug_sections[debug_str],
+		     file->syms, 0,
+		     &file->dwarf_str_buffer, &file->dwarf_str_size))
+    return NULL;
+
+  if (!read_section (unit->abfd, &stash->debug_sections[debug_str_offsets],
+		     file->syms, 0,
+		     &file->dwarf_str_offsets_buffer,
+		     &file->dwarf_str_offsets_size))
+    return NULL;
+
+  info_ptr = (file->dwarf_str_offsets_buffer
+	      + unit->dwarf_str_offset
+	      + idx * unit->offset_size);
+
+  if (unit->offset_size == 4)
+    str_offset = bfd_get_32 (unit->abfd, info_ptr);
+  else
+    str_offset = bfd_get_64 (unit->abfd, info_ptr);
+
+  return (const char *) file->dwarf_str_buffer + str_offset;
 }

 /* Read and fill in the value of attribute ATTR as described by FORM.
@@ -1381,21 +1483,37 @@ read_attribute_value (struct attribute *  attr,
     case DW_FORM_ref1:
     case DW_FORM_flag:
     case DW_FORM_data1:
+      attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
+      break;
     case DW_FORM_addrx1:
       attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
+      /* dwarf_addr_offset value 0 indicates the attribute DW_AT_addr_base
+	 is not yet read.  */
+      if (unit->dwarf_addr_offset != 0)
+	attr->u.val = read_indexed_address (attr->u.val, unit);
       break;
     case DW_FORM_data2:
-    case DW_FORM_addrx2:
     case DW_FORM_ref2:
       attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
       break;
+    case DW_FORM_addrx2:
+      attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
+      if (unit->dwarf_addr_offset != 0)
+	attr->u.val = read_indexed_address (attr->u.val, unit);
+      break;
     case DW_FORM_addrx3:
       attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
+      if (unit->dwarf_addr_offset != 0)
+	attr->u.val = read_indexed_address(attr->u.val, unit);
       break;
     case DW_FORM_ref4:
     case DW_FORM_data4:
+      attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
+      break;
     case DW_FORM_addrx4:
       attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
+      if (unit->dwarf_addr_offset != 0)
+	attr->u.val = read_indexed_address (attr->u.val, unit);
       break;
     case DW_FORM_data8:
     case DW_FORM_ref8:
@@ -1416,24 +1534,31 @@ read_attribute_value (struct attribute *  attr,
       break;
     case DW_FORM_strx1:
       attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
-      attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      /* dwarf_str_offset value 0 indicates the attribute DW_AT_str_offsets_base
+	 is not yet read.  */
+      if (unit->dwarf_str_offset != 0)
+	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
       break;
     case DW_FORM_strx2:
       attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
-      attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      if (unit->dwarf_str_offset != 0)
+	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
       break;
     case DW_FORM_strx3:
       attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
-      attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      if (unit->dwarf_str_offset != 0)
+	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
       break;
     case DW_FORM_strx4:
       attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
-      attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      if (unit->dwarf_str_offset != 0)
+	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
       break;
     case DW_FORM_strx:
       attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
 					   false, info_ptr_end);
-      attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+      if (unit->dwarf_str_offset != 0)
+	attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
       break;
     case DW_FORM_exprloc:
     case DW_FORM_block:
@@ -1455,9 +1580,14 @@ read_attribute_value (struct attribute *  attr,
       break;
     case DW_FORM_ref_udata:
     case DW_FORM_udata:
+      attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
+					   false, info_ptr_end);
+      break;
     case DW_FORM_addrx:
       attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
 					   false, info_ptr_end);
+      if (unit->dwarf_addr_offset != 0)
+	attr->u.val = read_indexed_address (attr->u.val, unit);
       break;
     case DW_FORM_indirect:
       form = _bfd_safe_read_leb128 (abfd, &info_ptr,
@@ -2396,6 +2526,11 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp,
 	    {
 	    case DW_FORM_string:
 	    case DW_FORM_line_strp:
+	    case DW_FORM_strx:
+	    case DW_FORM_strx1:
+	    case DW_FORM_strx2:
+	    case DW_FORM_strx3:
+	    case DW_FORM_strx4:
 	      *stringp = attr.u.str;
 	      break;

@@ -4031,6 +4166,80 @@ scan_unit_for_symbols (struct comp_unit *unit)
   return false;
 }

+/* Read the attributes of the form strx and addrx.  */
+
+static void
+reread_attribute (struct comp_unit *unit,
+		  struct attribute *attr,
+		  bfd_vma *low_pc,
+		  bfd_vma *high_pc,
+		  bool *high_pc_relative,
+		  bool compunit)
+{
+  if (is_strx_form (attr->form))
+    attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
+  if (is_addrx_form (attr->form))
+    attr->u.val = read_indexed_address (attr->u.val, unit);
+
+  switch (attr->name)
+    {
+    case DW_AT_stmt_list:
+      unit->stmtlist = 1;
+      unit->line_offset = attr->u.val;
+      break;
+
+    case DW_AT_name:
+      if (is_str_form (attr))
+	unit->name = attr->u.str;
+      break;
+
+    case DW_AT_low_pc:
+      *low_pc = attr->u.val;
+      if (compunit)
+	unit->base_address = *low_pc;
+      break;
+
+    case DW_AT_high_pc:
+      *high_pc = attr->u.val;
+      *high_pc_relative = attr->form != DW_FORM_addr;
+      break;
+
+    case DW_AT_ranges:
+      if (!read_rangelist (unit, &unit->arange,
+			   &unit->file->trie_root, attr->u.val))
+	return;
+      break;
+
+    case DW_AT_comp_dir:
+      {
+	char *comp_dir = attr->u.str;
+
+	if (!is_str_form (attr))
+	  {
+	    _bfd_error_handler
+	      (_("DWARF error: DW_AT_comp_dir attribute encountered "
+		 "with a non-string form"));
+	    comp_dir = NULL;
+	  }
+
+	if (comp_dir)
+	  {
+	    char *cp = strchr (comp_dir, ':');
+
+	    if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/')
+	      comp_dir = cp + 1;
+	  }
+	unit->comp_dir = comp_dir;
+	break;
+      }
+
+    case DW_AT_language:
+      unit->lang = attr->u.val;
+    default:
+      break;
+    }
+}
+
 /* Parse a DWARF2 compilation unit starting at INFO_PTR.  UNIT_LENGTH
    includes the compilation unit header that proceeds the DIE's, but
    does not include the length field that precedes each compilation
@@ -4064,6 +4273,10 @@ parse_comp_unit (struct dwarf2_debug *stash,
   bfd *abfd = file->bfd_ptr;
   bool high_pc_relative = false;
   enum dwarf_unit_type unit_type;
+  struct attribute *str_addrp = NULL;
+  size_t str_count = 0;
+  size_t str_alloc = 0;
+  bool compunit_flag = false;

   version = read_2_bytes (abfd, &info_ptr, end_ptr);
   if (version < 2 || version > 5)
@@ -4168,11 +4381,33 @@ parse_comp_unit (struct dwarf2_debug *stash,
   unit->file = file;
   unit->info_ptr_unit = info_ptr_unit;

+  if (abbrev->tag == DW_TAG_compile_unit)
+    compunit_flag = true;
+
   for (i = 0; i < abbrev->num_attrs; ++i)
     {
       info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr);
       if (info_ptr == NULL)
-	return NULL;
+	goto err_exit;
+
+      /* Identify attributes of the form strx* and addrx* which come before
+	 DW_AT_str_offsets_base and DW_AT_addr_base respectively in the CU.
+	 Store the attributes in an array and process them later.  */
+      if ((unit->dwarf_str_offset == 0 && is_strx_form (attr.form))
+	  || (unit->dwarf_addr_offset == 0 && is_addrx_form (attr.form)))
+	{
+	  if (str_count <= str_alloc)
+	    {
+	      str_alloc = 2 * str_alloc + 200;
+	      str_addrp = bfd_realloc (str_addrp,
+				       str_alloc * sizeof (*str_addrp));
+	      if (str_addrp == NULL)
+		goto err_exit;
+	    }
+	  str_addrp[str_count] = attr;
+	  str_count++;
+	  continue;
+	}

       /* Store the data if it is of an attribute we want to keep in a
 	 partial symbol table.  */
@@ -4198,7 +4433,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
 	      /* If the compilation unit DIE has a DW_AT_low_pc attribute,
 		 this is the base address to use when reading location
 		 lists or range lists.  */
-	      if (abbrev->tag == DW_TAG_compile_unit)
+	      if (compunit_flag)
 		unit->base_address = low_pc;
 	    }
 	  break;
@@ -4215,7 +4450,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
 	  if (is_int_form (&attr)
 	      && !read_rangelist (unit, &unit->arange,
 				  &unit->file->trie_root, attr.u.val))
-	    return NULL;
+	    goto err_exit;
 	  break;

 	case DW_AT_comp_dir:
@@ -4248,21 +4483,40 @@ parse_comp_unit (struct dwarf2_debug *stash,
 	    unit->lang = attr.u.val;
 	  break;

+	case DW_AT_addr_base:
+	  unit->dwarf_addr_offset = attr.u.val;
+	  break;
+
+	case DW_AT_str_offsets_base:
+	  unit->dwarf_str_offset = attr.u.val;
+	  break;
+
 	default:
 	  break;
 	}
     }
+
+  for (i = 0; i < str_count; ++i)
+    reread_attribute (unit, &str_addrp[i], &low_pc, &high_pc,
+		      &high_pc_relative, compunit_flag);
+
   if (high_pc_relative)
     high_pc += low_pc;
   if (high_pc != 0)
     {
       if (!arange_add (unit, &unit->arange, &unit->file->trie_root,
 		       low_pc, high_pc))
-	return NULL;
+	goto err_exit;
     }

   unit->first_child_die_ptr = info_ptr;
+
+  free (str_addrp);
   return unit;
+
+ err_exit:
+  free (str_addrp);
+  return NULL;
 }

 /* Return TRUE if UNIT may contain the address given by ADDR.  When
--
2.31.1