mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 22:26:06 +00:00
linux: Correct handling of load bias
The load bias is documented to be the difference between the preferred and actual load address for a module, but is declared as an unsigned number, and math using it relies on it being a pointer-precisioned two's complement number that might cause over- or under-flow. ElfImageReader and DebugRendezvous both provide ways to get the load bias for a module and are corroborated in tests. However, the load bias computed by DebugRendezvous does not have access to the preferred address, so there is not enough information to determine the signedness to use with a VMOffset. This patch compares the load biases modulo the numeric range for a pointer to ignore the signedness of the value. Also update the test module to trigger a negative load bias. Bug: chromium:1147922 Change-Id: I55bc49195cfb2def06777e26388380fb9bc0f710 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2569886 Commit-Queue: Joshua Peraza <jperaza@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
20cbfa4971
commit
00491d58ee
@ -41,7 +41,7 @@ class DebugRendezvous {
|
||||
|
||||
//! \brief The difference between the preferred load address in the ELF file
|
||||
//! and the actual loaded address in memory.
|
||||
LinuxVMOffset load_bias;
|
||||
VMAddress load_bias;
|
||||
|
||||
//! \brief The address of the dynamic array for this object.
|
||||
LinuxVMAddress dynamic_array;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "build/build_config.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "snapshot/elf/elf_image_reader.h"
|
||||
#include "snapshot/linux/test_modules.h"
|
||||
#include "test/linux/fake_ptrace_connection.h"
|
||||
#include "test/main_arguments.h"
|
||||
#include "test/multiprocess.h"
|
||||
@ -34,6 +35,7 @@
|
||||
#include "util/linux/auxiliary_vector.h"
|
||||
#include "util/linux/direct_ptrace_connection.h"
|
||||
#include "util/linux/memory_map.h"
|
||||
#include "util/numeric/safe_assignment.h"
|
||||
#include "util/process/process_memory_linux.h"
|
||||
#include "util/process/process_memory_range.h"
|
||||
|
||||
@ -45,6 +47,20 @@ namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
void ExpectLoadBias(bool is_64_bit,
|
||||
VMAddress unsigned_bias,
|
||||
VMOffset signed_bias) {
|
||||
if (is_64_bit) {
|
||||
EXPECT_EQ(unsigned_bias, static_cast<VMAddress>(signed_bias));
|
||||
} else {
|
||||
uint32_t unsigned_bias32;
|
||||
ASSERT_TRUE(AssignIfInRange(&unsigned_bias32, unsigned_bias));
|
||||
|
||||
uint32_t casted_bias32 = static_cast<uint32_t>(signed_bias);
|
||||
EXPECT_EQ(unsigned_bias32, casted_bias32);
|
||||
}
|
||||
}
|
||||
|
||||
void TestAgainstTarget(PtraceConnection* connection) {
|
||||
// Use ElfImageReader on the main executable which can tell us the debug
|
||||
// address. glibc declares the symbol _r_debug in link.h which we can use to
|
||||
@ -112,9 +128,11 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
|
||||
// Android's loader doesn't set the load bias until Android 4.3 (API 18).
|
||||
if (android_runtime_api >= 18) {
|
||||
EXPECT_EQ(debug.Executable()->load_bias, exe_reader.GetLoadBias());
|
||||
ExpectLoadBias(connection->Is64Bit(),
|
||||
debug.Executable()->load_bias,
|
||||
exe_reader.GetLoadBias());
|
||||
} else {
|
||||
EXPECT_EQ(debug.Executable()->load_bias, 0);
|
||||
EXPECT_EQ(debug.Executable()->load_bias, 0u);
|
||||
}
|
||||
|
||||
for (const DebugRendezvous::LinkEntry& module : debug.Modules()) {
|
||||
@ -130,7 +148,7 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
// (API 17).
|
||||
if (is_android_loader && android_runtime_api < 17) {
|
||||
EXPECT_EQ(module.dynamic_array, 0u);
|
||||
EXPECT_EQ(module.load_bias, 0);
|
||||
EXPECT_EQ(module.load_bias, 0u);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -185,9 +203,11 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
// (API 20) until Android 6.0 (API 23).
|
||||
if (is_android_loader && android_runtime_api > 20 &&
|
||||
android_runtime_api < 23) {
|
||||
EXPECT_EQ(module.load_bias, 0);
|
||||
EXPECT_EQ(module.load_bias, 0u);
|
||||
} else {
|
||||
EXPECT_EQ(module.load_bias, module_reader->GetLoadBias());
|
||||
ExpectLoadBias(connection->Is64Bit(),
|
||||
module.load_bias,
|
||||
static_cast<VMAddress>(module_reader->GetLoadBias()));
|
||||
}
|
||||
|
||||
CheckedLinuxAddressRange module_range(
|
||||
@ -197,6 +217,12 @@ void TestAgainstTarget(PtraceConnection* connection) {
|
||||
}
|
||||
|
||||
TEST(DebugRendezvous, Self) {
|
||||
const std::string module_name = "test_module.so";
|
||||
const std::string module_soname = "test_module_soname";
|
||||
ScopedModuleHandle empty_test_module(
|
||||
LoadTestModule(module_name, module_soname));
|
||||
ASSERT_TRUE(empty_test_module.valid());
|
||||
|
||||
FakePtraceConnection connection;
|
||||
ASSERT_TRUE(connection.Initialize(getpid()));
|
||||
|
||||
|
@ -126,23 +126,35 @@ bool WriteTestModule(const base::FilePath& module_path,
|
||||
offsetof(decltype(module.shdr_table), section_header_string_table) /
|
||||
sizeof(Shdr);
|
||||
|
||||
constexpr size_t load2_vaddr = 0x200000;
|
||||
const size_t page_size = getpagesize();
|
||||
auto align = [page_size](uintptr_t addr) {
|
||||
return (addr + page_size - 1) & ~(page_size - 1);
|
||||
};
|
||||
constexpr size_t segment_size = offsetof(decltype(module), shdr_table);
|
||||
|
||||
// This test module covers cases where:
|
||||
// 1. Multiple segments are mapped from file offset 0.
|
||||
// 2. Load bias is negative.
|
||||
|
||||
const uintptr_t load2_vaddr = align(std::numeric_limits<uintptr_t>::max() -
|
||||
align(segment_size) - page_size);
|
||||
const uintptr_t load1_vaddr = load2_vaddr - align(segment_size);
|
||||
|
||||
module.phdr_table.load1.p_type = PT_LOAD;
|
||||
module.phdr_table.load1.p_offset = 0;
|
||||
module.phdr_table.load1.p_vaddr = 0;
|
||||
module.phdr_table.load1.p_filesz = offsetof(decltype(module), shdr_table);
|
||||
module.phdr_table.load1.p_memsz = offsetof(decltype(module), shdr_table);
|
||||
module.phdr_table.load1.p_vaddr = load1_vaddr;
|
||||
module.phdr_table.load1.p_filesz = segment_size;
|
||||
module.phdr_table.load1.p_memsz = segment_size;
|
||||
module.phdr_table.load1.p_flags = PF_R;
|
||||
module.phdr_table.load1.p_align = load2_vaddr;
|
||||
module.phdr_table.load1.p_align = page_size;
|
||||
|
||||
module.phdr_table.load2.p_type = PT_LOAD;
|
||||
module.phdr_table.load2.p_offset = 0;
|
||||
module.phdr_table.load2.p_vaddr = load2_vaddr;
|
||||
module.phdr_table.load2.p_filesz = offsetof(decltype(module), shdr_table);
|
||||
module.phdr_table.load2.p_memsz = offsetof(decltype(module), shdr_table);
|
||||
module.phdr_table.load2.p_filesz = segment_size;
|
||||
module.phdr_table.load2.p_memsz = segment_size;
|
||||
module.phdr_table.load2.p_flags = PF_R | PF_W;
|
||||
module.phdr_table.load2.p_align = load2_vaddr;
|
||||
module.phdr_table.load2.p_align = page_size;
|
||||
|
||||
module.phdr_table.dynamic.p_type = PT_DYNAMIC;
|
||||
module.phdr_table.dynamic.p_offset =
|
||||
@ -155,13 +167,14 @@ bool WriteTestModule(const base::FilePath& module_path,
|
||||
module.phdr_table.dynamic.p_align = 8;
|
||||
|
||||
module.dynamic_array.hash.d_tag = DT_HASH;
|
||||
module.dynamic_array.hash.d_un.d_ptr = offsetof(decltype(module), hash_table);
|
||||
module.dynamic_array.hash.d_un.d_ptr =
|
||||
load1_vaddr + offsetof(decltype(module), hash_table);
|
||||
module.dynamic_array.strtab.d_tag = DT_STRTAB;
|
||||
module.dynamic_array.strtab.d_un.d_ptr =
|
||||
offsetof(decltype(module), string_table);
|
||||
load1_vaddr + offsetof(decltype(module), string_table);
|
||||
module.dynamic_array.symtab.d_tag = DT_SYMTAB;
|
||||
module.dynamic_array.symtab.d_un.d_ptr =
|
||||
offsetof(decltype(module), symbol_table);
|
||||
load1_vaddr + offsetof(decltype(module), symbol_table);
|
||||
module.dynamic_array.strsz.d_tag = DT_STRSZ;
|
||||
module.dynamic_array.strsz.d_un.d_val = sizeof(module.string_table);
|
||||
module.dynamic_array.syment.d_tag = DT_SYMENT;
|
||||
|
Loading…
x
Reference in New Issue
Block a user