|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 3/3] x86/mkelf32: re-write ELF notes
64-bit ELF notes generally (sadly with exceptions) are padded to 8-byte
boundaries, whereas 32-bit ELF notes are padded to 4-byte ones. The excess
padding makes it impossible for tools like objdump to properly deal with
these notes.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
Is there a need to further generalize or tighten anything?
---
v2: New.
--- a/xen/arch/x86/boot/mkelf32.c
+++ b/xen/arch/x86/boot/mkelf32.c
@@ -8,6 +8,7 @@
*/
#include <errno.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -256,6 +257,8 @@ int main(int argc, char **argv)
char buffer[1024] = {};
int bytes, todo, i = 1;
int num_phdrs = 1;
+ void *notes32 = NULL;
+ unsigned int note_sz32 = 0;
Elf32_Ehdr in32_ehdr;
@@ -359,8 +362,6 @@ int main(int argc, char **argv)
do_read(infd, &in64_phdr, sizeof(in64_phdr));
endianadjust_phdr64(&in64_phdr);
- (void)lseek(infd, offset, SEEK_SET);
-
note_sz = in64_phdr.p_memsz;
note_base = in64_phdr.p_vaddr - note_base;
@@ -373,6 +374,84 @@ int main(int argc, char **argv)
offset, offset + dat_siz);
return 1;
}
+
+ note_sz32 = note_sz;
+
+ /* Convert 8-byte padded notes to 4-byte padded ones. */
+ if ( in64_phdr.p_align == 8 )
+ {
+ Elf64_Note *notes64 = malloc(note_sz);
+
+ notes32 = malloc(note_sz);
+ if ( notes64 && notes32 )
+ {
+ unsigned int left = note_sz;
+ void *ptr32 = notes32;
+
+ lseek(infd, in64_phdr.p_offset, SEEK_SET);
+ do_read(infd, notes64, note_sz);
+
+ for ( bool start = true; left > sizeof(*notes64); )
+ {
+ unsigned int size;
+
+ if ( start && !notes64->namesz )
+ {
+ /* Padding. */
+ notes64 = (void *)(¬es64->namesz + 1);
+ left -= sizeof(notes64->namesz);
+ start = false;
+ continue;
+ }
+
+ /*
+ * The note descriptor may start at either the next 4- or
+ * 8-byte boundary. See e.g.
+ * https://sourceware.org/bugzilla/show_bug.cgi?id=33259.
+ * For the notes we have actively in use at the time of
+ * writing, rounding to the next 4-byte boundary is enough
+ * (and in fact is already excessive: "GNU" and "Xen" as
+ * note names both satisfy the 8-byte alignment without
+ * extra effort).
+ *
+ * The similar ->descsz aspect is covered by the check
+ * above.
+ */
+ size = ROUNDUP(sizeof(*notes64) + notes64->namesz, 4) +
+ ROUNDUP(notes64->descsz, 4);
+ if ( left < size )
+ {
+ fprintf(stderr,
+ "Warning: ELF note overrunning segment (%u
bytes left, %u bytes claimed)\n",
+ left, size);
+ left = 0;
+ break;
+ }
+
+ /* Leverage Elf{32,64}_Note actually having same layout. */
+ memcpy(ptr32, notes64, size);
+
+ notes64 = (void *)notes64 + size;
+ ptr32 += size;
+ left -= size;
+ start = true;
+ }
+
+ if ( left )
+ fprintf(stderr, "Warning: %u trailing bytes of ELF
notes\n",
+ left);
+
+ note_sz32 = ptr32 - notes32;
+ memset(ptr32, 0, note_sz - note_sz32);
+ }
+ else
+ fprintf(stderr,
+ "Warning: Not enough memory to re-write %"PRIu32"
bytes of ELF notes\n",
+ note_sz);
+ }
+
+ (void)lseek(infd, offset, SEEK_SET);
+
/* Gets us the absolute offset within the .text section. */
offset = in64_phdr.p_offset - offset;
}
@@ -405,8 +484,8 @@ int main(int argc, char **argv)
/* Fill out the PT_NOTE program header. */
note_phdr.p_vaddr = note_base;
note_phdr.p_paddr = note_base;
- note_phdr.p_filesz = note_sz;
- note_phdr.p_memsz = note_sz;
+ note_phdr.p_filesz = note_sz32;
+ note_phdr.p_memsz = note_sz32;
note_phdr.p_offset = RAW_OFFSET + offset;
/* Tack on the .note\0 */
@@ -415,7 +494,7 @@ int main(int argc, char **argv)
out_shdr[2].sh_offset += sizeof(out_shdr_note);
/* Fill out the .note section. */
- out_shdr_note.sh_size = note_sz;
+ out_shdr_note.sh_size = note_sz32;
out_shdr_note.sh_addr = note_base;
out_shdr_note.sh_offset = RAW_OFFSET + offset;
}
@@ -483,6 +562,17 @@ int main(int argc, char **argv)
do_write(outfd, buffer, 4 - (bytes & 3));
}
+ if ( notes32 )
+ {
+ lseek(outfd, note_phdr.p_offset, SEEK_SET);
+
+ /*
+ * While we use note_sz32 above, overwrite the full original contents,
+ * to not leave confusing rubbish there.
+ */
+ do_write(outfd, notes32, note_sz);
+ }
+
close(infd);
close(outfd);
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |