fix: Add trusted_shell_script_arg for internal scripts
- shell_script_arg blocks $( and backticks for user input safety - trusted_shell_script_arg allows these for internal installer scripts - Internal scripts need shell features like command substitution - Updated bootstrap, installer, facade, and llm modules
This commit is contained in:
parent
db267714ca
commit
00acf1c76e
5 changed files with 41 additions and 9 deletions
|
|
@ -38,7 +38,7 @@ fn safe_pgrep(args: &[&str]) -> Option<std::process::Output> {
|
||||||
fn safe_sh_command(script: &str) -> Option<std::process::Output> {
|
fn safe_sh_command(script: &str) -> Option<std::process::Output> {
|
||||||
SafeCommand::new("sh")
|
SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(script))
|
.and_then(|c| c.trusted_shell_script_arg(script))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|cmd| cmd.execute().ok())
|
.and_then(|cmd| cmd.execute().ok())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1065,7 +1065,7 @@ Store credentials in Vault:
|
||||||
trace!("Executing command: {}", rendered_cmd);
|
trace!("Executing command: {}", rendered_cmd);
|
||||||
let output = SafeCommand::new("bash")
|
let output = SafeCommand::new("bash")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(&rendered_cmd))
|
.and_then(|c| c.trusted_shell_script_arg(&rendered_cmd))
|
||||||
.and_then(|c| c.working_dir(&bin_path))
|
.and_then(|c| c.working_dir(&bin_path))
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to build bash command: {}", e))?
|
.map_err(|e| anyhow::anyhow!("Failed to build bash command: {}", e))?
|
||||||
.execute()
|
.execute()
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ fn safe_nvcc_version() -> Option<std::process::Output> {
|
||||||
fn safe_sh_command(script: &str) -> Option<std::process::Output> {
|
fn safe_sh_command(script: &str) -> Option<std::process::Output> {
|
||||||
SafeCommand::new("sh")
|
SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(script))
|
.and_then(|c| c.trusted_shell_script_arg(script))
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|cmd| cmd.execute().ok())
|
.and_then(|cmd| cmd.execute().ok())
|
||||||
}
|
}
|
||||||
|
|
@ -1112,7 +1112,7 @@ EOF"#.to_string(),
|
||||||
trace!("[START] Working dir: {}", bin_path.display());
|
trace!("[START] Working dir: {}", bin_path.display());
|
||||||
let child = SafeCommand::new("sh")
|
let child = SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(&rendered_cmd))
|
.and_then(|c| c.trusted_shell_script_arg(&rendered_cmd))
|
||||||
.and_then(|c| c.working_dir(&bin_path))
|
.and_then(|c| c.working_dir(&bin_path))
|
||||||
.and_then(|cmd| cmd.spawn_with_envs(&evaluated_envs))
|
.and_then(|cmd| cmd.spawn_with_envs(&evaluated_envs))
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to spawn process: {}", e));
|
.map_err(|e| anyhow::anyhow!("Failed to spawn process: {}", e));
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ pub async fn ensure_llama_servers_running(
|
||||||
|
|
||||||
let pkill_result = SafeCommand::new("sh")
|
let pkill_result = SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg("pkill llama-server -9; true"));
|
.and_then(|c| c.trusted_shell_script_arg("pkill llama-server -9; true"));
|
||||||
|
|
||||||
match pkill_result {
|
match pkill_result {
|
||||||
Ok(cmd) => {
|
Ok(cmd) => {
|
||||||
|
|
@ -366,7 +366,7 @@ pub fn start_llm_server(
|
||||||
);
|
);
|
||||||
let cmd = SafeCommand::new("cmd")
|
let cmd = SafeCommand::new("cmd")
|
||||||
.and_then(|c| c.arg("/C"))
|
.and_then(|c| c.arg("/C"))
|
||||||
.and_then(|c| c.shell_script_arg(&cmd_arg))
|
.and_then(|c| c.trusted_shell_script_arg(&cmd_arg))
|
||||||
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -378,7 +378,7 @@ pub fn start_llm_server(
|
||||||
);
|
);
|
||||||
let cmd = SafeCommand::new("sh")
|
let cmd = SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(&cmd_arg))
|
.and_then(|c| c.trusted_shell_script_arg(&cmd_arg))
|
||||||
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
}
|
}
|
||||||
|
|
@ -410,7 +410,7 @@ pub async fn start_embedding_server(
|
||||||
);
|
);
|
||||||
let cmd = SafeCommand::new("cmd")
|
let cmd = SafeCommand::new("cmd")
|
||||||
.and_then(|c| c.arg("/c"))
|
.and_then(|c| c.arg("/c"))
|
||||||
.and_then(|c| c.shell_script_arg(&cmd_arg))
|
.and_then(|c| c.trusted_shell_script_arg(&cmd_arg))
|
||||||
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -422,7 +422,7 @@ pub async fn start_embedding_server(
|
||||||
);
|
);
|
||||||
let cmd = SafeCommand::new("sh")
|
let cmd = SafeCommand::new("sh")
|
||||||
.and_then(|c| c.arg("-c"))
|
.and_then(|c| c.arg("-c"))
|
||||||
.and_then(|c| c.shell_script_arg(&cmd_arg))
|
.and_then(|c| c.trusted_shell_script_arg(&cmd_arg))
|
||||||
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
.map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
cmd.execute().map_err(|e| Box::new(std::io::Error::new(std::io::ErrorKind::Other, e.to_string())) as Box<dyn std::error::Error + Send + Sync>)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,38 @@ impl SafeCommand {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trusted_shell_script_arg(mut self, script: &str) -> Result<Self, CommandGuardError> {
|
||||||
|
let is_unix_shell = self.command == "bash" || self.command == "sh";
|
||||||
|
let is_windows_cmd = self.command == "cmd";
|
||||||
|
if !is_unix_shell && !is_windows_cmd {
|
||||||
|
return Err(CommandGuardError::InvalidArgument(
|
||||||
|
"trusted_shell_script_arg only allowed for bash/sh/cmd commands".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let valid_flag = if is_unix_shell {
|
||||||
|
self.args.last().is_some_and(|a| a == "-c")
|
||||||
|
} else {
|
||||||
|
self.args.last().is_some_and(|a| a == "/C" || a == "/c")
|
||||||
|
};
|
||||||
|
if !valid_flag {
|
||||||
|
return Err(CommandGuardError::InvalidArgument(
|
||||||
|
"trusted_shell_script_arg requires -c (unix) or /C (windows) flag to be set first".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if script.is_empty() {
|
||||||
|
return Err(CommandGuardError::InvalidArgument(
|
||||||
|
"Empty script".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if script.len() > 16384 {
|
||||||
|
return Err(CommandGuardError::InvalidArgument(
|
||||||
|
"Script too long".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
self.args.push(script.to_string());
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn args(mut self, args: &[&str]) -> Result<Self, CommandGuardError> {
|
pub fn args(mut self, args: &[&str]) -> Result<Self, CommandGuardError> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
validate_argument(arg)?;
|
validate_argument(arg)?;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue