Fix 29 audit findings across all severity tiers
This commit is contained in:
@@ -42,7 +42,6 @@ pub enum LaunchMethod {
|
||||
/// Extract-and-run fallback (APPIMAGE_EXTRACT_AND_RUN=1)
|
||||
ExtractAndRun,
|
||||
/// Via firejail sandbox
|
||||
#[allow(dead_code)]
|
||||
Sandboxed,
|
||||
}
|
||||
|
||||
@@ -68,7 +67,6 @@ pub enum LaunchResult {
|
||||
Crashed {
|
||||
exit_code: Option<i32>,
|
||||
stderr: String,
|
||||
#[allow(dead_code)]
|
||||
method: LaunchMethod,
|
||||
},
|
||||
/// Failed to launch.
|
||||
@@ -99,6 +97,22 @@ pub fn launch_appimage(
|
||||
}
|
||||
};
|
||||
|
||||
// Override with sandboxed launch if the user enabled firejail for this app
|
||||
let method = if has_firejail() {
|
||||
let sandbox = db
|
||||
.get_appimage_by_id(record_id)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|r| r.sandbox_mode);
|
||||
if sandbox.as_deref() == Some("firejail") {
|
||||
LaunchMethod::Sandboxed
|
||||
} else {
|
||||
method
|
||||
}
|
||||
} else {
|
||||
method
|
||||
};
|
||||
|
||||
let result = execute_appimage(appimage_path, &method, extra_args, extra_env);
|
||||
|
||||
// Record the launch event regardless of success
|
||||
@@ -163,42 +177,38 @@ fn execute_appimage(
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
// Capture stderr to detect crash messages, stdin detached
|
||||
// Detach stdin, pipe stderr so we can capture crash messages
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stderr(Stdio::piped());
|
||||
|
||||
match cmd.spawn() {
|
||||
Ok(mut child) => {
|
||||
// Brief wait to detect immediate crashes (e.g. missing Qt plugins)
|
||||
std::thread::sleep(std::time::Duration::from_millis(1500));
|
||||
// Give the process a brief moment to fail on immediate errors
|
||||
// (missing libs, exec format errors, Qt plugin failures, etc.)
|
||||
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
// Process already exited - it crashed
|
||||
let stderr = child
|
||||
.stderr
|
||||
.take()
|
||||
.and_then(|mut err| {
|
||||
let mut buf = String::new();
|
||||
use std::io::Read;
|
||||
err.read_to_string(&mut buf).ok()?;
|
||||
Some(buf)
|
||||
})
|
||||
.unwrap_or_default();
|
||||
// Already exited - immediate crash. Read stderr for details.
|
||||
let stderr_text = child.stderr.take().map(|mut pipe| {
|
||||
let mut buf = String::new();
|
||||
use std::io::Read;
|
||||
// Read with a size cap to avoid huge allocations
|
||||
let mut limited = (&mut pipe).take(64 * 1024);
|
||||
let _ = limited.read_to_string(&mut buf);
|
||||
buf
|
||||
}).unwrap_or_default();
|
||||
|
||||
LaunchResult::Crashed {
|
||||
exit_code: status.code(),
|
||||
stderr,
|
||||
stderr: stderr_text,
|
||||
method: method.clone(),
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
// Still running - success
|
||||
LaunchResult::Started {
|
||||
child,
|
||||
method: method.clone(),
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Can't check status, assume it's running
|
||||
_ => {
|
||||
// Still running after 150ms - drop the stderr pipe so the
|
||||
// child process won't block if it fills the pipe buffer.
|
||||
drop(child.stderr.take());
|
||||
LaunchResult::Started {
|
||||
child,
|
||||
method: method.clone(),
|
||||
@@ -211,11 +221,38 @@ fn execute_appimage(
|
||||
}
|
||||
|
||||
/// Parse a launch_args string from the database into a Vec of individual arguments.
|
||||
/// Splits on whitespace; returns an empty Vec if the input is None or empty.
|
||||
#[allow(dead_code)]
|
||||
/// Parse launch arguments with basic quote support.
|
||||
/// Splits on whitespace, respecting double-quoted strings.
|
||||
/// Returns an empty Vec if the input is None or empty.
|
||||
pub fn parse_launch_args(args: Option<&str>) -> Vec<String> {
|
||||
args.map(|s| s.split_whitespace().map(String::from).collect())
|
||||
.unwrap_or_default()
|
||||
let Some(s) = args else {
|
||||
return Vec::new();
|
||||
};
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut result = Vec::new();
|
||||
let mut current = String::new();
|
||||
let mut in_quotes = false;
|
||||
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'"' => in_quotes = !in_quotes,
|
||||
' ' | '\t' if !in_quotes => {
|
||||
if !current.is_empty() {
|
||||
result.push(std::mem::take(&mut current));
|
||||
}
|
||||
}
|
||||
_ => current.push(c),
|
||||
}
|
||||
}
|
||||
if !current.is_empty() {
|
||||
result.push(current);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Check if firejail is available for sandboxed launches.
|
||||
|
||||
Reference in New Issue
Block a user