fix(security): add path canonicalization and actionable permission error in install_ollama_from_bundle
This commit is contained in:
parent
fc50fe3102
commit
dffd26a6fd
@ -145,6 +145,8 @@ pub async fn get_audit_log(
|
|||||||
// Security note: the bundled binary's integrity is guaranteed by the CI release pipeline
|
// Security note: the bundled binary's integrity is guaranteed by the CI release pipeline
|
||||||
// which verifies SHA256 checksums against Ollama's published sha256sums.txt before bundling.
|
// which verifies SHA256 checksums against Ollama's published sha256sums.txt before bundling.
|
||||||
// Runtime re-verification is not performed here; the app bundle itself is the trust boundary.
|
// Runtime re-verification is not performed here; the app bundle itself is the trust boundary.
|
||||||
|
// On Unix, writing to /usr/local/bin requires elevated privileges. If the operation fails with
|
||||||
|
// PermissionDenied the caller receives an actionable error message.
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn install_ollama_from_bundle(
|
pub async fn install_ollama_from_bundle(
|
||||||
app: tauri::AppHandle,
|
app: tauri::AppHandle,
|
||||||
@ -153,10 +155,12 @@ pub async fn install_ollama_from_bundle(
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
|
||||||
let resource_path = app
|
let resource_dir = app
|
||||||
.path()
|
.path()
|
||||||
.resource_dir()
|
.resource_dir()
|
||||||
.map_err(|e: tauri::Error| e.to_string())?
|
.map_err(|e: tauri::Error| e.to_string())?;
|
||||||
|
|
||||||
|
let resource_path = resource_dir
|
||||||
.join("ollama")
|
.join("ollama")
|
||||||
.join(if cfg!(windows) { "ollama.exe" } else { "ollama" });
|
.join(if cfg!(windows) { "ollama.exe" } else { "ollama" });
|
||||||
|
|
||||||
@ -164,6 +168,13 @@ pub async fn install_ollama_from_bundle(
|
|||||||
return Err("Bundled Ollama not found in resources".to_string());
|
return Err("Bundled Ollama not found in resources".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Defense-in-depth: verify resolved path stays within the resource directory.
|
||||||
|
let canonical_resource = resource_path.canonicalize().map_err(|e| e.to_string())?;
|
||||||
|
let canonical_dir = resource_dir.canonicalize().map_err(|e| e.to_string())?;
|
||||||
|
if !canonical_resource.starts_with(&canonical_dir) {
|
||||||
|
return Err("Resource path validation failed".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let install_path = PathBuf::from("/usr/local/bin/ollama");
|
let install_path = PathBuf::from("/usr/local/bin/ollama");
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -179,7 +190,18 @@ pub async fn install_ollama_from_bundle(
|
|||||||
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
|
fs::create_dir_all(parent).map_err(|e| e.to_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::copy(&resource_path, &install_path).map_err(|e| e.to_string())?;
|
fs::copy(&resource_path, &install_path).map_err(|e| {
|
||||||
|
if e.kind() == std::io::ErrorKind::PermissionDenied {
|
||||||
|
format!(
|
||||||
|
"Permission denied writing to {}. On Linux, re-run the app with elevated \
|
||||||
|
privileges or install manually: sudo cp \"{}\" /usr/local/bin/ollama",
|
||||||
|
install_path.display(),
|
||||||
|
resource_path.display()
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
e.to_string()
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user