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 <[email protected]>
---
 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

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/20200708184200.33634-1-jwkozaczuk%40gmail.com.

Reply via email to