mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-31 03:02:08 +08:00
fix(linux): stage approved cores when installing service
Pass available cores and their SHA-256 digests explicitly during service installation and repair, instead of relying on automatic discovery that can skip untrusted source locations. Preserve the arguments across root, pkexec, and sudo execution paths. Fixes #7995
This commit is contained in:
@@ -8,6 +8,10 @@
|
||||
- 修复 DNS 覆写:空内容报错、初始值覆盖已有设置、已填写字段残留原配置、空字段在高级编辑器中缺失
|
||||
- 修复首次以管理员身份启动后,系统服务因数据目录所有权不符而拒绝启动内核的问题
|
||||
|
||||
**🐧 Linux**
|
||||
|
||||
- Linux 修复安装或修复服务后仍无法启动内核、开启 TUN 模式的问题
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
@@ -583,11 +583,11 @@ fn install_service() -> Result<()> {
|
||||
.iter()
|
||||
.map(|core| service_core_path(core, ".exe"))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
install_windows_service_with_cores(&cores, run_windows_service_installer)
|
||||
install_service_with_cores(&cores, run_windows_service_installer)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn install_windows_service_with_cores(
|
||||
#[cfg(any(target_os = "windows", target_os = "linux", test))]
|
||||
fn install_service_with_cores(
|
||||
cores: &[PathBuf],
|
||||
mut run_installer: impl FnMut(&[std::ffi::OsString]) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
@@ -712,7 +712,15 @@ fn uninstall_service() -> Result<()> {
|
||||
#[cfg(target_os = "linux")]
|
||||
fn install_service() -> Result<()> {
|
||||
logging!(info, Type::Service, "install service");
|
||||
let cores = crate::config::IVerge::VALID_CLASH_CORES
|
||||
.iter()
|
||||
.map(|core| service_core_path(core, ""))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
install_service_with_cores(&cores, run_linux_service_installer)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn run_linux_service_installer(arguments: &[std::ffi::OsString]) -> Result<()> {
|
||||
let install_path = packaged_service_tool_path("clash-verge-service-install", || {
|
||||
Ok(tauri::utils::platform::current_exe()?.with_file_name("clash-verge-service-install"))
|
||||
})?;
|
||||
@@ -723,12 +731,13 @@ fn install_service() -> Result<()> {
|
||||
|
||||
let elevator = crate::utils::help::linux_elevator();
|
||||
let output = if linux_running_as_root() {
|
||||
StdCommand::new(&install_path).output()?
|
||||
StdCommand::new(&install_path).args(arguments).output()?
|
||||
} else {
|
||||
let result = StdCommand::new(&elevator)
|
||||
.arg("--disable-internal-agent")
|
||||
.arg(&install_path)
|
||||
.output()?;
|
||||
let mut elevated = StdCommand::new(&elevator);
|
||||
if elevator.contains("pkexec") {
|
||||
elevated.arg("--disable-internal-agent");
|
||||
}
|
||||
let result = elevated.arg(&install_path).args(arguments).output()?;
|
||||
|
||||
// 如果 pkexec 执行失败,回退到 sudo
|
||||
if !result.status.success() && elevator.contains("pkexec") {
|
||||
@@ -738,7 +747,7 @@ fn install_service() -> Result<()> {
|
||||
"pkexec failed with code {}, falling back to sudo",
|
||||
result.status.code().unwrap_or(-1)
|
||||
);
|
||||
StdCommand::new("sudo").arg(&install_path).output()?
|
||||
StdCommand::new("sudo").arg(&install_path).args(arguments).output()?
|
||||
} else {
|
||||
result
|
||||
}
|
||||
@@ -2243,20 +2252,19 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn windows_service_install_combines_service_and_attested_cores() -> anyhow::Result<()> {
|
||||
fn service_install_combines_service_and_attested_cores() -> anyhow::Result<()> {
|
||||
use std::ffi::OsString;
|
||||
let root = TestDirectory::new("scoop install")?;
|
||||
let root = TestDirectory::new("service install")?;
|
||||
let cores: Vec<_> = crate::config::IVerge::VALID_CLASH_CORES
|
||||
.iter()
|
||||
.map(|name| root.path().join(format!("{name}.exe")))
|
||||
.map(|name| root.path().join(format!("{name}{}", std::env::consts::EXE_SUFFIX)))
|
||||
.collect();
|
||||
for core in &cores {
|
||||
std::fs::write(core, b"abc")?;
|
||||
}
|
||||
let mut calls = Vec::new();
|
||||
super::install_windows_service_with_cores(&cores, |arguments| {
|
||||
super::install_service_with_cores(&cores, |arguments| {
|
||||
calls.push(arguments.to_vec());
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -2275,16 +2283,19 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn windows_service_install_skips_unavailable_cores() -> anyhow::Result<()> {
|
||||
fn service_install_skips_unavailable_cores() -> anyhow::Result<()> {
|
||||
let root = TestDirectory::new("missing-core")?;
|
||||
let core = root.path().join("verge-mihomo.exe");
|
||||
let missing = root.path().join("verge-mihomo-alpha.exe");
|
||||
let core = root
|
||||
.path()
|
||||
.join(format!("verge-mihomo{}", std::env::consts::EXE_SUFFIX));
|
||||
let missing = root
|
||||
.path()
|
||||
.join(format!("verge-mihomo-alpha{}", std::env::consts::EXE_SUFFIX));
|
||||
std::fs::write(&core, b"abc")?;
|
||||
let cores = [core.clone(), missing.clone(), root.path().to_path_buf()];
|
||||
let mut calls = Vec::new();
|
||||
super::install_windows_service_with_cores(&cores, |arguments| {
|
||||
super::install_service_with_cores(&cores, |arguments| {
|
||||
calls.push(arguments.to_vec());
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -2293,7 +2304,7 @@ mod tests {
|
||||
assert_eq!(calls[0][0], "--install-service");
|
||||
assert_eq!(calls[0][2], core.as_os_str());
|
||||
|
||||
let error = super::install_windows_service_with_cores(&[missing, root.path().to_path_buf()], |_| {
|
||||
let error = super::install_service_with_cores(&[missing, root.path().to_path_buf()], |_| {
|
||||
panic!("no available core must fail before invoking the installer")
|
||||
})
|
||||
.expect_err("installation requires at least one available core");
|
||||
@@ -2301,14 +2312,15 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn windows_service_install_propagates_installer_failure() -> anyhow::Result<()> {
|
||||
fn service_install_propagates_installer_failure() -> anyhow::Result<()> {
|
||||
let root = TestDirectory::new("install-failure")?;
|
||||
let core = root.path().join("verge-mihomo.exe");
|
||||
let core = root
|
||||
.path()
|
||||
.join(format!("verge-mihomo{}", std::env::consts::EXE_SUFFIX));
|
||||
std::fs::write(&core, b"abc")?;
|
||||
let mut calls = 0;
|
||||
let result = super::install_windows_service_with_cores(std::slice::from_ref(&core), |_| {
|
||||
let result = super::install_service_with_cores(std::slice::from_ref(&core), |_| {
|
||||
calls += 1;
|
||||
bail!("installer failed with exit code 1")
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user