Verify that the elf matches the expected arch.

To avoid a case where a malicious app might try and trick the system to
create an elf and register object that mismatches, always verify that they
are the same arch.

Test: Ran unit tests.
Change-Id: I66978e9e02f8e4f396856912e7019528ead4838e
This commit is contained in:
Christopher Ferris 2018-10-23 17:42:41 -07:00
parent 2a8460721c
commit 4568f4bc0f
19 changed files with 164 additions and 106 deletions

View file

@ -49,6 +49,7 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
regs, stack_map->process_memory());
unwinder.SetResolveNames(stack_map->ResolveNames());
stack_map->SetArch(regs->Arch());
if (stack_map->GetJitDebug() != nullptr) {
unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
}

View file

@ -25,6 +25,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Regs.h>
#include "UnwindStackMap.h"
@ -106,7 +107,17 @@ std::string UnwindStackMap::GetFunctionName(uint64_t pc, uint64_t* offset) {
return "";
}
unwindstack::Elf* elf = map_info->GetElf(process_memory());
if (arch_ == unwindstack::ARCH_UNKNOWN) {
if (pid_ == getpid()) {
arch_ = unwindstack::Regs::CurrentArch();
} else {
// Create a remote regs, to figure out the architecture.
std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid_));
arch_ = regs->Arch();
}
}
unwindstack::Elf* elf = map_info->GetElf(process_memory(), arch_);
std::string name;
uint64_t func_offset;

View file

