|
|
9ae3a8 |
From 198cca2028659addc6cce1a4fe2f14b7b84d1a22 Mon Sep 17 00:00:00 2001
|
|
|
9ae3a8 |
From: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Date: Mon, 12 Aug 2013 15:59:37 +0200
|
|
|
9ae3a8 |
Subject: dump: clamp guest-provided mapping lengths to ramblock sizes
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
RH-Author: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Message-id: <1376323180-12863-8-git-send-email-lersek@redhat.com>
|
|
|
9ae3a8 |
Patchwork-id: 53169
|
|
|
9ae3a8 |
O-Subject: [RHEL-7 qemu-kvm PATCH 07/10] dump: clamp guest-provided mapping lengths to ramblock sizes
|
|
|
9ae3a8 |
Bugzilla: 981582
|
|
|
9ae3a8 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Radim Krcmar <rkrcmar@redhat.com>
|
|
|
9ae3a8 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Even a trusted & clean-state guest can map more memory than what it was
|
|
|
9ae3a8 |
given. Since the vmcore contains RAMBlocks, mapping sizes should be
|
|
|
9ae3a8 |
clamped to RAMBlock sizes. Otherwise such oversized mappings can exceed
|
|
|
9ae3a8 |
the entire file size, and ELF parsers might refuse even the valid portion
|
|
|
9ae3a8 |
of the PT_LOAD entry.
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=981582
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
9ae3a8 |
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
|
|
|
9ae3a8 |
(cherry picked from commit 2cac260768b9d4253737417ea7501cf2950e257f)
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
diff --git a/dump.c b/dump.c
|
|
|
9ae3a8 |
index 44a1339..cbfad1c 100644
|
|
|
9ae3a8 |
--- a/dump.c
|
|
|
9ae3a8 |
+++ b/dump.c
|
|
|
9ae3a8 |
@@ -187,7 +187,8 @@ static int write_elf32_header(DumpState *s)
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
|
|
9ae3a8 |
- int phdr_index, hwaddr offset)
|
|
|
9ae3a8 |
+ int phdr_index, hwaddr offset,
|
|
|
9ae3a8 |
+ hwaddr filesz)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
Elf64_Phdr phdr;
|
|
|
9ae3a8 |
int ret;
|
|
|
9ae3a8 |
@@ -197,15 +198,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
|
|
9ae3a8 |
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
|
|
|
9ae3a8 |
phdr.p_offset = cpu_convert_to_target64(offset, endian);
|
|
|
9ae3a8 |
phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian);
|
|
|
9ae3a8 |
- if (offset == -1) {
|
|
|
9ae3a8 |
- /* When the memory is not stored into vmcore, offset will be -1 */
|
|
|
9ae3a8 |
- phdr.p_filesz = 0;
|
|
|
9ae3a8 |
- } else {
|
|
|
9ae3a8 |
- phdr.p_filesz = cpu_convert_to_target64(memory_mapping->length, endian);
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
+ phdr.p_filesz = cpu_convert_to_target64(filesz, endian);
|
|
|
9ae3a8 |
phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian);
|
|
|
9ae3a8 |
phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ assert(memory_mapping->length >= filesz);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
|
|
9ae3a8 |
if (ret < 0) {
|
|
|
9ae3a8 |
dump_error(s, "dump: failed to write program header table.\n");
|
|
|
9ae3a8 |
@@ -216,7 +214,8 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
|
|
9ae3a8 |
- int phdr_index, hwaddr offset)
|
|
|
9ae3a8 |
+ int phdr_index, hwaddr offset,
|
|
|
9ae3a8 |
+ hwaddr filesz)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
Elf32_Phdr phdr;
|
|
|
9ae3a8 |
int ret;
|
|
|
9ae3a8 |
@@ -226,15 +225,12 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
|
|
9ae3a8 |
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
|
|
|
9ae3a8 |
phdr.p_offset = cpu_convert_to_target32(offset, endian);
|
|
|
9ae3a8 |
phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian);
|
|
|
9ae3a8 |
- if (offset == -1) {
|
|
|
9ae3a8 |
- /* When the memory is not stored into vmcore, offset will be -1 */
|
|
|
9ae3a8 |
- phdr.p_filesz = 0;
|
|
|
9ae3a8 |
- } else {
|
|
|
9ae3a8 |
- phdr.p_filesz = cpu_convert_to_target32(memory_mapping->length, endian);
|
|
|
9ae3a8 |
- }
|
|
|
9ae3a8 |
+ phdr.p_filesz = cpu_convert_to_target32(filesz, endian);
|
|
|
9ae3a8 |
phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian);
|
|
|
9ae3a8 |
phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian);
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ assert(memory_mapping->length >= filesz);
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
|
|
9ae3a8 |
if (ret < 0) {
|
|
|
9ae3a8 |
dump_error(s, "dump: failed to write program header table.\n");
|
|
|
9ae3a8 |
@@ -422,17 +418,24 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
|
|
|
9ae3a8 |
return 0;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
-/* get the memory's offset in the vmcore */
|
|
|
9ae3a8 |
-static hwaddr get_offset(hwaddr phys_addr,
|
|
|
9ae3a8 |
- DumpState *s)
|
|
|
9ae3a8 |
+/* get the memory's offset and size in the vmcore */
|
|
|
9ae3a8 |
+static void get_offset_range(hwaddr phys_addr,
|
|
|
9ae3a8 |
+ ram_addr_t mapping_length,
|
|
|
9ae3a8 |
+ DumpState *s,
|
|
|
9ae3a8 |
+ hwaddr *p_offset,
|
|
|
9ae3a8 |
+ hwaddr *p_filesz)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
RAMBlock *block;
|
|
|
9ae3a8 |
hwaddr offset = s->memory_offset;
|
|
|
9ae3a8 |
int64_t size_in_block, start;
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
+ /* When the memory is not stored into vmcore, offset will be -1 */
|
|
|
9ae3a8 |
+ *p_offset = -1;
|
|
|
9ae3a8 |
+ *p_filesz = 0;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
if (s->has_filter) {
|
|
|
9ae3a8 |
if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
|
|
|
9ae3a8 |
- return -1;
|
|
|
9ae3a8 |
+ return;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
@@ -461,18 +464,26 @@ static hwaddr get_offset(hwaddr phys_addr,
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (phys_addr >= start && phys_addr < start + size_in_block) {
|
|
|
9ae3a8 |
- return phys_addr - start + offset;
|
|
|
9ae3a8 |
+ *p_offset = phys_addr - start + offset;
|
|
|
9ae3a8 |
+
|
|
|
9ae3a8 |
+ /* The offset range mapped from the vmcore file must not spill over
|
|
|
9ae3a8 |
+ * the RAMBlock, clamp it. The rest of the mapping will be
|
|
|
9ae3a8 |
+ * zero-filled in memory at load time; see
|
|
|
9ae3a8 |
+ * <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>.
|
|
|
9ae3a8 |
+ */
|
|
|
9ae3a8 |
+ *p_filesz = phys_addr + mapping_length <= start + size_in_block ?
|
|
|
9ae3a8 |
+ mapping_length :
|
|
|
9ae3a8 |
+ size_in_block - (phys_addr - start);
|
|
|
9ae3a8 |
+ return;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
offset += size_in_block;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
-
|
|
|
9ae3a8 |
- return -1;
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
static int write_elf_loads(DumpState *s)
|
|
|
9ae3a8 |
{
|
|
|
9ae3a8 |
- hwaddr offset;
|
|
|
9ae3a8 |
+ hwaddr offset, filesz;
|
|
|
9ae3a8 |
MemoryMapping *memory_mapping;
|
|
|
9ae3a8 |
uint32_t phdr_index = 1;
|
|
|
9ae3a8 |
int ret;
|
|
|
9ae3a8 |
@@ -485,11 +496,15 @@ static int write_elf_loads(DumpState *s)
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
|
|
|
9ae3a8 |
- offset = get_offset(memory_mapping->phys_addr, s);
|
|
|
9ae3a8 |
+ get_offset_range(memory_mapping->phys_addr,
|
|
|
9ae3a8 |
+ memory_mapping->length,
|
|
|
9ae3a8 |
+ s, &offset, &filesz);
|
|
|
9ae3a8 |
if (s->dump_info.d_class == ELFCLASS64) {
|
|
|
9ae3a8 |
- ret = write_elf64_load(s, memory_mapping, phdr_index++, offset);
|
|
|
9ae3a8 |
+ ret = write_elf64_load(s, memory_mapping, phdr_index++, offset,
|
|
|
9ae3a8 |
+ filesz);
|
|
|
9ae3a8 |
} else {
|
|
|
9ae3a8 |
- ret = write_elf32_load(s, memory_mapping, phdr_index++, offset);
|
|
|
9ae3a8 |
+ ret = write_elf32_load(s, memory_mapping, phdr_index++, offset,
|
|
|
9ae3a8 |
+ filesz);
|
|
|
9ae3a8 |
}
|
|
|
9ae3a8 |
|
|
|
9ae3a8 |
if (ret < 0) {
|