frida/frida-rust

Returning a released pointer from RangeDetails::with_address

mkravchik opened this issue · 6 comments

Hi,
I consistently encountered this in the code I'm debugging. There is a call to RangeDetails::with_address. The returned value is complete nonsense.
When I debug it, I can see that when the save_range_details_by_address is called, it is passed a pointer to a details struct with correct data. However when we get back to with_address, the pointer points to garbage. I can only assume that the native Gum has freed this object and don't see anything preventing it from doing so.

pub fn with_address(address: u64) -> Option<RangeDetails<'a>> {
    let mut context = SaveRangeDetailsByAddressContext {
        address,
        details: core::ptr::null_mut(),
    };
    unsafe {
        gum_sys::gum_process_enumerate_ranges(
            gum_sys::_GumPageProtection_GUM_PAGE_NO_ACCESS as u32,
            Some(save_range_details_by_address),
            &mut context as *mut _ as *mut c_void,
        );
    }

    if !context.details.is_null() {
        Some(RangeDetails::from_raw(context.details))
    } else {
        None
    }
}

@mkravchik can you try this fix and confirm it is working?

Oh wait. I'm dumb... This doesn't fix at all...

Ok. Try now

I tried it, and it looks good. In the meantime (until the version is out) I've found the following workaround useful:

/// Get the start and end of the memory region containing the given address
/// Uses RangeDetails::enumerate_with_prot as RangeDetails::with_address seems to have a bug
/// Returns (start, end)
fn range_for_address(address: usize) -> (usize, usize) {
    let mut start = 0; 
    let mut end = 0; 
    RangeDetails::enumerate_with_prot(PageProtection::NoAccess, &mut |range: &RangeDetails| {
        let range_start = range.memory_range().base_address().0 as usize;
        let range_end = range_start + range.memory_range().size();
        if range_start <= address && range_end >= address {
            start = range_start;
            end = range_end;
            // I want to stop iteration here
            return false;
        }
        true
    });

    if start == 0 {
        log::error!("range_for_address: no range found for address {:#x}", address);
    }
    (start, end)
}

I'll wait till the next frida version to release.