platform: Add flag for testing validity of executable in root remote

This commit is contained in:
Vicki Pfau 2025-02-25 21:44:58 -08:00
parent ecb6026370
commit af61f76b89
2 changed files with 81 additions and 16 deletions

View file

@ -603,7 +603,7 @@ async fn create_config_interfaces(
} }
if let Some(config) = config.update_bios.as_ref() { if let Some(config) = config.update_bios.as_ref() {
match config.is_valid().await { match config.is_valid(true).await {
Ok(true) => { Ok(true) => {
object_server.at(MANAGER_PATH, update_bios).await?; object_server.at(MANAGER_PATH, update_bios).await?;
} }
@ -613,7 +613,7 @@ async fn create_config_interfaces(
} }
if let Some(config) = config.update_dock.as_ref() { if let Some(config) = config.update_dock.as_ref() {
match config.is_valid().await { match config.is_valid(true).await {
Ok(true) => { Ok(true) => {
object_server.at(MANAGER_PATH, update_dock).await?; object_server.at(MANAGER_PATH, update_dock).await?;
} }

View file

@ -9,6 +9,8 @@ use anyhow::Result;
use nix::errno::Errno; use nix::errno::Errno;
use nix::unistd::{access, AccessFlags}; use nix::unistd::{access, AccessFlags};
use serde::Deserialize; use serde::Deserialize;
use std::io::ErrorKind;
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf; use std::path::PathBuf;
use tokio::fs::{metadata, read_to_string}; use tokio::fs::{metadata, read_to_string};
#[cfg(not(test))] #[cfg(not(test))]
@ -50,18 +52,29 @@ pub(crate) struct ScriptConfig {
} }
impl ScriptConfig { impl ScriptConfig {
pub(crate) async fn is_valid(&self) -> Result<bool> { pub(crate) async fn is_valid(&self, root: bool) -> Result<bool> {
let script = self.script.clone(); let meta = match metadata(&self.script).await {
if !spawn_blocking(move || match access(&script, AccessFlags::X_OK) { Ok(meta) => meta,
Ok(()) => Ok(true), Err(e) if [ErrorKind::NotFound, ErrorKind::PermissionDenied].contains(&e.kind()) => {
Err(Errno::ENOENT | Errno::EACCES) => Ok(false), return Ok(false)
Err(e) => Err(e), }
}) Err(e) => return Err(e.into()),
.await?? };
{ if !meta.is_file() {
return Ok(false); return Ok(false);
} }
if !metadata(&self.script).await?.is_file() { if root {
let script = self.script.clone();
if !spawn_blocking(move || match access(&script, AccessFlags::X_OK) {
Ok(()) => Ok(true),
Err(Errno::ENOENT | Errno::EACCES) => Ok(false),
Err(e) => Err(e),
})
.await??
{
return Ok(false);
}
} else if (meta.mode() & 0o111) == 0 {
return Ok(false); return Ok(false);
} }
Ok(true) Ok(true)
@ -169,7 +182,12 @@ mod test {
#[tokio::test] #[tokio::test]
async fn script_config_valid_no_path() { async fn script_config_valid_no_path() {
assert!(!ScriptConfig::default().is_valid().await.unwrap()); assert!(!ScriptConfig::default().is_valid(false).await.unwrap());
}
#[tokio::test]
async fn script_config_valid_root_no_path() {
assert!(!ScriptConfig::default().is_valid(true).await.unwrap());
} }
#[tokio::test] #[tokio::test]
@ -178,7 +196,18 @@ mod test {
script: PathBuf::from("/"), script: PathBuf::from("/"),
script_args: Vec::new(), script_args: Vec::new(),
} }
.is_valid() .is_valid(false)
.await
.unwrap());
}
#[tokio::test]
async fn script_config_valid_root_directory() {
assert!(!ScriptConfig {
script: PathBuf::from("/"),
script_args: Vec::new(),
}
.is_valid(true)
.await .await
.unwrap()); .unwrap());
} }
@ -196,7 +225,25 @@ mod test {
script: exe_path, script: exe_path,
script_args: Vec::new(), script_args: Vec::new(),
} }
.is_valid() .is_valid(false)
.await
.unwrap());
}
#[tokio::test]
async fn script_config_root_valid_noexec() {
let _handle = testing::start();
let exe_path = path("exe");
write(&exe_path, "").await.unwrap();
set_permissions(&exe_path, PermissionsExt::from_mode(0o600))
.await
.unwrap();
assert!(!ScriptConfig {
script: exe_path,
script_args: Vec::new(),
}
.is_valid(true)
.await .await
.unwrap()); .unwrap());
} }
@ -214,7 +261,25 @@ mod test {
script: exe_path, script: exe_path,
script_args: Vec::new(), script_args: Vec::new(),
} }
.is_valid() .is_valid(false)
.await
.unwrap());
}
#[tokio::test]
async fn script_config_root_valid() {
let _handle = testing::start();
let exe_path = path("exe");
write(&exe_path, "").await.unwrap();
set_permissions(&exe_path, PermissionsExt::from_mode(0o700))
.await
.unwrap();
assert!(ScriptConfig {
script: exe_path,
script_args: Vec::new(),
}
.is_valid(true)
.await .await
.unwrap()); .unwrap());
} }