diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index 70814c74106..6c1080af832 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -738,6 +738,22 @@ dependencies = [ "syn", ] +[[package]] +name = "ctor" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" + [[package]] name = "ctr" version = "0.9.2" @@ -1029,6 +1045,21 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dtor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + [[package]] name = "ecdsa" version = "0.16.9" @@ -1821,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55740c4ae1d8696773c78fdafd5d0e5fe9bc9f1b071c7ba493ba5c413a9184f3" dependencies = [ "bitflags", - "ctor", + "ctor 0.2.9", "napi-derive", "napi-sys", "once_cell", @@ -2473,6 +2504,15 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "process_isolation" +version = "0.0.0" +dependencies = [ + "ctor 0.5.0", + "desktop_core", + "libc", +] + [[package]] name = "quick-xml" version = "0.37.5" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index 21835c61585..540780ac2a9 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator", "autotype"] +members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator", "autotype", "process_isolation"] [workspace.package] version = "0.0.0" @@ -20,6 +20,7 @@ byteorder = "=1.5.0" bytes = "=1.10.1" cbc = "=0.1.2" core-foundation = "=0.10.0" +ctor = "=0.5.0" dirs = "=6.0.0" ed25519 = "=2.2.3" embed_plist = "=1.2.2" diff --git a/apps/desktop/desktop_native/build.js b/apps/desktop/desktop_native/build.js index 2edd0e89616..9c90b555189 100644 --- a/apps/desktop/desktop_native/build.js +++ b/apps/desktop/desktop_native/build.js @@ -45,6 +45,19 @@ function buildProxyBin(target, release = true) { } } +function buildProcessIsolation() { + if (process.platform !== "linux") { + return; + } + + child_process.execSync(`cargo build --release`, { + stdio: 'inherit', + cwd: path.join(__dirname, "process_isolation") + }); + + fs.copyFileSync(path.join(__dirname, "target", "release", "libprocess_isolation.so"), path.join(__dirname, "dist", `libprocess_isolation.so`)); +} + function installTarget(target) { child_process.execSync(`rustup target add ${target}`, { stdio: 'inherit', cwd: __dirname }); } @@ -53,6 +66,7 @@ if (!crossPlatform && !target) { console.log(`Building native modules in ${mode} mode for the native architecture`); buildNapiModule(false, mode === "release"); buildProxyBin(false, mode === "release"); + buildProcessIsolation(); return; } @@ -61,6 +75,7 @@ if (target) { installTarget(target); buildNapiModule(target, mode === "release"); buildProxyBin(target, mode === "release"); + buildProcessIsolation(); return; } @@ -78,4 +93,5 @@ platformTargets.forEach(([target, _]) => { installTarget(target); buildNapiModule(target); buildProxyBin(target); + buildProcessIsolation(); }); diff --git a/apps/desktop/desktop_native/process_isolation/Cargo.toml b/apps/desktop/desktop_native/process_isolation/Cargo.toml new file mode 100644 index 00000000000..045f84fe26a --- /dev/null +++ b/apps/desktop/desktop_native/process_isolation/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "process_isolation" +edition = { workspace = true } +license = { workspace = true } +version = { workspace = true } +publish = { workspace = true } + +[lib] +crate-type = ["cdylib"] + +[dependencies] +ctor.workspace = true +libc = { workspace = true } +desktop_core = { path = "../core" } diff --git a/apps/desktop/process_isolation/src/lib.rs b/apps/desktop/desktop_native/process_isolation/src/lib.rs similarity index 68% rename from apps/desktop/process_isolation/src/lib.rs rename to apps/desktop/desktop_native/process_isolation/src/lib.rs index 4241d9fe569..bbd59d61e88 100644 --- a/apps/desktop/process_isolation/src/lib.rs +++ b/apps/desktop/desktop_native/process_isolation/src/lib.rs @@ -3,14 +3,13 @@ //! On Linux, this is PR_SET_DUMPABLE to prevent debuggers from attaching, the env //! from being read and the memory from being stolen. -use std::ffi::{c_char, c_void}; +use std::{ffi::c_char, sync::LazyLock}; +use desktop_core::process_isolation; -mod isolate; - -#[link(name = "dl")] -unsafe extern "C" { - unsafe fn dlsym(handle: *const c_void, symbol: *const c_char) -> *const c_void; -} +static ORIGINAL_UNSETENV: LazyLock i32> = + LazyLock::new(|| unsafe { + std::mem::transmute(libc::dlsym(libc::RTLD_NEXT, c"unsetenv".as_ptr())) + }); /// Hooks unsetenv to fix a bug in zypak-wrapper. /// Zypak unsets the env in Flatpak as a side-effect, which means that only the top level @@ -18,9 +17,9 @@ unsafe extern "C" { #[unsafe(no_mangle)] unsafe extern "C" fn unsetenv(name: *const c_char) -> i32 { unsafe { - let name_str = std::ffi::CStr::from_ptr(name).to_str().unwrap(); - let original_unsetenv: unsafe extern "C" fn(*const c_char) -> i32 = - std::mem::transmute(dlsym(libc::RTLD_NEXT, c"unsetenv".as_ptr())); + let Ok(name_str) = std::ffi::CStr::from_ptr(name).to_str() else { + return ORIGINAL_UNSETENV(name); + }; if name_str == "LD_PRELOAD" { // This env variable is provided by the flatpak configuration @@ -29,7 +28,7 @@ unsafe extern "C" fn unsetenv(name: *const c_char) -> i32 { return 0; } - original_unsetenv(name) + ORIGINAL_UNSETENV(name) } } @@ -39,7 +38,7 @@ fn preload_init() { let pid = unsafe { libc::getpid() }; unsafe { println!("[Process Isolation] Enabling memory security for process {pid}"); - isolate::isolate_process(); - isolate::disable_coredumps(); + process_isolation::disable_memory_access(); + process_isolation::disable_coredumps(); } } diff --git a/apps/desktop/process_isolation/test_isolation.sh b/apps/desktop/desktop_native/process_isolation/test_isolation.sh similarity index 100% rename from apps/desktop/process_isolation/test_isolation.sh rename to apps/desktop/desktop_native/process_isolation/test_isolation.sh diff --git a/apps/desktop/process_isolation/Cargo.lock b/apps/desktop/process_isolation/Cargo.lock deleted file mode 100644 index 35de8a22214..00000000000 --- a/apps/desktop/process_isolation/Cargo.lock +++ /dev/null @@ -1,48 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "ctor" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67773048316103656a637612c4a62477603b777d91d9c62ff2290f9cde178fdb" -dependencies = [ - "ctor-proc-macro", - "dtor", -] - -[[package]] -name = "ctor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2931af7e13dc045d8e9d26afccc6fa115d64e115c9c84b1166288b46f6782c2" - -[[package]] -name = "dtor" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e58a0764cddb55ab28955347b45be00ade43d4d6f3ba4bf3dc354e4ec9432934" -dependencies = [ - "dtor-proc-macro", -] - -[[package]] -name = "dtor-proc-macro" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" - -[[package]] -name = "libc" -version = "0.2.175" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" - -[[package]] -name = "memory-security" -version = "0.1.0" -dependencies = [ - "ctor", - "libc", -] diff --git a/apps/desktop/process_isolation/Cargo.toml b/apps/desktop/process_isolation/Cargo.toml deleted file mode 100644 index 889332fbe2f..00000000000 --- a/apps/desktop/process_isolation/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "process-isolation" -version = "0.1.0" -edition = "2024" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -ctor = "0.5.0" -libc = "0.2.175" diff --git a/apps/desktop/process_isolation/src/isolate.rs b/apps/desktop/process_isolation/src/isolate.rs deleted file mode 100644 index 7d97aa6b09b..00000000000 --- a/apps/desktop/process_isolation/src/isolate.rs +++ /dev/null @@ -1,36 +0,0 @@ -#[cfg(target_env = "gnu")] -use libc::c_uint; -use libc::{self, c_int}; - -/// RLIMIT_CORE is the maximum size of a core dump file. Setting both to 0 disables core dumps, on crashes -/// https://github.com/torvalds/linux/blob/1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0/include/uapi/asm-generic/resource.h#L20 -#[cfg(target_env = "musl")] -const RLIMIT_CORE: c_int = 4; -#[cfg(target_env = "gnu")] -const RLIMIT_CORE: c_uint = 4; - -/// PR_SET_DUMPABLE makes it so no other running process (root or same user) can dump the memory of this process -/// or attach a debugger to it. -/// https://github.com/torvalds/linux/blob/a38297e3fb012ddfa7ce0321a7e5a8daeb1872b6/include/uapi/linux/prctl.h#L14 -const PR_SET_DUMPABLE: c_int = 4; - -/// Prevents a process crash from creating a coredump on disk -pub(crate) fn disable_coredumps() { - let rlimit = libc::rlimit { - rlim_cur: 0, - rlim_max: 0, - }; - - if unsafe { libc::setrlimit(RLIMIT_CORE, &rlimit) } != 0 { - let e = std::io::Error::last_os_error(); - eprintln!("[Process Isolation] Failed to disable core dumping: {e}"); - } -} - -/// Prevents other process from accessing env, memory, attaching debugger -pub(crate) fn isolate_process() { - if unsafe { libc::prctl(PR_SET_DUMPABLE, 0) } != 0 { - let e = std::io::Error::last_os_error(); - eprintln!("[Process Isolation] Failed to disable memory dumping: {e}"); - } -}