zdump: check provided sizes for reasonableness

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 <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Marc Hartmayer
2022-11-09 19:27:48 +00:00
committed by Jan Höppner
parent f4ed0b0ec6
commit 1911cba130
4 changed files with 38 additions and 8 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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)