fix: wipe credentials in the connect path and keep release builds out of dumps and debuggers
- Credential callbacks (SecretFn) now return Zeroizing<String>, as do the
session-only/pending caches they read and the RDP client's password,
so Nexus's own copies are wiped; a plain String copy is made only
where a library API needs one (SSH password auth, IRC, VNC, CredSSP).
- Release builds disable core dumps (RLIMIT_CORE 0) and, on Linux, mark
the process non-dumpable (PR_SET_DUMPABLE 0), which also blocks ptrace
attach and /proc/<pid>/mem reads by other processes of the same user.
Debug builds are unchanged so they stay debuggable. Verified on the
release binary: core limit 0, /proc/<pid>/{environ,mem} root-owned and
unreadable, local shells (including cwd capture) still work.
Closes the remaining parts of SEC-20261012-007 that the app controls;
egui's internal text buffers remain outside its reach.
This commit is contained in:
@@ -28,3 +28,6 @@ arboard = "3.6.1"
|
||||
|
||||
[build-dependencies]
|
||||
winresource = "0.1"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
@@ -33,6 +33,7 @@ use nexus_core::service::Service;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
harden_process();
|
||||
// A panic on a worker thread (a session's reader, a transfer) ends only that thread; say so in
|
||||
// the UI rather than letting the session just stop.
|
||||
let default_hook = std::panic::take_hook();
|
||||
@@ -161,3 +162,20 @@ fn init_logging(data_dir: &std::path::Path) {
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn,nexus_terminal=info,nexus_core=info"));
|
||||
let _ = tracing_subscriber::registry().with(filter).with(file).with(stderr).try_init();
|
||||
}
|
||||
|
||||
/// Release builds keep secrets out of core dumps and away from same-user debuggers: no core
|
||||
/// files, and on Linux the process is non-dumpable (also blocks ptrace attach by other processes
|
||||
/// of the same user). Debug builds skip this so they can still be debugged.
|
||||
fn harden_process() {
|
||||
if cfg!(debug_assertions) {
|
||||
return;
|
||||
}
|
||||
#[cfg(unix)]
|
||||
// SAFETY: plain syscalls on this process with valid arguments; failure is harmless.
|
||||
unsafe {
|
||||
let none = libc::rlimit { rlim_cur: 0, rlim_max: 0 };
|
||||
libc::setrlimit(libc::RLIMIT_CORE, &none);
|
||||
#[cfg(target_os = "linux")]
|
||||
libc::prctl(libc::PR_SET_DUMPABLE, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user