mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat(ffi): unwind safety: shield FFI entrypoints with panic guard (#546)
This PR implements widely accepted Rust programming practices for dealing with panics across ABI (programming language) boundaries. - Add panic_guard.rs to wrap FFI calls and prevent panic across FFI/ABI boundary (undefined behavior). - Capture per-thread backtraces via a temporary panic hook - After a panic, subsequent invocations are poisoned. - Integrate with_unwind_guard across the engine, schema registry, and target registry exportis Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
GitHub
parent
9426b2ec02
commit
80686d6ed1
@@ -4,6 +4,7 @@
|
||||
#![cfg(feature = "azure_policy")]
|
||||
|
||||
use crate::common::*;
|
||||
use crate::panic_guard::with_unwind_guard;
|
||||
use anyhow::Result;
|
||||
use std::os::raw::c_char;
|
||||
|
||||
@@ -16,12 +17,14 @@ use std::os::raw::c_char;
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_register_target_from_json(target_json: *const c_char) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let target_str = from_c_str(target_json)?;
|
||||
let target = regorus::Target::from_json_str(&target_str)?;
|
||||
regorus::registry::targets::register(regorus::Rc::new(target))?;
|
||||
Ok(())
|
||||
}())
|
||||
with_unwind_guard(|| {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let target_str = from_c_str(target_json)?;
|
||||
let target = regorus::Target::from_json_str(&target_str)?;
|
||||
regorus::registry::targets::register(regorus::Rc::new(target))?;
|
||||
Ok(())
|
||||
}())
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if a target is registered.
|
||||
@@ -36,31 +39,35 @@ pub extern "C" fn regorus_register_target_from_json(target_json: *const c_char)
|
||||
/// The name parameter must be a valid null-terminated UTF-8 string.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn regorus_target_registry_contains(name: *const c_char) -> RegorusResult {
|
||||
let target_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid target name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
with_unwind_guard(|| {
|
||||
let target_name = match from_c_str(name) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
return RegorusResult::err_with_message(
|
||||
RegorusStatus::InvalidArgument,
|
||||
format!("Invalid target name string: {e}"),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let contains = regorus::registry::targets::contains(&target_name);
|
||||
RegorusResult::ok_bool(contains)
|
||||
let contains = regorus::registry::targets::contains(&target_name);
|
||||
RegorusResult::ok_bool(contains)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get a list of all registered target names as JSON array.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_list_names() -> RegorusResult {
|
||||
let names = regorus::registry::targets::list_names();
|
||||
let output = serde_json::to_string_pretty(&names).map_err(anyhow::Error::msg);
|
||||
with_unwind_guard(|| {
|
||||
let names = regorus::registry::targets::list_names();
|
||||
let output = serde_json::to_string_pretty(&names).map_err(anyhow::Error::msg);
|
||||
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
match output {
|
||||
Ok(out) => RegorusResult::ok_string(out),
|
||||
Err(e) => to_regorus_result(Err(e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Remove a target from the registry by name.
|
||||
@@ -69,19 +76,23 @@ pub extern "C" fn regorus_target_registry_list_names() -> RegorusResult {
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_remove(name: *const c_char) -> RegorusResult {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let name_str = from_c_str(name)?;
|
||||
regorus::registry::targets::remove(&name_str);
|
||||
Ok(())
|
||||
}())
|
||||
with_unwind_guard(|| {
|
||||
to_regorus_result(|| -> Result<()> {
|
||||
let name_str = from_c_str(name)?;
|
||||
regorus::registry::targets::remove(&name_str);
|
||||
Ok(())
|
||||
}())
|
||||
})
|
||||
}
|
||||
|
||||
/// Clear all targets from the registry.
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_clear() -> RegorusResult {
|
||||
regorus::registry::targets::clear();
|
||||
RegorusResult::ok_void()
|
||||
with_unwind_guard(|| {
|
||||
regorus::registry::targets::clear();
|
||||
RegorusResult::ok_void()
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the number of registered targets.
|
||||
@@ -91,8 +102,10 @@ pub extern "C" fn regorus_target_registry_clear() -> RegorusResult {
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_len() -> RegorusResult {
|
||||
let count = regorus::registry::targets::len();
|
||||
RegorusResult::ok_int(count as i64)
|
||||
with_unwind_guard(|| {
|
||||
let count = regorus::registry::targets::len();
|
||||
RegorusResult::ok_int(count as i64)
|
||||
})
|
||||
}
|
||||
|
||||
/// Check if the target registry is empty.
|
||||
@@ -102,6 +115,8 @@ pub extern "C" fn regorus_target_registry_len() -> RegorusResult {
|
||||
#[no_mangle]
|
||||
#[cfg(feature = "azure_policy")]
|
||||
pub extern "C" fn regorus_target_registry_is_empty() -> RegorusResult {
|
||||
let is_empty = regorus::registry::targets::is_empty();
|
||||
RegorusResult::ok_bool(is_empty)
|
||||
with_unwind_guard(|| {
|
||||
let is_empty = regorus::registry::targets::is_empty();
|
||||
RegorusResult::ok_bool(is_empty)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user