@ -30,6 +30,7 @@
#if !defined(NO_LIBDEXFILE_SUPPORT)
#include <unwindstack/DexFiles.h>
#endif
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@ -58,6 +59,8 @@ class UnwindStackMap : public BacktraceMap {
unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
#endif
void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; }
protected:
uint64_t GetLoadBias(size_t index) override;
@ -67,6 +70,8 @@ class UnwindStackMap : public BacktraceMap {
#if !defined(NO_LIBDEXFILE_SUPPORT)
std::unique_ptr<unwindstack::DexFiles> dex_files_;
#endif
unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
};
class UnwindStackOfflineMap : public UnwindStackMap {

View file

@ -54,8 +54,8 @@ DexFiles::~DexFiles() {
}
}
void DexFiles::SetArch(ArchEnum arch) {
switch (arch) {
void DexFiles::ProcessArch() {
switch (arch()) {
case ARCH_ARM:
case ARCH_MIPS:
case ARCH_X86:

View file

@ -88,6 +88,11 @@ void Elf::InitGnuDebugdata() {
}
}
void Elf::Invalidate() {
interface_.reset(nullptr);
valid_ = false;
}
bool Elf::GetSoname(std::string* name) {
std::lock_guard<std::mutex> guard(lock_);
return valid_ && interface_->GetSoname(name);

View file

@ -31,6 +31,13 @@ Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
: memory_(memory), search_libs_(search_libs) {}
void Global::SetArch(ArchEnum arch) {
if (arch_ == ARCH_UNKNOWN) {
arch_ = arch;
ProcessArch();
}
}
uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
if (!search_libs_.empty()) {
bool found = false;
@ -46,7 +53,7 @@ uint64_t Global::GetVariableOffset(MapInfo* info, const std::string& variable) {
}
}
Elf* elf = info->GetElf(memory_);
Elf* elf = info->GetElf(memory_, arch());
uint64_t ptr;
// Find first non-empty list (libraries might be loaded multiple times).
if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {

View file

@ -141,8 +141,8 @@ uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
return code.next;
}
void JitDebug::SetArch(ArchEnum arch) {
switch (arch) {
void JitDebug::ProcessArch() {
switch (arch()) {
case ARCH_X86:
read_descriptor_func_ = &JitDebug::ReadDescriptor32;
read_entry_func_ = &JitDebug::ReadEntry32Pack;

View file

@ -88,6 +88,7 @@ MapInfo* LocalUnwinder::GetMapInfo(uint64_t pc) {
bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames) {
std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
unwindstack::RegsGetLocal(regs.get());
ArchEnum arch = regs->Arch();
size_t num_frames = 0;
bool adjust_pc = false;
@ -100,7 +101,7 @@ bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_f
break;
}
Elf* elf = map_info->GetElf(process_memory_);
Elf* elf = map_info->GetElf(process_memory_, arch);
uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
uint64_t step_pc = rel_pc;
uint64_t pc_adjustment;

View file

@ -146,7 +146,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
return nullptr;
}
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
// Make sure no other thread is trying to add the elf to this map.
std::lock_guard<std::mutex> guard(mutex_);
@ -176,6 +176,10 @@ Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
elf->Init();
if (elf->valid() && expected_arch != elf->arch()) {
// Make the elf invalid, mismatch between arch and expected arch.
elf->Invalidate();
}
if (locked) {
Elf::CacheAdd(this);

View file

@ -135,6 +135,8 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
last_error_.code = ERROR_NONE;
last_error_.address = 0;
ArchEnum arch = regs_->Arch();
bool return_address_attempt = false;
bool adjust_pc = false;
std::unique_ptr<JitDebug> jit_debug;
@ -155,7 +157,7 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
}
elf = map_info->GetElf(process_memory_);
elf = map_info->GetElf(process_memory_, arch);
step_pc = regs_->pc();
rel_pc = elf->GetRelPc(step_pc, map_info);
// Everyone except elf data in gdb jit debug maps uses the relative pc.

View file

@ -47,8 +47,6 @@ class DexFiles : public Global {
void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
uint64_t* method_offset);
void SetArch(ArchEnum arch);
private:
void Init(Maps* maps);
@ -64,6 +62,8 @@ class DexFiles : public Global {
bool ReadVariableData(uint64_t ptr_offset) override;
void ProcessArch() override;
std::mutex lock_;
bool initialized_ = false;
std::unordered_map<uint64_t, DexFile*> files_;

View file

@ -57,6 +57,8 @@ class Elf {
void InitGnuDebugdata();
void Invalidate();
bool GetSoname(std::string* name);
bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);

View file

@ -25,6 +25,7 @@
#include <unordered_map>
#include <vector>
#include <unwindstack/Elf.h>
#include <unwindstack/Memory.h>
namespace unwindstack {
@ -39,12 +40,20 @@ class Global {
Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
virtual ~Global() = default;
void SetArch(ArchEnum arch);
ArchEnum arch() { return arch_; }
protected:
uint64_t GetVariableOffset(MapInfo* info, const std::string& variable);
void FindAndReadVariable(Maps* maps, const char* variable);
virtual bool ReadVariableData(uint64_t offset) = 0;
virtual void ProcessArch() = 0;
ArchEnum arch_ = ARCH_UNKNOWN;
std::shared_ptr<Memory> memory_;
std::vector<std::string> search_libs_;
};

View file

@ -42,17 +42,9 @@ class JitDebug : public Global {
Elf* GetElf(Maps* maps, uint64_t pc);
void SetArch(ArchEnum arch);
private:
void Init(Maps* maps);
uint64_t entry_addr_ = 0;
bool initialized_ = false;
std::vector<Elf*> elf_list_;
std::mutex lock_;
uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr;
uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr;
@ -64,6 +56,14 @@ class JitDebug : public Global {
uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
bool ReadVariableData(uint64_t ptr_offset) override;
void ProcessArch() override;
uint64_t entry_addr_ = 0;
bool initialized_ = false;
std::vector<Elf*> elf_list_;
std::mutex lock_;
};
} // namespace unwindstack

View file

@ -72,7 +72,7 @@ struct MapInfo {
std::atomic_uint64_t load_bias;
// This function guarantees it will never return nullptr.
Elf* GetElf(const std::shared_ptr<Memory>& process_memory);
Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);

View file

@ -36,12 +36,20 @@ namespace unwindstack {
class DexFilesTest : public ::testing::Test {
protected:
void SetUp() override {
memory_ = new MemoryFake;
process_memory_.reset(memory_);
void CreateFakeElf(MapInfo* map_info) {
MemoryFake* memory = new MemoryFake;
ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
map_info->elf.reset(elf);
}
void Init(ArchEnum arch) {
dex_files_.reset(new DexFiles(process_memory_));
dex_files_->SetArch(ARCH_ARM);
dex_files_->SetArch(arch);
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
@ -58,35 +66,24 @@ class DexFilesTest : public ::testing::Test {
// Global variable in a section that is not readable.
MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
ASSERT_TRUE(map_info != nullptr);
MemoryFake* memory = new MemoryFake;
ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
// Global variable not set by default.
map_info = maps_->Get(kMapGlobalSetToZero);
ASSERT_TRUE(map_info != nullptr);
memory = new MemoryFake;
elf = new ElfFake(memory);
elf->FakeSetValid(true);
interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
// Global variable set in this map.
map_info = maps_->Get(kMapGlobal);
ASSERT_TRUE(map_info != nullptr);
memory = new MemoryFake;
elf = new ElfFake(memory);
elf->FakeSetValid(true);
interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
}
void SetUp() override {
memory_ = new MemoryFake;
process_memory_.reset(memory_);
Init(ARCH_ARM);
}
void WriteDescriptor32(uint64_t addr, uint32_t head);
@ -169,11 +166,12 @@ TEST_F(DexFilesTest, get_method_information_32) {
}
TEST_F(DexFilesTest, get_method_information_64) {
Init(ARCH_ARM64);
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
MapInfo* info = maps_->Get(kMapDexFiles);
dex_files_->SetArch(ARCH_ARM64);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0, 0, 0x301000);
WriteDex(0x301000);
@ -199,11 +197,12 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
}
TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
Init(ARCH_ARM64);
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
MapInfo* info = maps_->Get(kMapDexFiles);
dex_files_->SetArch(ARCH_ARM64);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0x200100, 0, 0x100000);
WriteEntry64(0x200100, 0, 0x200000, 0x300000);
@ -297,6 +296,8 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
}
TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
Init(ARCH_ARM64);
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
MapInfo* info = maps_->Get(kMapDexFiles);
@ -308,7 +309,6 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
WriteEntry64(0x200000, 0, 0, 0x300000);
WriteDex(0x300000);
dex_files_->SetArch(ARCH_ARM64);
dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);

View file

@ -82,9 +82,9 @@ void ElfCacheTest::VerifySameMap(bool cache_enabled) {
MapInfo info1(nullptr, start, end, 0, 0x5, tf.path);
MapInfo info2(nullptr, start, end, 0, 0x5, tf.path);
Elf* elf1 = info1.GetElf(memory_);
Elf* elf1 = info1.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf1->valid());
Elf* elf2 = info2.GetElf(memory_);
Elf* elf2 = info2.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf2->valid());
if (cache_enabled) {
@ -132,10 +132,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path);
MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path);
Elf* elf0_1 = info0_1.GetElf(memory_);
Elf* elf0_1 = info0_1.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf0_1->valid());
EXPECT_EQ(ARCH_ARM, elf0_1->arch());
Elf* elf0_2 = info0_2.GetElf(memory_);
Elf* elf0_2 = info0_2.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf0_2->valid());
EXPECT_EQ(ARCH_ARM, elf0_2->arch());
EXPECT_EQ(0U, info0_1.elf_offset);
@ -146,10 +146,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
EXPECT_NE(elf0_1, elf0_2);
}
Elf* elf100_1 = info100_1.GetElf(memory_);
Elf* elf100_1 = info100_1.GetElf(memory_, ARCH_X86);
ASSERT_TRUE(elf100_1->valid());
EXPECT_EQ(ARCH_X86, elf100_1->arch());
Elf* elf100_2 = info100_2.GetElf(memory_);
Elf* elf100_2 = info100_2.GetElf(memory_, ARCH_X86);
ASSERT_TRUE(elf100_2->valid());
EXPECT_EQ(ARCH_X86, elf100_2->arch());
EXPECT_EQ(0U, info100_1.elf_offset);
@ -160,10 +160,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
EXPECT_NE(elf100_1, elf100_2);
}
Elf* elf200_1 = info200_1.GetElf(memory_);
Elf* elf200_1 = info200_1.GetElf(memory_, ARCH_X86_64);
ASSERT_TRUE(elf200_1->valid());
EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
Elf* elf200_2 = info200_2.GetElf(memory_);
Elf* elf200_2 = info200_2.GetElf(memory_, ARCH_X86_64);
ASSERT_TRUE(elf200_2->valid());
EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
EXPECT_EQ(0U, info200_1.elf_offset);
@ -174,10 +174,10 @@ void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
EXPECT_NE(elf200_1, elf200_2);
}
Elf* elf300_1 = info300_1.GetElf(memory_);
Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf300_1->valid());
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
Elf* elf300_2 = info300_2.GetElf(memory_);
Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf300_2->valid());
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
EXPECT_EQ(0x300U, info300_1.elf_offset);
@ -222,10 +222,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path);
MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path);
Elf* elf300_1 = info300_1.GetElf(memory_);
Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf300_1->valid());
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
Elf* elf300_2 = info300_2.GetElf(memory_);
Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf300_2->valid());
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
EXPECT_EQ(0x300U, info300_1.elf_offset);
@ -236,10 +236,10 @@ void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
EXPECT_NE(elf300_1, elf300_2);
}
Elf* elf400_1 = info400_1.GetElf(memory_);
Elf* elf400_1 = info400_1.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf400_1->valid());
EXPECT_EQ(ARCH_ARM, elf400_1->arch());
Elf* elf400_2 = info400_2.GetElf(memory_);
Elf* elf400_2 = info400_2.GetElf(memory_, ARCH_ARM);
ASSERT_TRUE(elf400_2->valid());
EXPECT_EQ(ARCH_ARM, elf400_2->arch());
EXPECT_EQ(0x400U, info400_1.elf_offset);

