elf: adjust small DT_STRTAB addresses by load bias

Change-Id: I7ffbd2be0800aedad8b5c4b6982379e5485f1bc8
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2229114
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Joshua Peraza 2020-06-04 15:05:27 -07:00 committed by Commit Bot
parent 86c28287d2
commit 294d233ca0
2 changed files with 31 additions and 11 deletions

View File

@ -589,6 +589,14 @@ bool ElfImageReader::ReadDynamicStringTableAtOffset(VMSize offset,
return false; return false;
} }
// GNU ld.so doesn't adjust the vdso's dynamic array entries by the load bias.
// If the address is too small to point into the loaded module range and is
// small enough to be an offset from the base of the module, adjust it now.
if (string_table_address < memory_.Base() &&
string_table_address < memory_.Size()) {
string_table_address += GetLoadBias();
}
if (!memory_.ReadCStringSizeLimited( if (!memory_.ReadCStringSizeLimited(
string_table_address + offset, string_table_size - offset, string)) { string_table_address + offset, string_table_size - offset, string)) {
LOG(ERROR) << "missing nul-terminator"; LOG(ERROR) << "missing nul-terminator";

View File

@ -535,7 +535,8 @@ void ExpectModulesFromSelf(
#endif // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21 #endif // !OS_ANDROID || !ARCH_CPU_ARMEL || __ANDROID_API__ >= 21
} }
bool WriteTestModule(const base::FilePath& module_path) { bool WriteTestModule(const base::FilePath& module_path,
const std::string& soname) {
#if defined(ARCH_CPU_64_BITS) #if defined(ARCH_CPU_64_BITS)
using Ehdr = Elf64_Ehdr; using Ehdr = Elf64_Ehdr;
using Phdr = Elf64_Phdr; using Phdr = Elf64_Phdr;
@ -565,6 +566,7 @@ bool WriteTestModule(const base::FilePath& module_path) {
Dyn symtab; Dyn symtab;
Dyn strsz; Dyn strsz;
Dyn syment; Dyn syment;
Dyn soname;
Dyn null; Dyn null;
} dynamic_array; } dynamic_array;
struct { struct {
@ -573,8 +575,7 @@ bool WriteTestModule(const base::FilePath& module_path) {
Elf32_Word bucket; Elf32_Word bucket;
Elf32_Word chain; Elf32_Word chain;
} hash_table; } hash_table;
struct { char string_table[32];
} string_table;
struct { struct {
} section_header_string_table; } section_header_string_table;
struct { struct {
@ -671,6 +672,9 @@ bool WriteTestModule(const base::FilePath& module_path) {
module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table); module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table);
module.dynamic_array.syment.d_tag = DT_SYMENT; module.dynamic_array.syment.d_tag = DT_SYMENT;
module.dynamic_array.syment.d_un.d_val = sizeof(Sym); module.dynamic_array.syment.d_un.d_val = sizeof(Sym);
constexpr size_t kSonameOffset = 1;
module.dynamic_array.soname.d_tag = DT_SONAME;
module.dynamic_array.soname.d_un.d_val = kSonameOffset;
module.dynamic_array.null.d_tag = DT_NULL; module.dynamic_array.null.d_tag = DT_NULL;
@ -679,6 +683,10 @@ bool WriteTestModule(const base::FilePath& module_path) {
module.hash_table.bucket = 0; module.hash_table.bucket = 0;
module.hash_table.chain = 0; module.hash_table.chain = 0;
CHECK_GE(sizeof(module.string_table), soname.size() + 2);
module.string_table[0] = '\0';
memcpy(&module.string_table[kSonameOffset], soname.c_str(), soname.size());
module.shdr_table.null.sh_type = SHT_NULL; module.shdr_table.null.sh_type = SHT_NULL;
module.shdr_table.dynamic.sh_name = 0; module.shdr_table.dynamic.sh_name = 0;
@ -716,11 +724,12 @@ bool WriteTestModule(const base::FilePath& module_path) {
return true; return true;
} }
ScopedModuleHandle LoadTestModule(const std::string& module_name) { ScopedModuleHandle LoadTestModule(const std::string& module_name,
const std::string& module_soname) {
base::FilePath module_path( base::FilePath module_path(
TestPaths::Executable().DirName().Append(module_name)); TestPaths::Executable().DirName().Append(module_name));
if (!WriteTestModule(module_path)) { if (!WriteTestModule(module_path, module_soname)) {
return ScopedModuleHandle(nullptr); return ScopedModuleHandle(nullptr);
} }
EXPECT_TRUE(IsRegularFile(module_path)); EXPECT_TRUE(IsRegularFile(module_path));
@ -756,7 +765,9 @@ void ExpectTestModule(ProcessReaderLinux* reader,
TEST(ProcessReaderLinux, SelfModules) { TEST(ProcessReaderLinux, SelfModules) {
const std::string module_name = "test_module.so"; const std::string module_name = "test_module.so";
ScopedModuleHandle empty_test_module(LoadTestModule(module_name)); const std::string module_soname = "test_module_soname";
ScopedModuleHandle empty_test_module(
LoadTestModule(module_name, module_soname));
ASSERT_TRUE(empty_test_module.valid()); ASSERT_TRUE(empty_test_module.valid());
FakePtraceConnection connection; FakePtraceConnection connection;
@ -766,12 +777,12 @@ TEST(ProcessReaderLinux, SelfModules) {
ASSERT_TRUE(process_reader.Initialize(&connection)); ASSERT_TRUE(process_reader.Initialize(&connection));
ExpectModulesFromSelf(process_reader.Modules()); ExpectModulesFromSelf(process_reader.Modules());
ExpectTestModule(&process_reader, module_name); ExpectTestModule(&process_reader, module_soname);
} }
class ChildModuleTest : public Multiprocess { class ChildModuleTest : public Multiprocess {
public: public:
ChildModuleTest() : Multiprocess(), module_name_("test_module.so") {} ChildModuleTest() : Multiprocess(), module_soname_("test_module_soname") {}
~ChildModuleTest() = default; ~ChildModuleTest() = default;
private: private:
@ -786,11 +797,12 @@ class ChildModuleTest : public Multiprocess {
ASSERT_TRUE(process_reader.Initialize(&connection)); ASSERT_TRUE(process_reader.Initialize(&connection));
ExpectModulesFromSelf(process_reader.Modules()); ExpectModulesFromSelf(process_reader.Modules());
ExpectTestModule(&process_reader, module_name_); ExpectTestModule(&process_reader, module_soname_);
} }
void MultiprocessChild() override { void MultiprocessChild() override {
ScopedModuleHandle empty_test_module(LoadTestModule(module_name_)); ScopedModuleHandle empty_test_module(
LoadTestModule("test_module.so", module_soname_));
ASSERT_TRUE(empty_test_module.valid()); ASSERT_TRUE(empty_test_module.valid());
char c = 0; char c = 0;
@ -799,7 +811,7 @@ class ChildModuleTest : public Multiprocess {
CheckedReadFileAtEOF(ReadPipeHandle()); CheckedReadFileAtEOF(ReadPipeHandle());
} }
const std::string module_name_; const std::string module_soname_;
DISALLOW_COPY_AND_ASSIGN(ChildModuleTest); DISALLOW_COPY_AND_ASSIGN(ChildModuleTest);
}; };