-
Notifications
You must be signed in to change notification settings - Fork 103
Replace .unwrap() with proper error handling in run() #689
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| use anyhow::{Result, anyhow}; | ||
| use anyhow::{Context, Result, anyhow}; | ||
| use clap::Parser; | ||
| use litebox::fs::{FileSystem as _, Mode}; | ||
| use litebox_platform_multiplex::Platform; | ||
|
|
@@ -92,11 +92,15 @@ fn mmapped_file_data(path: impl AsRef<Path>) -> Result<&'static [u8]> { | |
|
|
||
| /// Run Linux programs with LiteBox on unmodified Linux | ||
| /// | ||
| /// # Errors | ||
| /// | ||
| /// Returns an error if the program path cannot be resolved, directories along the path are | ||
| /// inaccessible, or the initial filesystem cannot be set up. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Can panic if any particulars of the environment are not set up as expected. Ideally, would not | ||
| /// panic. If it does actually panic, then ping the authors of LiteBox, and likely a better error | ||
| /// message could be thrown instead. | ||
| /// May still panic if internal filesystem operations (e.g., in-memory mkdir/chown/open) or | ||
| /// syscall rewriting fail unexpectedly. | ||
| pub fn run(cli_args: CliArgs) -> Result<()> { | ||
| if !cli_args.insert_files.is_empty() { | ||
| unimplemented!( | ||
|
|
@@ -108,20 +112,21 @@ pub fn run(cli_args: CliArgs) -> Result<()> { | |
| Vec<(litebox::fs::Mode, u32)>, | ||
| alloc::borrow::Cow<'static, [u8]>, | ||
| ) = { | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])).unwrap(); | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])) | ||
| .with_context(|| format!("Could not resolve absolute path for program '{}'", &cli_args.program_and_arguments[0]))?; | ||
| let ancestors: Vec<_> = prog.ancestors().collect(); | ||
| let modes: Vec<_> = ancestors | ||
| let modes: Result<Vec<_>> = ancestors | ||
| .into_iter() | ||
| .rev() | ||
| .skip(1) | ||
| .map(|path| { | ||
| let metadata = path.metadata().unwrap(); | ||
| ( | ||
| litebox::fs::Mode::from_bits(metadata.st_mode()).unwrap(), | ||
| metadata.st_uid(), | ||
| ) | ||
| let metadata = path.metadata() | ||
| .with_context(|| format!("Could not read metadata for '{}'. Ensure the path exists and is accessible.", path.display()))?; | ||
| let mode = litebox::fs::Mode::from_bits_truncate(metadata.st_mode()); | ||
| Ok((mode, metadata.st_uid())) | ||
| }) | ||
| .collect(); | ||
| let modes = modes?; | ||
| let data = mmapped_file_data(prog)?; | ||
| let data = if cli_args.rewrite_syscalls { | ||
| litebox_syscall_rewriter::hook_syscalls_in_elf(data, None) | ||
|
|
@@ -152,7 +157,8 @@ pub fn run(cli_args: CliArgs) -> Result<()> { | |
| let litebox = shim_builder.litebox(); | ||
| let initial_file_system = { | ||
| let mut in_mem = litebox::fs::in_mem::FileSystem::new(litebox); | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])).unwrap(); | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])) | ||
| .with_context(|| format!("Could not resolve absolute path for program '{}'", &cli_args.program_and_arguments[0]))?; | ||
|
Comment on lines
+160
to
+161
|
||
| let ancestors: Vec<_> = prog.ancestors().collect(); | ||
| let mut prev_user = 0; | ||
| for (path, &mode_and_user) in ancestors | ||
|
|
@@ -254,7 +260,8 @@ pub fn run(cli_args: CliArgs) -> Result<()> { | |
| }; | ||
|
|
||
| // We need to get the file path before enabling seccomp | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])).unwrap(); | ||
| let prog = std::path::absolute(Path::new(&cli_args.program_and_arguments[0])) | ||
| .with_context(|| format!("Could not resolve absolute path for program '{}'", &cli_args.program_and_arguments[0]))?; | ||
| let prog_path = prog.to_str().ok_or_else(|| { | ||
| anyhow!( | ||
| "Could not convert program path {:?} to a string", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT license. | ||
|
|
||
| //! Regression tests for error handling in the runner (see #650). | ||
| //! | ||
| //! These tests verify that the runner produces clear error messages instead | ||
| //! of panicking when given invalid inputs. | ||
|
|
||
| use std::process::Command; | ||
|
|
||
| /// Get the path to the litebox_runner_linux_userland binary. | ||
| fn runner_binary() -> String { | ||
| std::env::var("NEXTEST_BIN_EXE_litebox_runner_linux_userland") | ||
| .unwrap_or_else(|_| env!("CARGO_BIN_EXE_litebox_runner_linux_userland").to_string()) | ||
| } | ||
|
|
||
| /// Regression test for #650: running with a nonexistent program path should | ||
| /// produce a clear, contextual error message instead of panicking. | ||
| #[test] | ||
| fn test_nonexistent_program_returns_error_not_panic() { | ||
| let output = Command::new(runner_binary()) | ||
| .arg("/nonexistent/path/to/program") | ||
| .output() | ||
| .expect("Failed to execute runner binary"); | ||
|
|
||
| // The process should fail (non-zero exit code) | ||
| assert!( | ||
| !output.status.success(), | ||
| "Expected runner to fail for nonexistent program, but it succeeded" | ||
| ); | ||
|
|
||
| let stderr = String::from_utf8_lossy(&output.stderr); | ||
|
|
||
| // It should NOT contain a panic message | ||
| assert!( | ||
| !stderr.contains("panicked at"), | ||
| "Runner panicked instead of returning an error.\nStderr: {stderr}" | ||
| ); | ||
|
|
||
| // It SHOULD contain a contextual error message about the path | ||
| assert!( | ||
| stderr.contains("Could not resolve absolute path") | ||
| || stderr.contains("Could not read metadata"), | ||
| "Expected a contextual error message about path resolution or metadata, \ | ||
| but got:\nStderr: {stderr}" | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a regression test covering the reported scenario (missing/unresolvable program path) to ensure
run()returns a contextualErrinstead of panicking. This crate already has an integration test suite underlitebox_runner_linux_userland/tests, and a test here would prevent #650 from regressing.