diff --git a/changelog.d/2576.added.md b/changelog.d/2576.added.md new file mode 100644 index 00000000000..fcebe0edd37 --- /dev/null +++ b/changelog.d/2576.added.md @@ -0,0 +1 @@ +Added experimental.trust_any_certificate to enable making app trust any certificate on macOS \ No newline at end of file diff --git a/mirrord-schema.json b/mirrord-schema.json index 5897114ddeb..d8c5d452206 100644 --- a/mirrord-schema.json +++ b/mirrord-schema.json @@ -617,7 +617,7 @@ "type": "object", "properties": { "readlink": { - "title": "_experimental_ readlink {#fexperimental-readlink}", + "title": "_experimental_ readlink {#experimental-readlink}", "description": "Enables the `readlink` hook.", "type": [ "boolean", @@ -625,12 +625,20 @@ ] }, "tcp_ping4_mock": { - "title": "_experimental_ tcp_ping4_mock {#fexperimental-tcp_ping4_mock}", + "title": "_experimental_ tcp_ping4_mock {#experimental-tcp_ping4_mock}", "description": "", "type": [ "boolean", "null" ] + }, + "trust_any_certificate": { + "title": "_experimental_ trust_any_certificate {#experimental-trust_any_certificate}", + "description": "Enables trusting any certificate on macOS, useful for ", + "type": [ + "boolean", + "null" + ] } }, "additionalProperties": false diff --git a/mirrord/config/src/experimental.rs b/mirrord/config/src/experimental.rs index d8239ef3095..8c50d191ab5 100644 --- a/mirrord/config/src/experimental.rs +++ b/mirrord/config/src/experimental.rs @@ -10,22 +10,29 @@ use crate::config::source::MirrordConfigSource; #[config(map_to = "ExperimentalFileConfig", derive = "JsonSchema")] #[cfg_attr(test, config(derive = "PartialEq, Eq"))] pub struct ExperimentalConfig { - /// ## _experimental_ tcp_ping4_mock {#fexperimental-tcp_ping4_mock} + /// ## _experimental_ tcp_ping4_mock {#experimental-tcp_ping4_mock} /// /// #[config(default = true)] pub tcp_ping4_mock: bool, - /// ## _experimental_ readlink {#fexperimental-readlink} + /// ## _experimental_ readlink {#experimental-readlink} /// /// Enables the `readlink` hook. #[config(default = false)] pub readlink: bool, + + /// # _experimental_ trust_any_certificate {#experimental-trust_any_certificate} + /// + /// Enables trusting any certificate on macOS, useful for + #[config(default = false)] + pub trust_any_certificate: bool, } impl CollectAnalytics for &ExperimentalConfig { fn collect_analytics(&self, analytics: &mut mirrord_analytics::Analytics) { analytics.add("tcp_ping4_mock", self.tcp_ping4_mock); analytics.add("readlink", self.readlink); + analytics.add("trust_any_certificate", self.trust_any_certificate); } } diff --git a/mirrord/layer/src/lib.rs b/mirrord/layer/src/lib.rs index ea7242356ff..07135a0b99f 100644 --- a/mirrord/layer/src/lib.rs +++ b/mirrord/layer/src/lib.rs @@ -112,6 +112,8 @@ mod macros; mod proxy_connection; mod setup; mod socket; +#[cfg(target_os = "macos")] +mod tls; #[cfg(all( any(target_arch = "x86_64", target_arch = "aarch64"), @@ -341,11 +343,7 @@ fn layer_start(mut config: LayerConfig) { SETUP.set(state).unwrap(); let state = setup(); - enable_hooks( - state.fs_config().is_active(), - state.remote_dns_enabled(), - state.sip_binaries(), - ); + enable_hooks(state); let _detour_guard = DetourGuard::new(); tracing::info!("Initializing mirrord-layer!"); @@ -475,7 +473,12 @@ fn sip_only_layer_start(mut config: LayerConfig, patch_binaries: Vec) { /// `true`, see [`NetworkConfig`](mirrord_config::feature::network::NetworkConfig), and /// [`hooks::enable_socket_hooks`](socket::hooks::enable_socket_hooks). #[mirrord_layer_macro::instrument(level = "trace")] -fn enable_hooks(enabled_file_ops: bool, enabled_remote_dns: bool, patch_binaries: Vec) { +fn enable_hooks(state: &LayerSetup) { + let enabled_file_ops = state.fs_config().is_active(); + let enabled_remote_dns = state.remote_dns_enabled(); + #[cfg(target_os = "macos")] + let patch_binaries = state.sip_binaries(); + let mut hook_manager = HookManager::default(); unsafe { @@ -526,6 +529,11 @@ fn enable_hooks(enabled_file_ops: bool, enabled_remote_dns: bool, patch_binaries exec_utils::enable_execve_hook(&mut hook_manager, patch_binaries) }; + #[cfg(target_os = "macos")] + if state.experimental().trust_any_certificate { + unsafe { tls::enable_tls_hooks(&mut hook_manager) }; + } + if enabled_file_ops { unsafe { file::hooks::enable_file_hooks(&mut hook_manager) }; } diff --git a/mirrord/layer/src/setup.rs b/mirrord/layer/src/setup.rs index f5862718c21..ee16ed12fd3 100644 --- a/mirrord/layer/src/setup.rs +++ b/mirrord/layer/src/setup.rs @@ -119,6 +119,7 @@ impl LayerSetup { .unwrap_or(true) } + #[cfg(target_os = "macos")] pub fn sip_binaries(&self) -> Vec { self.config .sip_binaries diff --git a/mirrord/layer/src/tls.rs b/mirrord/layer/src/tls.rs new file mode 100644 index 00000000000..6b77c17c82f --- /dev/null +++ b/mirrord/layer/src/tls.rs @@ -0,0 +1,24 @@ +use libc::c_void; +use mirrord_layer_macro::hook_guard_fn; + +use crate::{hooks::HookManager, replace}; + +// https://developer.apple.com/documentation/security/2980705-sectrustevaluatewitherror +#[hook_guard_fn] +pub(crate) unsafe extern "C" fn sec_trust_evaluate_with_error_detour( + trust: *const c_void, + error: *const c_void, +) -> bool { + tracing::trace!("sec_trust_evaluate_with_error_detour called"); + true +} + +pub(crate) unsafe fn enable_tls_hooks(hook_manager: &mut HookManager) { + replace!( + hook_manager, + "SecTrustEvaluateWithError", + sec_trust_evaluate_with_error_detour, + FnSec_trust_evaluate_with_error, + FN_SEC_TRUST_EVALUATE_WITH_ERROR + ); +}