View file

@ -35,12 +35,19 @@ namespace unwindstack {
class JitDebugTest : public ::testing::Test {
protected:
void SetUp() override {
memory_ = new MemoryFake;
process_memory_.reset(memory_);
void CreateFakeElf(MapInfo* map_info) {
MemoryFake* memory = new MemoryFake;
ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
}
void Init(ArchEnum arch) {
jit_debug_.reset(new JitDebug(process_memory_));
jit_debug_->SetArch(ARCH_ARM);
jit_debug_->SetArch(arch);
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
@ -57,33 +64,22 @@ class JitDebugTest : public ::testing::Test {
MapInfo* map_info = maps_->Get(3);
ASSERT_TRUE(map_info != nullptr);
MemoryFake* memory = new MemoryFake;
ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
memory = new MemoryFake;
elf = new ElfFake(memory);
elf->FakeSetValid(true);
interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
map_info = maps_->Get(7);
ASSERT_TRUE(map_info != nullptr);
memory = new MemoryFake;
elf = new ElfFake(memory);
elf->FakeSetValid(true);
interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
CreateFakeElf(map_info);
}
void SetUp() override {
memory_ = new MemoryFake;
process_memory_.reset(memory_);
Init(ARCH_ARM);
}
template <typename EhdrType, typename ShdrType>
@ -326,6 +322,8 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) {
}
TEST_F(JitDebugTest, get_elf_x86) {
Init(ARCH_X86);
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
WriteDescriptor32(0xf800, 0x200000);
@ -343,12 +341,13 @@ TEST_F(JitDebugTest, get_elf_x86) {
}
TEST_F(JitDebugTest, get_elf_64) {
Init(ARCH_ARM64);
CreateElf<Elf64_Ehdr, Elf64_Shdr>(0x4000, ELFCLASS64, EM_AARCH64, 0x1500, 0x200);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
jit_debug_->SetArch(ARCH_ARM64);
Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf != nullptr);

View file

@ -72,7 +72,7 @@ TEST_F(MapInfoGetElfTest, invalid) {
MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
// The map is empty, but this should still create an invalid elf object.
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
@ -84,7 +84,7 @@ TEST_F(MapInfoGetElfTest, valid32) {
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@ -98,13 +98,25 @@ TEST_F(MapInfoGetElfTest, valid64) {
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
}
TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
MapInfo info(nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
Elf32_Ehdr ehdr;
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_, ARCH_X86);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
@ -113,7 +125,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
memory_->SetMemory(0x2000 + offset, ptr, size);
});
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@ -129,7 +141,7 @@ TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
memory_->SetMemory(0x5000 + offset, ptr, size);
});
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@ -144,20 +156,20 @@ TEST_F(MapInfoGetElfTest, end_le_start) {
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
info.elf.reset();
info.end = 0xfff;
elf = info.GetElf(process_memory_);
elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
info.elf.reset();
info.end = 0x2000;
elf = info.GetElf(process_memory_);
elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
}
@ -174,7 +186,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@ -203,7 +215,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@ -236,7 +248,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32)
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@ -264,7 +276,7 @@ TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64)
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@ -290,13 +302,13 @@ TEST_F(MapInfoGetElfTest, process_memory_not_read_only) {
ehdr.e_shnum = 0;
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_);
elf = info.GetElf(process_memory_, ARCH_ARM64);
ASSERT_TRUE(elf->valid());
}
@ -313,20 +325,20 @@ TEST_F(MapInfoGetElfTest, check_device_maps) {
ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
info.elf.reset();
info.name = "";
elf = info.GetElf(process_memory_);
elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
info.elf.reset();
info.flags = PROT_READ;
elf = info.GetElf(process_memory_);
elf = info.GetElf(process_memory_, ARCH_X86_64);
ASSERT_TRUE(elf->valid());
}
@ -352,7 +364,7 @@ TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
while (wait)
;
Elf* elf = info.GetElf(process_memory_);
Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
elf_in_threads[i] = elf;
});
threads.push_back(thread);