Skip to content

Update fuzzing test to check for simpleguest in same directory as executable #324

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

Merged
merged 4 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/Fuzzing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
fuzzing:
uses: ./.github/workflows/dep_fuzzing.yml
with:
targets: '["host_print", "guest_call", "host_call"]' # Pass as a JSON array
targets: '["fuzz_host_print", "fuzz_guest_call", "fuzz_host_call"]' # Pass as a JSON array
max_total_time: 18000 # 5 hours in seconds
secrets: inherit
2 changes: 1 addition & 1 deletion .github/workflows/ValidatePullRequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
- docs-pr
uses: ./.github/workflows/dep_fuzzing.yml
with:
targets: '["host_print", "guest_call", "host_call"]' # Pass as a JSON array
targets: '["fuzz_host_print", "fuzz_guest_call", "fuzz_host_call"]' # Pass as a JSON array
max_total_time: 300 # 5 minutes in seconds
docs_only: ${{needs.docs-pr.outputs.docs-only}}
secrets: inherit
Expand Down
7 changes: 7 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,10 @@ fuzz fuzz-target:
# Fuzzes the given target. Stops after `max_time` seconds
fuzz-timed fuzz-target max_time:
cargo +nightly fuzz run {{ fuzz-target }} --release -- -max_total_time={{ max_time }}

# Builds fuzzers for submission to external fuzzing services
build-fuzzers: (build-fuzzer "fuzz_guest_call") (build-fuzzer "fuzz_host_call") (build-fuzzer "fuzz_host_print")

# Builds the given fuzzer
build-fuzzer fuzz-target:
cargo +nightly fuzz build {{ fuzz-target }} --release -s none
6 changes: 3 additions & 3 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ hyperlight-testing = { workspace = true }
hyperlight-host = { workspace = true, default-features = true, features = ["fuzzing"]}

[[bin]]
name = "host_print"
name = "fuzz_host_print"
path = "fuzz_targets/host_print.rs"
test = false
doc = false
bench = false

[[bin]]
name = "guest_call"
name = "fuzz_guest_call"
path = "fuzz_targets/guest_call.rs"
test = false
doc = false
bench = false

[[bin]]
name = "host_call"
name = "fuzz_host_call"
path = "fuzz_targets/host_call.rs"
test = false
doc = false
Expand Down
2 changes: 1 addition & 1 deletion fuzz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ You can run the fuzzers with:
```sh
just fuzz <fuzz_target>
```
which evaluates to the following command `cargo +nightly fuzz run host_print --release`. We use the release profile to make sure the release-optimized guest is used. The default fuzz profile which is release+debugsymbols would cause our debug guests to be loaded, since we currently determine which test guest to load based on whether debug symbols are present.
which evaluates to the following command `cargo +nightly fuzz run fuzz_host_print --release`. We use the release profile to make sure the release-optimized guest is used. The default fuzz profile which is release+debugsymbols would cause our debug guests to be loaded, since we currently determine which test guest to load based on whether debug symbols are present.

As per Microsoft's Offensive Research & Security Engineering (MORSE) team, all host exposed functions that receive or interact with guest data must be continuously fuzzed for, at least, 500 million fuzz test cases without any crashes. Because `cargo-fuzz` doesn't support setting a maximum number of iterations; instead, we use the `--max_total_time` flag to set a maximum time to run the fuzzer. We have a GitHub action (acting like a CRON job) that runs the fuzzers for 24 hours every week.

Expand Down
5 changes: 3 additions & 2 deletions fuzz/fuzz_targets/guest_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ use hyperlight_host::sandbox::uninitialized::GuestBinary;
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
use hyperlight_host::sandbox_state::transition::Noop;
use hyperlight_host::{MultiUseSandbox, UninitializedSandbox};
use hyperlight_testing::simple_guest_as_string;
use hyperlight_testing::simple_guest_for_fuzzing_as_string;
use libfuzzer_sys::fuzz_target;
static SANDBOX: OnceLock<Mutex<MultiUseSandbox>> = OnceLock::new();

// This fuzz target tests all combinations of ReturnType and Parameters for `call_guest_function_by_name`.
// For fuzzing efficiency, we create one Sandbox and reuse it for all fuzzing iterations.
fuzz_target!(
init: {

let u_sbox = UninitializedSandbox::new(
GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
GuestBinary::FilePath(simple_guest_for_fuzzing_as_string().expect("Guest Binary Missing")),
None,
None,
None,
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/host_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use hyperlight_host::sandbox::SandboxConfiguration;
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
use hyperlight_host::sandbox_state::transition::Noop;
use hyperlight_host::{HyperlightError, MultiUseSandbox, UninitializedSandbox};
use hyperlight_testing::simple_guest_as_string;
use hyperlight_testing::simple_guest_for_fuzzing_as_string;
use libfuzzer_sys::fuzz_target;
static SANDBOX: OnceLock<Mutex<MultiUseSandbox>> = OnceLock::new();

Expand All @@ -33,7 +33,7 @@ static SANDBOX: OnceLock<Mutex<MultiUseSandbox>> = OnceLock::new();
fuzz_target!(
init: {
let u_sbox = UninitializedSandbox::new(
GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
GuestBinary::FilePath(simple_guest_for_fuzzing_as_string().expect("Guest Binary Missing")),
None,
None,
None,
Expand Down
4 changes: 2 additions & 2 deletions fuzz/fuzz_targets/host_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use hyperlight_host::sandbox::uninitialized::GuestBinary;
use hyperlight_host::sandbox_state::sandbox::EvolvableSandbox;
use hyperlight_host::sandbox_state::transition::Noop;
use hyperlight_host::{MultiUseSandbox, UninitializedSandbox};
use hyperlight_testing::simple_guest_as_string;
use hyperlight_testing::simple_guest_for_fuzzing_as_string;
use libfuzzer_sys::{fuzz_target, Corpus};

static SANDBOX: OnceLock<Mutex<MultiUseSandbox>> = OnceLock::new();
Expand All @@ -19,7 +19,7 @@ static SANDBOX: OnceLock<Mutex<MultiUseSandbox>> = OnceLock::new();
fuzz_target!(
init: {
let u_sbox = UninitializedSandbox::new(
GuestBinary::FilePath(simple_guest_as_string().expect("Guest Binary Missing")),
GuestBinary::FilePath(simple_guest_for_fuzzing_as_string().expect("Guest Binary Missing")),
None,
None,
None,
Expand Down
24 changes: 24 additions & 0 deletions src/hyperlight_testing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

// This crate contains testing utilities which need to be shared across multiple
// crates in this project.
use std::env;
use std::path::PathBuf;

use anyhow::{anyhow, Result};
Expand Down Expand Up @@ -129,3 +130,26 @@ pub fn c_callback_guest_as_string() -> Result<String> {
.map(|s| s.to_string())
.ok_or_else(|| anyhow!("couldn't convert callback guest PathBuf to string"))
}

/// Get a fully qualified path to a simple guest binary preferring a binary
/// in the same directory as the parent executable. This will be used in
/// fuzzing scenarios where pre-built binaries will be built and submitted to
/// a fuzzing framework.
pub fn simple_guest_for_fuzzing_as_string() -> Result<String> {
let exe_dir = env::current_exe()
.ok()
.and_then(|path| path.parent().map(|p| p.to_path_buf()));

if let Some(exe_dir) = exe_dir {
let guest_path = exe_dir.join("simpleguest");

if guest_path.exists() {
return Ok(guest_path
.to_str()
.ok_or(anyhow!("Invalid path string"))?
.to_string());
}
}

simple_guest_as_string()
}
Loading