Skip to content

Commit 4192104

Browse files
committed
intercept: make execvpe optional (macos does not have)
1 parent fd26477 commit 4192104

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

intercept-preload/src/c/shim.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ extern void rust_session_init(char *const *envp);
5858
// Exec family functions
5959
extern int rust_execve(const char *path, char *const argv[], char *const envp[]);
6060
extern int rust_execvpe(const char *file, char *const argv[], char *const envp[]);
61+
extern int rust_execvp(const char *file, char *const argv[]);
6162
extern int rust_execvP(const char *file, const char *search_path, char *const argv[]);
6263
extern int rust_exect(const char *path, char *const argv[], char *const envp[]);
6364
extern int rust_posix_spawn(pid_t *pid, const char *path,
@@ -163,7 +164,11 @@ EXPORT int execlp(const char *file, const char *arg0, ...)
163164

164165
va_end(ap);
165166

167+
#if defined(has_symbol_execvpe)
166168
return rust_execvpe(file, argv, get_environ());
169+
#else
170+
return rust_execvp(file, argv);
171+
#endif
167172
}
168173
#endif
169174

@@ -226,7 +231,11 @@ EXPORT int execve(const char *path, char *const argv[], char *const envp[])
226231
#if defined(has_symbol_execvp)
227232
EXPORT int execvp(const char *file, char *const argv[])
228233
{
234+
#if defined(has_symbol_execvpe)
229235
return rust_execvpe(file, argv, get_environ());
236+
#else
237+
return rust_execvp(file, argv);
238+
#endif
230239
}
231240
#endif
232241

intercept-preload/src/implementation.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ static REAL_EXECVPE: AtomicPtr<libc::c_void> = {
4949
AtomicPtr::new(ptr)
5050
};
5151

52+
#[ctor]
53+
static REAL_EXECVP: AtomicPtr<libc::c_void> = {
54+
let ptr = unsafe { libc::dlsym(RTLD_NEXT, c"execvp".as_ptr() as *const _) };
55+
AtomicPtr::new(ptr)
56+
};
57+
5258
#[ctor]
5359
static REAL_EXECVP_OPENBSD: AtomicPtr<libc::c_void> = {
5460
let ptr = unsafe { libc::dlsym(RTLD_NEXT, c"execvP".as_ptr() as *const _) };
@@ -180,7 +186,8 @@ pub unsafe extern "C" fn rust_execve(
180186

181187
/// Rust implementation of execvpe (GNU extension)
182188
///
183-
/// Called from C shim for: execvpe, execvp, execlp
189+
/// Called from C shim for: execvpe
190+
/// On platforms where execvpe is available, execlp and execvp are also routed here.
184191
///
185192
/// # Safety
186193
/// This function is unsafe because it:
@@ -226,6 +233,52 @@ pub unsafe extern "C" fn rust_execvpe(
226233
}
227234
}
228235

236+
/// Rust implementation of execvp
237+
///
238+
/// Called from C shim for: execvp, execlp (on platforms where execvpe is not available)
239+
///
240+
/// Unlike `rust_execvpe`, this function does not take an explicit `envp` argument.
241+
/// The real `execvp` uses the process's `environ`, so no environment doctoring is
242+
/// performed here (same approach as `popen` and `system`).
243+
///
244+
/// # Safety
245+
/// This function is unsafe because it:
246+
/// - Dereferences raw pointers
247+
/// - Calls the real execvp function
248+
#[cfg(has_symbol_execvp)]
249+
#[unsafe(no_mangle)]
250+
pub unsafe extern "C" fn rust_execvp(
251+
file: *const c_char,
252+
argv: *const *const c_char,
253+
) -> c_int {
254+
type ExecvpFunc = unsafe extern "C" fn(
255+
file: *const c_char,
256+
argv: *const *const c_char,
257+
) -> c_int;
258+
259+
unsafe {
260+
report(|| {
261+
let result = Execution {
262+
executable: as_path_buf(file)?,
263+
arguments: as_string_vec(argv)?,
264+
working_dir: working_dir()?,
265+
environment: std::env::vars().collect(),
266+
};
267+
Ok(result)
268+
});
269+
270+
let func_ptr = REAL_EXECVP.load(Ordering::SeqCst);
271+
if !func_ptr.is_null() {
272+
let real_func_ptr: ExecvpFunc = std::mem::transmute(func_ptr);
273+
real_func_ptr(file, argv)
274+
} else {
275+
log::error!("Real execvp function not found");
276+
set_errno(libc::ENOSYS);
277+
-1
278+
}
279+
}
280+
}
281+
229282
/// Rust implementation of execvP (BSD extension)
230283
///
231284
/// Called from C shim for: execvP

intercept-preload/src/session.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use std::ffi::{CStr, CString};
1515
use std::net::SocketAddr;
1616
use std::sync::OnceLock;
1717

18-
use bear::environment::{KEY_INTERCEPT_STATE, KEY_OS__PRELOAD_PATH};
18+
use bear::environment::KEY_INTERCEPT_STATE;
19+
#[cfg(not(target_os = "macos"))]
20+
use bear::environment::KEY_OS__PRELOAD_PATH;
1921
#[cfg(target_os = "macos")]
2022
use bear::environment::{KEY_OS__MACOS_FLAT_NAMESPACE, KEY_OS__MACOS_PRELOAD_PATH};
2123
use bear::intercept::environment::{PreloadState, insert_to_path};

0 commit comments

Comments
 (0)