Skip to content

Commit

Permalink
Fix golang + linux + fstat (#2259)
Browse files Browse the repository at this point in the history
* add replace_with_fallback to use when functions might not be available in Go hook context [specifically, fstat]

* Fixed issue with Golang calling fstat on Linux causing crash

* Update mirrord/layer/src/macros.rs

Co-authored-by: meowjesty <[email protected]>

* fmt

---------

Co-authored-by: meowjesty <[email protected]>
  • Loading branch information
aviramha and meowjesty authored Feb 22, 2024
1 parent f729c52 commit 2e8f94c
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.d/2254.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed issue with Golang calling fstat on Linux causing crash
9 changes: 8 additions & 1 deletion mirrord/layer/src/file/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,14 @@ pub(crate) unsafe fn enable_file_hooks(hook_manager: &mut HookManager) {
FN___LXSTAT64
);
replace!(hook_manager, "lstat", lstat_detour, FnLstat, FN_LSTAT);
replace!(hook_manager, "fstat", fstat_detour, FnFstat, FN_FSTAT);
crate::replace_with_fallback!(
hook_manager,
"fstat",
fstat_detour,
FnFstat,
FN_FSTAT,
libc::fstat
);
replace!(hook_manager, "stat", stat_detour, FnStat, FN_STAT);
replace!(
hook_manager,
Expand Down
59 changes: 59 additions & 0 deletions mirrord/layer/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,65 @@ macro_rules! replace {
}};
}

/// Replaces the `$func` [`libc`] function, with the equivalent hook `$detour_function`, by calling
/// `HookManager::hook_export_or_any`. This variant accepts a fallback function to put in the
/// original function if the hook fails. This is useful in Go when we actually don't hook any libc
/// but still need to call it.
///
/// ## Parameters
///
/// - `$hook_manager`: a valid [`HookManager`](crate::hooks::HookManager) instance that is used to
/// replace the [`libc`] function;
///
/// - `$func`: the function we want to replace;
///
/// - `$detour_function`: one of our detour functions;
///
/// - `$detour_type`: the type alias that was generated by `hook_fn` for this function type;
///
/// - `$hook_fn`: stores the original function pointer as a [`HookFn`](crate::detour::HookFn) that
/// is created by `hook_fn`.
/// - `$fallback_fn`: stores the libc function to fallback to if the hook fails.
///
/// ## Examples
///
/// - Replacing [`libc::close`] with [`close_detour`](crate::close_detour):
///
/// ```rust, no_run
/// unsafe {
/// replace_with_fallback!(
/// hook_manager,
/// "close",
/// close_detour,
/// FnClose,
/// FN_CLOSE,
/// libc::close
/// );
/// }
/// ```
#[macro_export]
macro_rules! replace_with_fallback {
($hook_manager:expr, $func:expr, $detour_function:expr, $detour_type:ty, $hook_fn:expr, $fallback_fn:expr) => {{
let intercept = |hook_manager: &mut $crate::hooks::HookManager,
symbol_name,
detour: $detour_type|
-> $crate::error::Result<$detour_type> {
let replaced =
hook_manager.hook_export_or_any(symbol_name, detour as *mut libc::c_void)?;
let original_fn: $detour_type = std::mem::transmute(replaced);

tracing::trace!("hooked {symbol_name:?}");
Ok(original_fn)
};

let _ = intercept($hook_manager, $func, $detour_function)
.and_then(|hooked| Ok($hook_fn.set(hooked).unwrap()))
.unwrap_or_else(|_| {
$hook_fn.set($fallback_fn).unwrap();
});
}};
}

/// Used by [`go_hooks`](crate::go_hooks) to hook go syscalls with
/// `HookManager::hook_symbol_main_module`.
///
Expand Down

0 comments on commit 2e8f94c

Please sign in to comment.