summaryrefslogtreecommitdiffstats
path: root/libdwfl
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2021-12-19 21:11:13 +0100
committerMark Wielaard <mark@klomp.org>2021-12-19 21:11:13 +0100
commitd844d1575522b5ad9ada0aa3c26105230a1c1884 (patch)
tree68d9ed80d85b87f8e94b720673244ec2abf7420f /libdwfl
parentlibdwfl: Make sure dyn_filesz has a sane size (diff)
downloadelfutils-d844d1575522b5ad9ada0aa3c26105230a1c1884.tar.gz
elfutils-d844d1575522b5ad9ada0aa3c26105230a1c1884.tar.bz2
elfutils-d844d1575522b5ad9ada0aa3c26105230a1c1884.tar.xz
libdwfl: Rewrite GElf_Nhdr reading in dwfl_segment_report_module
Make sure that the notes filesz is not too big. Rewrite reading of the notes to check for overflow at every step. Also limit the size of the buildid bytes. Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdwfl')
-rw-r--r--libdwfl/ChangeLog5
-rw-r--r--libdwfl/dwfl_segment_report_module.c79
2 files changed, 49 insertions, 35 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 1f83576d..18ffc347 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
12021-12-19 Mark Wielaard <mark@klomp.org>
2
3 * dwfl_segment_report_module.c (dwfl_segment_report_module): Check
4 notes filesz. Rewrite reading of GElf_Nhdr.
5
12021-12-08 Mark Wielaard <mark@klomp.org> 62021-12-08 Mark Wielaard <mark@klomp.org>
2 7
3 * dwfl_segment_report_module.c (dwfl_segment_report_module): Make sure 8 * dwfl_segment_report_module.c (dwfl_segment_report_module): Make sure
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 78c70795..a6d6be85 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -520,6 +520,9 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
520 if (data_size != 0) 520 if (data_size != 0)
521 filesz = data_size; 521 filesz = data_size;
522 522
523 if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
524 continue;
525
523 assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); 526 assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
524 527
525 void *notes; 528 void *notes;
@@ -532,6 +535,8 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
532 { 535 {
533 const unsigned int xencoding = ehdr.e32.e_ident[EI_DATA]; 536 const unsigned int xencoding = ehdr.e32.e_ident[EI_DATA];
534 537
538 if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr))
539 continue;
535 notes = malloc (filesz); 540 notes = malloc (filesz);
536 if (unlikely (notes == NULL)) 541 if (unlikely (notes == NULL))
537 continue; /* Next header */ 542 continue; /* Next header */
@@ -552,44 +557,48 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
552 557
553 const GElf_Nhdr *nh = notes; 558 const GElf_Nhdr *nh = notes;
554 size_t len = 0; 559 size_t len = 0;
555 size_t last_len; 560 while (filesz - len > sizeof (*nh))
556 while (filesz > len + sizeof (*nh))
557 { 561 {
558 const void *note_name; 562 len += sizeof (*nh);
559 const void *note_desc; 563
560 last_len = len; 564 size_t namesz = nh->n_namesz;
561 565 namesz = align == 8 ? NOTE_ALIGN8 (namesz) : NOTE_ALIGN4 (namesz);
562 len += sizeof (*nh); 566 if (namesz > filesz - len || len + namesz < namesz)
563 note_name = notes + len; 567 break;
564 568
565 len += nh->n_namesz; 569 void *note_name = notes + len;
566 len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); 570 len += namesz;
567 note_desc = notes + len; 571
568 572 size_t descsz = nh->n_descsz;
569 if (unlikely (filesz < len + nh->n_descsz 573 descsz = align == 8 ? NOTE_ALIGN8 (descsz) : NOTE_ALIGN4 (descsz);
570 || len <= last_len 574 if (descsz > filesz - len || len + descsz < descsz)
571 || len + nh->n_descsz < last_len)) 575 break;
572 break; 576
573 577 void *note_desc = notes + len;
574 if (nh->n_type == NT_GNU_BUILD_ID 578 len += descsz;
575 && nh->n_descsz > 0 579
576 && nh->n_namesz == sizeof "GNU" 580 /* We don't handle very short or really large build-ids. We need at
577 && !memcmp (note_name, "GNU", sizeof "GNU")) 581 at least 3 and allow for up to 64 (normally ids are 20 long). */
578 { 582#define MIN_BUILD_ID_BYTES 3
579 build_id.vaddr = (note_desc 583#define MAX_BUILD_ID_BYTES 64
584 if (nh->n_type == NT_GNU_BUILD_ID
585 && nh->n_descsz >= MIN_BUILD_ID_BYTES
586 && nh->n_descsz <= MAX_BUILD_ID_BYTES
587 && nh->n_namesz == sizeof "GNU"
588 && !memcmp (note_name, "GNU", sizeof "GNU"))
589 {
590 build_id.vaddr = (note_desc
580 - (const void *) notes 591 - (const void *) notes
581 + note_vaddr); 592 + note_vaddr);
582 build_id.len = nh->n_descsz; 593 build_id.len = nh->n_descsz;
583 build_id.memory = malloc (build_id.len); 594 build_id.memory = malloc (build_id.len);
584 if (likely (build_id.memory != NULL)) 595 if (likely (build_id.memory != NULL))
585 memcpy (build_id.memory, note_desc, build_id.len); 596 memcpy (build_id.memory, note_desc, build_id.len);
586 break; 597 break;
587 } 598 }
588 599
589 len += nh->n_descsz; 600 nh = (void *) notes + len;
590 len = align == 8 ? NOTE_ALIGN8 (len) : NOTE_ALIGN4 (len); 601 }
591 nh = (void *) notes + len;
592 }
593 602
594 if (notes != data) 603 if (notes != data)
595 free (notes); 604 free (notes);