From 1911cba130d41523abf04a98c75b3817c7e8ea88 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Wed, 9 Nov 2022 19:27:48 +0000 Subject: [PATCH] zdump: check provided sizes for reasonableness MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check the dump provided sizes for reasonableness. This avoids that a corrupted dump leads to allocation of large buffers on the heap. Signed-off-by: Marc Hartmayer Reviewed-by: Steffen Eiden Signed-off-by: Jan Höppner --- zdump/df_elf.c | 13 +++++++++++-- zdump/df_elf.h | 6 ++++-- zdump/dfi_pv_elf.c | 17 +++++++++++++---- zdump/pv_defs.h | 10 ++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/zdump/df_elf.c b/zdump/df_elf.c index 69c51e3c..95206f52 100644 --- a/zdump/df_elf.c +++ b/zdump/df_elf.c @@ -121,7 +121,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, unsig return shdrs; } -unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size) +unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size, + const size_t max_size) { const size_t sh_size = shdr->sh_size; unsigned char *ret; @@ -133,6 +134,9 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s if (shdr->sh_offset > OFF_T_MAX) ERR_EXIT("Unsupported offset"); + if (sh_size > max_size) + ERR_EXIT("Unsupported section size: %#lx > %#lx", sh_size, max_size); + ret = util_malloc(sh_size); zg_seek(fh, (off_t)shdr->sh_offset, ZG_CHECK); zg_read(fh, ret, sh_size, ZG_CHECK); @@ -141,7 +145,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s } char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs, - const unsigned int shnum, size_t *shstrtab_size) + const unsigned int shnum, size_t *shstrtab_size, + const size_t max_shstrtab_size) { const size_t shstrndx = ehdr->e_shstrndx; Elf64_Xword tmp_shstrtab_size; @@ -166,6 +171,10 @@ char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const El ERR_EXIT("Unsupported offset"); tmp_shstrtab_size = shdrs[shstrndx].sh_size; + if (tmp_shstrtab_size > max_shstrtab_size) + ERR_EXIT("Unsupported shstrtab size: %#lx > %#lx", tmp_shstrtab_size, + max_shstrtab_size); + shstrtab = util_malloc(tmp_shstrtab_size); zg_seek(fh, (off_t)shstrndx_off, ZG_CHECK); zg_read(fh, shstrtab, tmp_shstrtab_size, ZG_CHECK); diff --git a/zdump/df_elf.h b/zdump/df_elf.h index c3e1fc93..0e3594e3 100644 --- a/zdump/df_elf.h +++ b/zdump/df_elf.h @@ -195,7 +195,8 @@ Elf64_Shdr *read_elf_shdrs(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, * * To read the section content the offset of @fh is changed. */ -unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size); +unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *shdr, size_t *size, + const size_t max_size); /* * Read ELF section header string table @@ -203,7 +204,8 @@ unsigned char *read_elf_section_data(const struct zg_fh *fh, const Elf64_Shdr *s * To read the section header string table the offset of @fh is changed. */ char *read_elf_shstrtab(const struct zg_fh *fh, const Elf64_Ehdr *ehdr, const Elf64_Shdr *shdrs, - const unsigned int shnum, size_t *shstrtab_size); + const unsigned int shnum, size_t *shstrtab_size, + const size_t max_shstrtab_size); /* * Find ELF section header by section name diff --git a/zdump/dfi_pv_elf.c b/zdump/dfi_pv_elf.c index b445aa14..ed2b9ffa 100644 --- a/zdump/dfi_pv_elf.c +++ b/zdump/dfi_pv_elf.c @@ -46,17 +46,19 @@ WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Elf64_Ehdr, free); * read_elf_section_data_as_gbytes: * @fh: (not nullable): open input file * @shdr: (not nullable): section header of the section to read + * @max_size: maximum section data size in bytes * * Try to read section data and return it as #GBytes. * * Returns: #GBytes on success, %NULL if an error occurred */ -static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr) +static GBytes *read_elf_section_data_as_gbytes(const struct zg_fh *fh, const Elf64_Shdr *shdr, + const size_t max_size) { unsigned char *data; size_t size; - data = read_elf_section_data(fh, shdr, &size); + data = read_elf_section_data(fh, shdr, &size, max_size); if (!data) return NULL; return g_bytes_new_with_free_func(data, size, free, data); @@ -106,6 +108,12 @@ static dfi_cpu_t *nt_s390_pv_cpu_data_read(const struct zg_fh *fh, const Elf64_N g_assert(dump_key); + if (note_descsz > PV_MAX_NT_S390_PV_CPU_DATA_SIZE) { + g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE, + _("Unable to read confidential CPU data. Dump probably corrupted.")); + return NULL; + } + note_data = g_malloc(note_descsz); if (nt_read(fh, note_hdr, note_data, note_descsz) < 0) { g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_CORRUPTED_NOTE, @@ -224,7 +232,7 @@ static int dfi_pv_elf_init(void) if (!shdrs) return -ENODEV; - shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size); + shstrtab = read_elf_shstrtab(fh, ehdr, shdrs, shnum, &shstrtab_size, PV_MAX_SHSTRTAB_SIZE); if (!shstrtab) return -ENODEV; @@ -255,7 +263,8 @@ static int dfi_pv_elf_init(void) return -EINVAL; /* Read the PV completion configuration section data */ - completion_sdata = read_elf_section_data_as_gbytes(fh, completion_shdr); + completion_sdata = + read_elf_section_data_as_gbytes(fh, completion_shdr, PV_MAX_COMPL_DATA_SIZE); if (!completion_sdata) return -EINVAL; diff --git a/zdump/pv_defs.h b/zdump/pv_defs.h index 55c5f065..c5da2add 100644 --- a/zdump/pv_defs.h +++ b/zdump/pv_defs.h @@ -20,6 +20,16 @@ #define PV_ELF_SECTION_NAME_COMPL "pv_compl" #define PV_ELF_SECTION_NAME_TWEAKS "pv_mem_meta" +/* Maximum size (in bytes) of completion section data */ +#define PV_MAX_COMPL_DATA_SIZE ROUNDUP(sizeof(pv_dump_completion_data_v1_t), PAGE_SIZE) +/* Maximum size (in bytes) of section header string table */ +#define PV_MAX_SHSTRTAB_SIZE \ + ROUNDUP(sizeof(PV_ELF_SECTION_NAME_COMPL) + sizeof(PV_ELF_SECTION_NAME_TWEAKS) + \ + sizeof(".shstrtab"), \ + PAGE_SIZE) +/* Maximum size of NT_S390_PV_CPU_DATA */ +#define PV_MAX_NT_S390_PV_CPU_DATA_SIZE ROUNDUP(sizeof(pv_cpu_dump_v1_t), PAGE_SIZE) + #define PV_COMPL_DATA_VERSION_1 ((uint32_t)1) #define PV_SEC_CPU_DATA_VERSION_1 ((uint32_t)1)