diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2024-03-12 11:35:35 +0000 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2024-03-12 11:35:35 +0000 |
| commit | 1c268991b3fe699fee16b1cbb9c6025d334c5b25 (patch) | |
| tree | d57a6a7277fd3abdfd547ee4a30ad1dcc1cc0d55 /contrib/elf2dmp/qemu_elf.c | |
| parent | 05ec974671200814fa5c1d5db710e0e4b88a40af (diff) | |
| parent | 5dd6bfd90d01e0cb27c349157208e5e4ce883846 (diff) | |
| download | focaccia-qemu-1c268991b3fe699fee16b1cbb9c6025d334c5b25.tar.gz focaccia-qemu-1c268991b3fe699fee16b1cbb9c6025d334c5b25.zip | |
Merge tag 'pull-target-arm-20240311' of https://git.linaro.org/people/pmaydell/qemu-arm into staging
target-arm queue: * contrib/elf2dmp: Improve robustness to corrupt input files * docs: update copyright date to the year 2024 * hw/arm: Deprecate various old Arm machine types # -----BEGIN PGP SIGNATURE----- # # iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmXvV4gZHHBldGVyLm1h # eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3oe5EACvvve9LOJ7UA4teEbn8zzs # O7GGsycpu3XWINX98sUi5Cuu+uexkcXsHf2Vg8GABj2fUuA+EEqPIdIWZhVcfB2t # RYGPgat/JVTwRUsl38OQ97l4joI2JeW18B20Pmh4/2tbZCJuIHoiHxxb+3aQl6Nl # gz/H137ayy+Q5utt1b6z1qXnw4etiUhk4wg2ltGVtAw63w5GZOvamTicSQ1DC3ZP # zfbIKW2WpGNjzrC1tCvaW/dNojt2blpZbsnpdPsL8cNE8puo01FnFLsUZCzOtu3m # 23uoQq0KjQZBJrU2oZMtshc+sKT/FGPADJ9B+J8jjU0EY6cV+Qo7FT4E78mxzoR0 # JbY9SLATtY7RE1Fbh3/Am+3OEyb3ZDor5nCux0CWOsuFoBk96dzD7r5MXxM2eft1 # pGmdJStYysZkdlSyx61bu6OifHOaGjnOe+lYWpaCrVy1U3cO3hbMWH2siSQygppM # 8EfjyfadzfST+nAnXfduSgWMv7Nc4ql4GIOxVnMIfGig32PIp545IvM9neh6GIp/ # 8fzw6TdoCQkHcWaazV1ibPF0ceH6JwRvLIMkWlNpr/QBSNdsx+zkdh7WZD+3S91U # XrCAA7hgf7OIvHauSD0ucSbztIiFRMROcHxIoh0ui6BermtaD6fnlei4QcsJI17o # 6XZSNSWm5/+JEsn+dcVh4g== # =UHyi # -----END PGP SIGNATURE----- # gpg: Signature made Mon 11 Mar 2024 19:12:08 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # gpg: aka "Peter Maydell <peter@archaic.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * tag 'pull-target-arm-20240311' of https://git.linaro.org/people/pmaydell/qemu-arm: docs: update copyright date to the year 2024 contrib/elf2dmp: Ensure phdrs fit in file contrib/elf2dmp: Clamp QEMU note to file size contrib/elf2dmp: Use GPtrArray MAINTAINERS: Add Akihiko Odaki as a elf2dmp reviewer contrib/elf2dmp: Use rol64() to decode contrib/elf2dmp: Use lduw_le_p() to read PDB contrib/elf2dmp: Ensure segment fits in file contrib/elf2dmp: Always destroy PA space contrib/elf2dmp: Always check for PA resolution failure contrib/elf2dmp: Fix error reporting style in main.c contrib/elf2dmp: Fix error reporting style in qemu_elf.c contrib/elf2dmp: Fix error reporting style in pdb.c contrib/elf2dmp: Fix error reporting style in download.c contrib/elf2dmp: Fix error reporting style in addrspace.c contrib/elf2dmp: Change pa_space_create() signature contrib/elf2dmp: Continue even contexts are lacking contrib/elf2dmp: Assume error by default contrib/elf2dmp: Remove unnecessary err flags hw/arm: Deprecate various old Arm machine types Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'contrib/elf2dmp/qemu_elf.c')
| -rw-r--r-- | contrib/elf2dmp/qemu_elf.c | 150 |
1 files changed, 86 insertions, 64 deletions
diff --git a/contrib/elf2dmp/qemu_elf.c b/contrib/elf2dmp/qemu_elf.c index 055e6f8792..c9bad6e82c 100644 --- a/contrib/elf2dmp/qemu_elf.c +++ b/contrib/elf2dmp/qemu_elf.c @@ -6,6 +6,7 @@ */ #include "qemu/osdep.h" +#include "qemu/host-utils.h" #include "err.h" #include "qemu_elf.h" @@ -15,36 +16,11 @@ #define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d))) #endif -#ifndef DIV_ROUND_UP -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -#endif - -#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size) \ - ((DIV_ROUND_UP((hdr_size), 4) + \ - DIV_ROUND_UP((name_size), 4) + \ - DIV_ROUND_UP((desc_size), 4)) * 4) - int is_system(QEMUCPUState *s) { return s->gs.base >> 63; } -static char *nhdr_get_name(Elf64_Nhdr *nhdr) -{ - return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4); -} - -static void *nhdr_get_desc(Elf64_Nhdr *nhdr) -{ - return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4); -} - -static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr) -{ - return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr), - nhdr->n_namesz, nhdr->n_descsz)); -} - Elf64_Phdr *elf64_getphdr(void *map) { Elf64_Ehdr *ehdr = map; @@ -60,54 +36,92 @@ Elf64_Half elf_getphdrnum(void *map) return ehdr->e_phnum; } -static int init_states(QEMU_Elf *qe) +static bool advance_note_offset(uint64_t *offsetp, uint64_t size, uint64_t end) +{ + uint64_t offset = *offsetp; + + if (uadd64_overflow(offset, size, &offset) || offset > UINT64_MAX - 3) { + return false; + } + + offset = ROUND_UP(offset, 4); + + if (offset > end) { + return false; + } + + *offsetp = offset; + + return true; +} + +static bool init_states(QEMU_Elf *qe) { Elf64_Phdr *phdr = elf64_getphdr(qe->map); - Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset); - Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz); Elf64_Nhdr *nhdr; - size_t cpu_nr = 0; + GPtrArray *states; + QEMUCPUState *state; + uint32_t state_size; + uint64_t offset; + uint64_t end_offset; + char *name; if (phdr[0].p_type != PT_NOTE) { eprintf("Failed to find PT_NOTE\n"); - return 1; + return false; } qe->has_kernel_gs_base = 1; + offset = phdr[0].p_offset; + states = g_ptr_array_new(); + + if (uadd64_overflow(offset, phdr[0].p_memsz, &end_offset) || + end_offset > qe->size) { + end_offset = qe->size; + } - for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) { - if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) { - QEMUCPUState *state = nhdr_get_desc(nhdr); + while (offset < end_offset) { + nhdr = (void *)((uint8_t *)qe->map + offset); - if (state->size < sizeof(*state)) { - eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n", - cpu_nr, state->size); + if (!advance_note_offset(&offset, sizeof(*nhdr), end_offset)) { + break; + } + + name = (char *)qe->map + offset; + + if (!advance_note_offset(&offset, nhdr->n_namesz, end_offset)) { + break; + } + + state = (void *)((uint8_t *)qe->map + offset); + + if (!advance_note_offset(&offset, nhdr->n_descsz, end_offset)) { + break; + } + + if (!strcmp(name, QEMU_NOTE_NAME) && + nhdr->n_descsz >= offsetof(QEMUCPUState, kernel_gs_base)) { + state_size = MIN(state->size, nhdr->n_descsz); + + if (state_size < sizeof(*state)) { + eprintf("CPU #%u: QEMU CPU state size %u doesn't match\n", + states->len, state_size); /* * We assume either every QEMU CPU state has KERNEL_GS_BASE or * no one has. */ qe->has_kernel_gs_base = 0; } - cpu_nr++; + g_ptr_array_add(states, state); } } - printf("%zu CPU states has been found\n", cpu_nr); - - qe->state = g_new(QEMUCPUState*, cpu_nr); - - cpu_nr = 0; - - for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) { - if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) { - qe->state[cpu_nr] = nhdr_get_desc(nhdr); - cpu_nr++; - } - } + printf("%u CPU states has been found\n", states->len); - qe->state_nr = cpu_nr; + qe->state_nr = states->len; + qe->state = (void *)g_ptr_array_free(states, FALSE); - return 0; + return true; } static void exit_states(QEMU_Elf *qe) @@ -118,6 +132,7 @@ static void exit_states(QEMU_Elf *qe) static bool check_ehdr(QEMU_Elf *qe) { Elf64_Ehdr *ehdr = qe->map; + uint64_t phendoff; if (sizeof(Elf64_Ehdr) > qe->size) { eprintf("Invalid input dump file size\n"); @@ -159,10 +174,17 @@ static bool check_ehdr(QEMU_Elf *qe) return false; } + if (umul64_overflow(ehdr->e_phnum, sizeof(Elf64_Phdr), &phendoff) || + uadd64_overflow(phendoff, ehdr->e_phoff, &phendoff) || + phendoff > qe->size) { + eprintf("phdrs do not fit in file\n"); + return false; + } + return true; } -static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename) +static bool QEMU_Elf_map(QEMU_Elf *qe, const char *filename) { #ifdef CONFIG_LINUX struct stat st; @@ -173,13 +195,13 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename) fd = open(filename, O_RDONLY, 0); if (fd == -1) { eprintf("Failed to open ELF dump file \'%s\'\n", filename); - return 1; + return false; } if (fstat(fd, &st)) { eprintf("Failed to get size of ELF dump file\n"); close(fd); - return 1; + return false; } qe->size = st.st_size; @@ -188,7 +210,7 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename) if (qe->map == MAP_FAILED) { eprintf("Failed to map ELF file\n"); close(fd); - return 1; + return false; } close(fd); @@ -201,14 +223,14 @@ static int QEMU_Elf_map(QEMU_Elf *qe, const char *filename) if (gerr) { eprintf("Failed to map ELF dump file \'%s\'\n", filename); g_error_free(gerr); - return 1; + return false; } qe->map = g_mapped_file_get_contents(qe->gmf); qe->size = g_mapped_file_get_length(qe->gmf); #endif - return 0; + return true; } static void QEMU_Elf_unmap(QEMU_Elf *qe) @@ -220,25 +242,25 @@ static void QEMU_Elf_unmap(QEMU_Elf *qe) #endif } -int QEMU_Elf_init(QEMU_Elf *qe, const char *filename) +bool QEMU_Elf_init(QEMU_Elf *qe, const char *filename) { - if (QEMU_Elf_map(qe, filename)) { - return 1; + if (!QEMU_Elf_map(qe, filename)) { + return false; } if (!check_ehdr(qe)) { eprintf("Input file has the wrong format\n"); QEMU_Elf_unmap(qe); - return 1; + return false; } - if (init_states(qe)) { + if (!init_states(qe)) { eprintf("Failed to extract QEMU CPU states\n"); QEMU_Elf_unmap(qe); - return 1; + return false; } - return 0; + return true; } void QEMU_Elf_exit(QEMU_Elf *qe) |