8000 Isolated Processes 3: Redirect process_reader by marti4d · Pull Request #180 · rust-minidump/minidump-writer · GitHub
[go: up one dir, main page]

Skip to content
8000
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 deletions src/bin/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ mod linux {
use minidump_writer::process_reader::ProcessReader;

let ppid = getppid().as_raw();
let dumper = fail_on_soft_error!(
let mut dumper = fail_on_soft_error!(
soft_errors,
MinidumpWriterConfig::new(ppid, ppid).build_for_testing(&mut soft_errors)?
);
Expand All @@ -91,7 +91,7 @@ mod linux {
let expected_stack = 0x11223344usize.to_ne_bytes();
let expected_heap = 0x55667788usize.to_ne_bytes();

let validate = |reader: &mut ProcessReader| -> Result<()> {
let validate = |reader: &ProcessReader| -> Result<()> {
let mut val = [0u8; std::mem::size_of::<usize>()];
let read = reader.read(stack_var, &mut val)?;
assert_eq!(read, val.len());
Expand All @@ -106,33 +106,45 @@ mod linux {

// virtual mem
{
let mut mr = ProcessReader::for_virtual_mem(ppid);
validate(&mut mr)
.map_err(|err| format!("failed to validate memory for {mr:?}: {err}"))?;
dumper.process_inspector.force_pr_virtual_mem();
validate(dumper.process_inspector.process_reader())
.map_err(|err| format!("failed to validate memory: {err}"))?;
}

// file
{
let mut mr = ProcessReader::for_file(ppid)
dumper
.process_inspector
.force_pr_file()
.map_err(|err| format!("failed to open `/proc/{ppid}/mem`: {err}"))?;
validate(&mut mr)
.map_err(|err| format!("failed to validate memory for {mr:?}: {err}"))?;
validate(dumper.process_inspector.process_reader())
.map_err(|err| format!("failed to validate memory: {err}"))?;
}

// ptrace
{
let mut mr = ProcessReader::for_ptrace(ppid);
validate(&mut mr)
.map_err(|err| format!("failed to validate memory for {mr:?}: {err}"))?;
dumper.process_inspector.force_pr_ptrace();
validate(dumper.process_inspector.process_reader())
.map_err(|err| format!("failed to validate memory: {err}"))?;
}

let stack_res =
MinidumpWriter::copy_from_process(ppid, stack_var, std::mem::size_of::<usize>())?;
dumper.process_inspector.force_pr_reset();

let stack_res = MinidumpWriter::copy_from_process(
&dumper.process_inspector,
ppid,
stack_var,
std::mem::size_of::<usize>(),
)?;

test!(stack_res == expected_stack, "stack var not correct");

let heap_res =
MinidumpWriter::copy_from_process(ppid, heap_var, std::mem::size_of::<usize>())?;
let heap_res = MinidumpWriter::copy_from_process(
&dumper.process_inspector,
ppid,
heap_var,
std::mem::size_of::<usize>(),
)?;

test!(heap_res == expected_heap, "heap var not correct");

Expand Down Expand Up @@ -225,8 +237,10 @@ mod linux {
if mapping.name == Some(LINUX_GATE_LIBRARY_NAME.into()) {
found_linux_gate = true;

let module_reader::BuildId(id) =
MinidumpWriter::from_process_memory_for_mapping(&mapping, ppid)?;
let module_reader::BuildId(id) = MinidumpWriter::from_process_memory_for_mapping(
&dumper.process_inspector,
&mapping,
)?;
test!(!id.is_empty(), "id-vec is empty");
test!(id.iter().any(|&x| x > 0), "all id elements are 0");
drop(dumper);
Expand Down
45 changes: 33 additions & 12 deletions src/linux/android.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
super::{
Pid, maps_reader::MappingInfo, minidump_writer::MinidumpWriter,
process_reader::CopyFromProcessError,
process_inspection::ProcessInspector, process_reader::CopyFromProcessError,
},
goblin::elf,
};
Expand Down Expand Up @@ -48,11 +48,16 @@ struct DynVaddresses {
dyn_count: usize,
}

fn has_android_packed_relocations(pid: Pid, load_bias: usize, vaddrs: DynVaddresses) -> Result<()> {
fn has_android_packed_relocations(
process_inspector: &ProcessInspector,
pid: Pid,
load_bias: usize,
vaddrs: DynVaddresses,
) -> Result<()> {
let dyn_addr = load_bias + vaddrs.dyn_vaddr;
for idx in 0..vaddrs.dyn_count {
let addr = dyn_addr + SIZEOF_DYN * idx;
let dyn_data = MinidumpWriter::copy_from_process(pid, addr, SIZEOF_DYN)?;
let dyn_data = MinidumpWriter::copy_from_process(process_inspector, pid, addr, SIZEOF_DYN)?;
// TODO: Couldn't find a nice way to use goblin for that, to avoid the unsafe-block
let dyn_obj: Dyn;
unsafe {
Expand All @@ -66,14 +71,19 @@ fn has_android_packed_relocations(pid: Pid, load_bias: usize, vaddrs: DynVaddres
Err(AndroidError::NoRelFound)
}

fn get_effective_load_bias(pid: Pid, ehdr: &elf_header::Header, address: usize) -> usize {
let ph = parse_loaded_elf_program_headers(pid, ehdr, address);
fn get_effective_load_bias(
process_inspector: &ProcessInspector,
pid: Pid,
ehdr: &elf_header::Header,
address: usize,
) -> usize {
let ph = parse_loaded_elf_program_headers(process_inspector, pid, ehdr, address);
// If |min_vaddr| is non-zero and we find Android packed relocation tags,
// return the effective load bias.

if ph.min_vaddr != 0 {
let load_bias = address - ph.min_vaddr;
if has_android_packed_relocations(pid, load_bias, ph).is_ok() {
if has_android_packed_relocations(process_inspector, pid, load_bias, ph).is_ok() {
return load_bias;
}
}
Expand All @@ -83,6 +93,7 @@ fn get_effective_load_bias(pid: Pid, ehdr: &elf_header::Header, address: usize)
}

fn parse_loaded_elf_program_headers(
process_inspector: &ProcessInspector,
pid: Pid,
ehdr: &elf_header::Header,
address: usize,
Expand All @@ -93,6 +104,7 @@ fn parse_loaded_elf_program_headers(
let mut dyn_count = 0;

let phdr_opt = MinidumpWriter::copy_from_process(
process_inspector,
pid,
phdr_addr,
elf_header::SIZEOF_EHDR * ehdr.e_phnum as usize,
Expand Down Expand Up @@ -122,17 +134,25 @@ fn parse_loaded_elf_program_headers(
}
}

pub fn late_process_mappings(pid: Pid, mappings: &mut [MappingInfo]) -> Result<()> {
pub fn late_process_mappings(
process_inspector: &ProcessInspector,
pid: Pid,
mappings: &mut [MappingInfo],
) -> Result<()> {
// Only consider exec mappings that indicate a file path was mapped, and
// where the ELF header indicates a mapped shared library.
for map in mappings
.iter_mut()
.filter(|m| m.is_executable() && m.name_is_path())
{
let ehdr_opt =
MinidumpWriter::copy_from_process(pid, map.start_address, elf_header::SIZEOF_EHDR)
.ok()
.and_then(|x| elf_header::Header::parse(&x).ok());
let ehdr_opt = MinidumpWriter::copy_from_process(
process_inspector,
pid,
map.start_address,
elf_header::SIZEOF_EHDR,
)
.ok()
.and_then(|x| elf_header::Header::parse(&x).ok());

if let Some(ehdr) = ehdr_opt {
if ehdr.e_type == elf_header::ET_DYN {
Expand All @@ -142,7 +162,8 @@ pub fn late_process_mappings(pid: Pid, mappings: &mut [MappingInfo]) -> Result<(
// the library does not contain Android packed relocations,
// GetEffectiveLoadBias() returns |start_addr| and the mapping entry
// is not changed.
let load_bias = get_effective_load_bias(pid, &ehdr, map.start_address);
let load_bias =
get_effective_load_bias(process_inspector, pid, &ehdr, map.start_address);
map.size += map.start_address - load_bias;
map.start_address = load_bias;
}
Expand Down
38 changes: 29 additions & 9 deletions src/linux/dso_debug.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
super::{
auxv::AuxvDumpInfo, minidump_writer::MinidumpWriter, process_reader::CopyFromProcessError,
serializers::*,
auxv::AuxvDumpInfo, minidump_writer::MinidumpWriter, process_inspection::ProcessInspector,
process_reader::CopyFromProcessError, serializers::*,
},
crate::{
mem_writer::{
Expand Down Expand Up @@ -97,6 +97,7 @@ pub struct RDebug {
}

pub fn write_dso_debug_stream(
process_inspector: &ProcessInspector,
buffer: &mut Buffer,
blamed_thread: i32,
auxv: &AuxvDumpInfo,
Expand All @@ -108,7 +109,12 @@ pub fn write_dso_debug_stream(
.get_program_header_address()
.ok_or(SectionDsoDebugError::CouldNotFind("AT_PHDR in auxv"))? as usize;

let ph = MinidumpWriter::copy_from_process(blamed_thread, phdr, SIZEOF_PHDR * phnum_max)?;
let ph = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
phdr,
SIZEOF_PHDR * phnum_max,
)?;
let program_headers;
#[cfg(target_pointer_width = "64")]
{
Expand Down Expand Up @@ -155,6 +161,7 @@ pub fn write_dso_debug_stream(
// dump it to a MD_LINUX_DSO_DEBUG stream.
loop {
let dyn_data = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
dyn_addr as usize + dynamic_length,
dyn_size,
Expand Down Expand Up @@ -182,8 +189,12 @@ pub fn write_dso_debug_stream(
// See <link.h> for a more detailed discussion of the how the dynamic
// loader communicates with debuggers.

let debug_entry_data =
MinidumpWriter::copy_from_process(blamed_thread, r_debug, std::mem::size_of::<RDebug>())?;
let debug_entry_data = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
r_debug,
std::mem::size_of::<RDebug>(),
)?;

// goblin::elf::Dyn doesn't have padding bytes
let (head, body, _tail) = unsafe { debug_entry_data.align_to::<RDebug>() };
Expand All @@ -195,6 +206,7 @@ pub fn write_dso_debug_stream(
let mut curr_map = debug_entry.r_map;
while curr_map != 0 {
let link_map_data = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
curr_map,
std::mem::size_of::<LinkMap>(),
Expand All @@ -220,8 +232,12 @@ pub fn write_dso_debug_stream(
for (idx, map) in dso_vec.iter().enumerate() {
let mut filename = String::new();
if map.l_name > 0 {
let filename_data =
MinidumpWriter::copy_from_process(blamed_thread, map.l_name, 256)?;
let filename_data = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
map.l_name,
256,
)?;

// C - string is NULL-terminated
if let Some(name) = filename_data.splitn(2, |x| *x == b'\0').next() {
Expand Down Expand Up @@ -256,8 +272,12 @@ pub fn write_dso_debug_stream(
};

dirent.location.data_size += dynamic_length as u32;
let dso_debug_data =
MinidumpWriter::copy_from_process(blamed_thread, dyn_addr as usize, dynamic_length)?;
let dso_debug_data = MinidumpWriter::copy_from_process(
process_inspector,
blamed_thread,
dyn_addr as usize,
dynamic_length,
)?;
MemoryArrayWriter::write_bytes(buffer, &dso_debug_data);

Ok(dirent)
Expand Down
8 changes: 6 additions & 2 deletions src/linux/minidump_writer/app_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ impl MinidumpWriter {
pub fn write_app_memory(&mut self, buffer: &mut DumpBuf) -> Result<(), SectionAppMemoryError> {
let blamed_thread = self.blamed_thread;
for app_memory in &self.app_memory {
let data_copy =
Self::copy_from_process(blamed_thread, app_memory.ptr, app_memory.length)?;
let data_copy = Self::copy_from_process(
&self.process_inspector,
blamed_thread,
app_memory.ptr,
app_memory.length,
)?;

let section = MemoryArrayWriter::write_bytes(buffer, &data_copy);
let desc = MDMemoryDescriptor {
Expand Down
Loading
Loading
0