Fix overflow in memory ranges.
Under normal circumstances, it should be impossible to cause this
overflow, but a hostile actor could potentially force it. So fix
an overflow where the offset + length overflows.
Found from the unwinder fuzzer.
Bug: 170307390
Test: Unit tests pass.
Test: Fuzzer error case passes.
Change-Id: I116b86a566c8c0069595f3da30984d6e667e7e4f
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index b4623fa..4310496 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdint.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
@@ -368,7 +369,15 @@
}
void MemoryRanges::Insert(MemoryRange* memory) {
- maps_.emplace(memory->offset() + memory->length(), memory);
+ uint64_t last_addr;
+ if (__builtin_add_overflow(memory->offset(), memory->length(), &last_addr)) {
+ // This should never happen in the real world. However, it is possible
+ // that an offset in a mapped in segment could be crafted such that
+ // this value overflows. In that case, clamp the value to the max uint64
+ // value.
+ last_addr = UINT64_MAX;
+ }
+ maps_.emplace(last_addr, memory);
}
size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 6d8d58e..d0c7a0c 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -411,4 +411,37 @@
EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
}
+TEST_F(MapInfoCreateMemoryTest, valid_rosegment_offset_overflow) {
+ Maps maps;
+ maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
+ maps.Add(0x1000, 0x2000, 0, PROT_READ, "/only/in/memory.so", 0);
+ maps.Add(0x3000, 0x4000, 0xfffffffffffff000UL, PROT_READ | PROT_EXEC, "/only/in/memory.so", 0);
+
+ Elf64_Ehdr ehdr = {};
+ TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
+ memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
+ memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x1000 - sizeof(ehdr), 0xab);
+
+ // Set the memory in the r-x map.
+ memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
+
+ MapInfo* map_info = maps.Find(0x3000);
+ ASSERT_TRUE(map_info != nullptr);
+
+ std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
+ ASSERT_TRUE(mem.get() != nullptr);
+ EXPECT_TRUE(map_info->memory_backed_elf);
+ EXPECT_EQ(0xfffffffffffff000UL, map_info->elf_offset);
+ EXPECT_EQ(0xfffffffffffff000UL, map_info->offset);
+ EXPECT_EQ(0U, map_info->elf_start_offset);
+
+ // Verify that reading values from this memory works properly.
+ std::vector<uint8_t> buffer(0x2000);
+ size_t bytes = mem->Read(0xfffffffffffff000UL, buffer.data(), buffer.size());
+ ASSERT_EQ(0x1000UL, bytes);
+ for (size_t i = 0; i < bytes; i++) {
+ ASSERT_EQ(0x5d, buffer[i]) << "Failed at byte " << i;
+ }
+}
+
} // namespace unwindstack