From 6c23ff0168c1571d5531c72eff891ed816dd1bae Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 14 Mar 2024 17:03:51 -0700 Subject: [PATCH] readelf: fix -n for x86-64 ibt/shstk notes. I couldn't work out how to get gcc to actually produce such a thing, but /bin/dbxtool on my debian box right now has them. The big mistake here is that GNU property notes' data is always 8-byte aligned, so we needed to skip that. That lets us get rid of the existing loop termination hack to skip padding. While I'm here -- since the symptom was running off the end of the file -- I've also added a bounds check in the property dumping loop. I wish I had fuzzing infrastructure to run AFL++ against this every time it changes... In lieu of that I do wonder whether we should add `readelf -aW /bin/* > /dev/null` as a smoke test that "at least it works for all the _valid_ binaries on the system you're testing on". That would have caught this sooner. --- toys/other/readelf.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/toys/other/readelf.c b/toys/other/readelf.c index 19387360f..c1fbba60e 100644 --- a/toys/other/readelf.c +++ b/toys/other/readelf.c @@ -370,14 +370,14 @@ static void show_attributes(unsigned long offset, unsigned long size) static void show_notes(unsigned long offset, unsigned long size) { - char *note = TT.elf + offset; + char *note = TT.elf + offset, *end = TT.elf + offset + size; if (!fits("note", -1, offset, size)) return; printf(" %-20s%11s\tDescription\n", "Owner", "Data size"); - while (note < TT.elf+offset+size) { + while (note < end) { char *p = note, *desc; - unsigned namesz=elf_int(&p), descsz=elf_int(&p), type=elf_int(&p), j=0; + unsigned namesz=elf_int(&p),descsz=elf_int(&p),type=elf_int(&p),j=0; if (namesz > size || descsz > size) return error_msg("%s: bad note @%lu", TT.f, offset); @@ -392,13 +392,13 @@ static void show_notes(unsigned long offset, unsigned long size) } else if (type == 4) { printf("NT_GNU_GOLD_VERSION\t%.*s", descsz, p), j=1; } else if (type == 5) { - printf("NT_GNU_PROPERTY_TYPE_0\t"); - while (descsz-j > 8) { // Ignore 0-padding at the end. + printf("NT_GNU_PROPERTY_TYPE_0\n Properties:"); + while (descsz - j > 0) { int pr_type = elf_int(&p); int pr_size = elf_int(&p), k, pr_data; j += 8; - printf("\n Properties: "); + if (p > end) return error_msg("%s: bad property @%lu", TT.f, offset); if (pr_size != 4) { // Just hex dump anything we aren't familiar with. for (k=0;k