zdump: check size before mmap'ing

Verify that the size is large enough before doing the mmap. Otherwise
this can result in a SIGBUS signal if there is an attempt to access a
page that lies beyond the end of the mapped file (see `man 2 mmap`).

Fixes: 8fa1b5a00b ("zdump: dfi: add support to read Protected Virtualization dumps")
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 17:59:02 +00:00
committed by Jan Höppner
parent 6e42c527d7
commit f4ed0b0ec6
3 changed files with 30 additions and 16 deletions

View File

@@ -263,9 +263,9 @@ static int dfi_pv_elf_init(void)
* completion configuration data and store it in `@cpl_conf_decr`. In addition, mmap the
* configuration storage state area and use the `tweak_nonce`.
*/
if (pv_process_section_data(fh->fh, completion_sdata, storage_state_shdr->sh_offset,
storage_state_shdr->sh_size, key, &cpl_conf_decr, &dump_key,
&storage_state_data, &error) < 0) {
if (pv_process_section_data(fh->fh, fh->sb.st_size, completion_sdata,
storage_state_shdr->sh_offset, storage_state_shdr->sh_size, key,
&cpl_conf_decr, &dump_key, &storage_state_data, &error) < 0) {
ERR(_("Unable to read decryption information:" ERR_NEWLINE "%s."), error->message);
return -EINVAL;
}

View File

@@ -677,10 +677,10 @@ struct _storage_state_mmap {
gatomicrefcount ref_count;
};
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
GError **error)
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
const u64 size, GError **error)
{
size_t tweak_components_cnt, start_addr, in_page_offset, mmapped_size;
size_t tweak_components_cnt, start_addr, min_size, in_page_offset, mmapped_size;
g_autoptr(storage_state_mmap_t) ret = NULL;
int saved_errno = 0;
u8 *ptr;
@@ -706,6 +706,19 @@ storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, con
start_addr);
return NULL;
}
if (G_UNLIKELY(!g_uint64_checked_add(&min_size, start_addr, mmapped_size))) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_PAGE_END_ADDR_OVERFLOW,
_("UInt overflow detected: %s: start_addr %#lx mmap_size %#lx"),
__func__, start_addr, mmapped_size);
return NULL;
}
if (file_size < min_size) {
g_set_error(error, ZDUMP_PV_UTILS_ERROR, ZDUMP_ERR_MMAP,
_("mmap failed: file too small"));
return NULL;
}
ptr = mmap(NULL, mmapped_size, PROT_READ, MAP_POPULATE | MAP_PRIVATE, fd,
(ssize_t)start_addr);
saved_errno = errno;
@@ -814,9 +827,9 @@ static long completion_data_get_version(GBytes *cpl_data, GError **error)
return *version;
}
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
const size_t storage_state_size, GBytes *cck,
pv_dump_completion_t **completion_decr, GBytes **dump_key,
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
const u64 storage_state_offset, const size_t storage_state_size,
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
storage_state_mmap_t **storage_state, GError **error)
{
g_autoptr(pv_dump_completion_t) _completion_decr = NULL;
@@ -870,8 +883,8 @@ int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 stor
return -1;
}
_storage_state_data =
storage_state_mmap_new(fd, storage_state_offset, storage_state_size, error);
_storage_state_data = storage_state_mmap_new(fd, file_size, storage_state_offset,
storage_state_size, error);
if (!_storage_state_data)
return -1;

View File

@@ -258,9 +258,9 @@ bool pv_is_pv_elf(const Elf64_Shdr *shdrs, const unsigned int shnum, const char
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_process_section_data(const int fd, GBytes *completion_sec, const u64 storage_state_offset,
const size_t storage_state_size, GBytes *cck,
pv_dump_completion_t **completion_decr, GBytes **dump_key,
int pv_process_section_data(const int fd, const size_t file_size, GBytes *completion_sec,
const u64 storage_state_offset, const size_t storage_state_size,
GBytes *cck, pv_dump_completion_t **completion_decr, GBytes **dump_key,
storage_state_mmap_t **storage_state_data, GError **error);
/**
@@ -283,14 +283,15 @@ int pv_elf_read(const pv_elf_ctx_t *elf_ctx, const u64 start_addr, void *dst, co
/**
* storage_state_mmap_new:
* @fd: file descriptor for which to create the mapping
* @file_size: file size in bytes
* @offset: offset in fd to pv_mem_meta section
* @size: size of mapping (and pv_mem_meta section)
* @error: return value for GError
*
* Returns: new storage_state_mmap context
*/
storage_state_mmap_t *storage_state_mmap_new(const int fd, const u64 offset, const u64 size,
GError **error);
storage_state_mmap_t *storage_state_mmap_new(const int fd, const size_t file_size, const u64 offset,
const u64 size, GError **error);
/**
* storage_state_ref: