提交 2cac2607 编写于 作者: L Laszlo Ersek 提交者: Luiz Capitulino

dump: clamp guest-provided mapping lengths to ramblock sizes

Even a trusted & clean-state guest can map more memory than what it was
given. Since the vmcore contains RAMBlocks, mapping sizes should be
clamped to RAMBlock sizes. Otherwise such oversized mappings can exceed
the entire file size, and ELF parsers might refuse even the valid portion
of the PT_LOAD entry.

Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=981582Signed-off-by: NLaszlo Ersek <lersek@redhat.com>
Signed-off-by: NLuiz Capitulino <lcapitulino@redhat.com>
上级 6fdf98f2
...@@ -187,7 +187,8 @@ static int write_elf32_header(DumpState *s) ...@@ -187,7 +187,8 @@ static int write_elf32_header(DumpState *s)
} }
static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset) int phdr_index, hwaddr offset,
hwaddr filesz)
{ {
Elf64_Phdr phdr; Elf64_Phdr phdr;
int ret; int ret;
...@@ -197,15 +198,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, ...@@ -197,15 +198,12 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
phdr.p_offset = cpu_convert_to_target64(offset, endian); phdr.p_offset = cpu_convert_to_target64(offset, endian);
phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian); phdr.p_paddr = cpu_convert_to_target64(memory_mapping->phys_addr, endian);
if (offset == -1) { phdr.p_filesz = cpu_convert_to_target64(filesz, endian);
/* When the memory is not stored into vmcore, offset will be -1 */
phdr.p_filesz = 0;
} else {
phdr.p_filesz = cpu_convert_to_target64(memory_mapping->length, endian);
}
phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian); phdr.p_memsz = cpu_convert_to_target64(memory_mapping->length, endian);
phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian); phdr.p_vaddr = cpu_convert_to_target64(memory_mapping->virt_addr, endian);
assert(memory_mapping->length >= filesz);
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s); ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
if (ret < 0) { if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n"); dump_error(s, "dump: failed to write program header table.\n");
...@@ -216,7 +214,8 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping, ...@@ -216,7 +214,8 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
} }
static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
int phdr_index, hwaddr offset) int phdr_index, hwaddr offset,
hwaddr filesz)
{ {
Elf32_Phdr phdr; Elf32_Phdr phdr;
int ret; int ret;
...@@ -226,15 +225,12 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping, ...@@ -226,15 +225,12 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian); phdr.p_type = cpu_convert_to_target32(PT_LOAD, endian);
phdr.p_offset = cpu_convert_to_target32(offset, endian); phdr.p_offset = cpu_convert_to_target32(offset, endian);
phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian); phdr.p_paddr = cpu_convert_to_target32(memory_mapping->phys_addr, endian);
if (offset == -1) { phdr.p_filesz = cpu_convert_to_target32(filesz, endian);
/* When the memory is not stored into vmcore, offset will be -1 */
phdr.p_filesz = 0;
} else {
phdr.p_filesz = cpu_convert_to_target32(memory_mapping->length, endian);
}
phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian); phdr.p_memsz = cpu_convert_to_target32(memory_mapping->length, endian);
phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian); phdr.p_vaddr = cpu_convert_to_target32(memory_mapping->virt_addr, endian);
assert(memory_mapping->length >= filesz);
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s); ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
if (ret < 0) { if (ret < 0) {
dump_error(s, "dump: failed to write program header table.\n"); dump_error(s, "dump: failed to write program header table.\n");
...@@ -418,17 +414,24 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start, ...@@ -418,17 +414,24 @@ static int write_memory(DumpState *s, RAMBlock *block, ram_addr_t start,
return 0; return 0;
} }
/* get the memory's offset in the vmcore */ /* get the memory's offset and size in the vmcore */
static hwaddr get_offset(hwaddr phys_addr, static void get_offset_range(hwaddr phys_addr,
DumpState *s) ram_addr_t mapping_length,
DumpState *s,
hwaddr *p_offset,
hwaddr *p_filesz)
{ {
RAMBlock *block; RAMBlock *block;
hwaddr offset = s->memory_offset; hwaddr offset = s->memory_offset;
int64_t size_in_block, start; int64_t size_in_block, start;
/* When the memory is not stored into vmcore, offset will be -1 */
*p_offset = -1;
*p_filesz = 0;
if (s->has_filter) { if (s->has_filter) {
if (phys_addr < s->begin || phys_addr >= s->begin + s->length) { if (phys_addr < s->begin || phys_addr >= s->begin + s->length) {
return -1; return;
} }
} }
...@@ -457,18 +460,26 @@ static hwaddr get_offset(hwaddr phys_addr, ...@@ -457,18 +460,26 @@ static hwaddr get_offset(hwaddr phys_addr,
} }
if (phys_addr >= start && phys_addr < start + size_in_block) { if (phys_addr >= start && phys_addr < start + size_in_block) {
return phys_addr - start + offset; *p_offset = phys_addr - start + offset;
/* The offset range mapped from the vmcore file must not spill over
* the RAMBlock, clamp it. The rest of the mapping will be
* zero-filled in memory at load time; see
* <http://refspecs.linuxbase.org/elf/gabi4+/ch5.pheader.html>.
*/
*p_filesz = phys_addr + mapping_length <= start + size_in_block ?
mapping_length :
size_in_block - (phys_addr - start);
return;
} }
offset += size_in_block; offset += size_in_block;
} }
return -1;
} }
static int write_elf_loads(DumpState *s) static int write_elf_loads(DumpState *s)
{ {
hwaddr offset; hwaddr offset, filesz;
MemoryMapping *memory_mapping; MemoryMapping *memory_mapping;
uint32_t phdr_index = 1; uint32_t phdr_index = 1;
int ret; int ret;
...@@ -481,11 +492,15 @@ static int write_elf_loads(DumpState *s) ...@@ -481,11 +492,15 @@ static int write_elf_loads(DumpState *s)
} }
QTAILQ_FOREACH(memory_mapping, &s->list.head, next) { QTAILQ_FOREACH(memory_mapping, &s->list.head, next) {
offset = get_offset(memory_mapping->phys_addr, s); get_offset_range(memory_mapping->phys_addr,
memory_mapping->length,
s, &offset, &filesz);
if (s->dump_info.d_class == ELFCLASS64) { if (s->dump_info.d_class == ELFCLASS64) {
ret = write_elf64_load(s, memory_mapping, phdr_index++, offset); ret = write_elf64_load(s, memory_mapping, phdr_index++, offset,
filesz);
} else { } else {
ret = write_elf32_load(s, memory_mapping, phdr_index++, offset); ret = write_elf32_load(s, memory_mapping, phdr_index++, offset,
filesz);
} }
if (ret < 0) { if (ret < 0) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册