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