In order to properly calculate and then map an elf object
in virtual memory, the set_base() method needs to identify the lowest
and the highest PT_LOAD header in terms of the p_vaddr value.
Unfortunately, there seems to be a bug in how it is implemented now
and in some cases, when for example there are multiple PT_LOAD and non-PT_LOAD
headers sharing the same p_vaddr value, it ends up using wrong
header and then overwriting other segments data.
This patch fixes it by separating filtering of PT_LOAD headers
and indentifying the lowest and highest ones.
Signed-off-by: Waldemar Kozaczuk <
jwkoz...@gmail.com>
---
core/elf.cc | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/core/elf.cc b/core/elf.cc
index ffb16004..0d33f63d 100644
--- a/core/elf.cc
+++ b/core/elf.cc
@@ -347,14 +347,19 @@ static bool intersects_with_kernel(Elf64_Addr elf_addr)
void object::set_base(void* base)
{
- auto p = std::min_element(_phdrs.begin(), _phdrs.end(),
- [](Elf64_Phdr a, Elf64_Phdr b)
- { return a.p_type == PT_LOAD
- && a.p_vaddr < b.p_vaddr; });
- auto q = std::min_element(_phdrs.begin(), _phdrs.end(),
- [](Elf64_Phdr a, Elf64_Phdr b)
- { return a.p_type == PT_LOAD
- && a.p_vaddr > b.p_vaddr; });
+ std::vector<const Elf64_Phdr*> pt_load_headers;
+ for (auto& p : _phdrs) {
+ if (p.p_type == PT_LOAD) {
+ pt_load_headers.push_back(&p);
+ }
+ }
+
+ auto p = *std::min_element(pt_load_headers.begin(), pt_load_headers.end(),
+ [](const Elf64_Phdr* a, const Elf64_Phdr* b)
+ { return a->p_vaddr < b->p_vaddr; });
+ auto q = *std::max_element(pt_load_headers.begin(), pt_load_headers.end(),
+ [](const Elf64_Phdr* a, const Elf64_Phdr* b)
+ { return a->p_vaddr < b->p_vaddr; });
if (!is_core() && is_non_pie_executable()) {
// Verify non-PIE executable does not collide with the kernel
--
2.25.1