mirror of
https://github.com/safing/portmaster.git
synced 2026-05-20 20:40:36 +00:00
fix(tauri): harden UI process restart path resolution and avoid exit on relaunch failure
This fixes Linux-related issue when UI process do not start automatically after upgrade. - replace direct current_exe relaunch usage with verified launch program resolution - consider both current_exe and argv0, but only accept verified launchable file paths - fail relaunch with explicit error when no safe executable path is available - in reconnect flow, exit current UI only if relaunch spawn succeeds - if relaunch request fails, keep current UI process running and continue normal startup https://github.com/safing/portmaster-shadow/issues/40
This commit is contained in:
@@ -66,11 +66,16 @@ impl portmaster::Handler for WsHandler {
|
||||
// relaunch the UI process now that the core is reachable again.
|
||||
if self.handle.portmaster().consume_restart_ui_proc_requested() {
|
||||
info!("restart-ui-process pending, relaunching UI process");
|
||||
if let Err(err) = relaunch::request_ui_relaunch() {
|
||||
error!("failed to relaunch UI process after upgrade: {}", err);
|
||||
match relaunch::request_ui_relaunch() {
|
||||
Ok(()) => {
|
||||
self.handle.exit(0);
|
||||
return;
|
||||
}
|
||||
Err(err) => {
|
||||
error!("failed to relaunch UI process after upgrade: {}", err);
|
||||
error!("continuing with current UI process");
|
||||
}
|
||||
}
|
||||
self.handle.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// we successfully connected to Portmaster. Set is_first_connect to false
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{
|
||||
ffi::OsString,
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
thread,
|
||||
time::Duration,
|
||||
@@ -11,6 +12,54 @@ const UI_RELAUNCH_HELPER_ENV: &str = "PORTMASTER_UI_RELAUNCH_HELPER";
|
||||
const RELAUNCH_RETRY_COUNT: usize = 40;
|
||||
const RELAUNCH_RETRY_DELAY: Duration = Duration::from_millis(500);
|
||||
|
||||
fn current_process_argv0() -> Option<OsString> {
|
||||
std::env::args_os().next()
|
||||
}
|
||||
|
||||
fn is_usable_launch_program(program: &OsString) -> bool {
|
||||
let path = Path::new(program);
|
||||
|
||||
// Fail closed for command-only values (for example, "portmaster"): we cannot
|
||||
// verify where they resolve to, so do not use them for relaunch.
|
||||
if !path.is_absolute() && path.components().count() <= 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !path.exists() || !path.is_file() {
|
||||
return false;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
|
||||
if let Ok(meta) = std::fs::metadata(path) {
|
||||
return meta.permissions().mode() & 0o111 != 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_launch_program() -> Result<OsString, String> {
|
||||
let current_exe = std::env::current_exe().ok().map(|p| p.into_os_string());
|
||||
let argv0 = current_process_argv0();
|
||||
|
||||
if let Some(program) = current_exe.as_ref().filter(|p| is_usable_launch_program(p)) {
|
||||
return Ok(program.clone());
|
||||
}
|
||||
|
||||
if let Some(program) = argv0.as_ref().filter(|p| is_usable_launch_program(p)) {
|
||||
return Ok(program.clone());
|
||||
}
|
||||
|
||||
Err("failed to determine relaunch executable: no verified launchable file path from current_exe or argv0".to_string())
|
||||
}
|
||||
|
||||
fn current_process_args() -> Vec<OsString> {
|
||||
std::env::args_os()
|
||||
.skip(1)
|
||||
@@ -23,8 +72,7 @@ fn current_process_args() -> Vec<OsString> {
|
||||
}
|
||||
|
||||
pub fn request_ui_relaunch() -> Result<(), String> {
|
||||
let exe = std::env::current_exe()
|
||||
.map_err(|err| format!("failed to get current executable path: {}", err))?;
|
||||
let exe = resolve_launch_program()?;
|
||||
let args = current_process_args();
|
||||
|
||||
let mut cmd = Command::new(&exe);
|
||||
@@ -53,8 +101,7 @@ pub fn run_relaunch_helper_if_requested() {
|
||||
}
|
||||
|
||||
fn run_relaunch_helper() -> Result<(), String> {
|
||||
let exe = std::env::current_exe()
|
||||
.map_err(|err| format!("failed to get current executable path in relaunch helper: {}", err))?;
|
||||
let exe = resolve_launch_program()?;
|
||||
let args = current_process_args();
|
||||
|
||||
debug!("[tauri] relaunch helper started");
|
||||
|
||||
Reference in New Issue
Block a user