Skip to main content

catalejo_sys/
access.rs

1//! Raw fault-protected memory access through the process fault backend.
2
3use catalejo_memory::primitive::{Primitive, PrimitiveUnion};
4
5use crate::{exception::backend::Backend, ffi::binding};
6
7/// Perform a bare-bones primitive read via the C-implemented shims.
8///
9/// # Safety
10///
11/// This has the same safety constraints as an individual `binding::catalejo_read_uN` operation,
12/// where `N` is the size of the primitive read. `fault_backend` must belong to the current process
13/// before a fault can occur.
14#[inline]
15pub unsafe fn read(
16    fault_backend: &Backend,
17    target_source: *const PrimitiveUnion,
18    target_value: *mut PrimitiveUnion,
19    target_type: Primitive,
20) -> binding::catalejo_outcome_t {
21    if fault_backend.validate().is_err() {
22        return binding::CATALEJO_OUTCOME_ERROR;
23    }
24
25    // Dispatch to the fixed-width C shim selected by the primitive type.
26    macro_rules! implement {
27        ($target_type:ident) => {
28            tokel::stream!(
29                [< binding::catalejo_read _ $target_type >]:concatenate (target_source.cast::<$target_type>(), target_value.cast::<$target_type>())
30            )
31        };
32    }
33
34    // SAFETY:
35    // The safety concerns of the foreign call have been satisfied by the caller.
36    unsafe {
37        match target_type {
38            Primitive::U8 => implement!(u8),
39            Primitive::U16 => implement!(u16),
40            Primitive::U32 => implement!(u32),
41            Primitive::U64 => implement!(u64),
42        }
43    }
44}
45
46/// Perform a bare-bones primitive write via the C-implemented shims.
47///
48/// # Safety
49///
50/// This has the same safety constraints as an individual `binding::catalejo_write_uN` operation,
51/// where `N` is the size of the primitive written. `fault_backend` must belong to the current
52/// process before a fault can occur.
53#[inline]
54pub unsafe fn write(
55    fault_backend: &Backend,
56    target_value: *mut PrimitiveUnion,
57    target_source: *const PrimitiveUnion,
58    target_type: Primitive,
59) -> binding::catalejo_outcome_t {
60    if fault_backend.validate().is_err() {
61        return binding::CATALEJO_OUTCOME_ERROR;
62    }
63
64    // Dispatch to the fixed-width C shim selected by the primitive type.
65    macro_rules! implement {
66        ($target_type:ident) => {
67            tokel::stream!(
68                [< binding::catalejo_write _ $target_type >]:concatenate (target_value.cast::<$target_type>(), target_source.cast::<$target_type>())
69            )
70        };
71    }
72
73    // SAFETY:
74    // The safety concerns of the foreign call have been satisfied by the caller.
75    unsafe {
76        match target_type {
77            Primitive::U8 => implement!(u8),
78            Primitive::U16 => implement!(u16),
79            Primitive::U32 => implement!(u32),
80            Primitive::U64 => implement!(u64),
81        }
82    }
83}
84
85/// Perform a fault-protected byte copy.
86///
87/// # Safety
88///
89/// Exactly one side must be the fault-adjudicated range. The other side must be valid for the
90/// complete byte count. The ranges must not overlap. The backend must belong to the current
91/// process.
92#[inline]
93pub unsafe fn copy(
94    fault_backend: &Backend,
95    target: *mut u8,
96    source: *const u8,
97    count: usize,
98) -> Result<(), usize> {
99    if fault_backend.validate().is_err() {
100        return Err(0);
101    }
102
103    // SAFETY:
104    // The caller supplies the complete protected-copy contract and the current process backend.
105    let outcome = unsafe { binding::catalejo_copy(target, source, count) };
106
107    match outcome.outcome_status {
108        binding::CATALEJO_OUTCOME_SUCCESS => Ok(()),
109        binding::CATALEJO_OUTCOME_ERROR => Err(outcome.byte_count),
110        #[cfg(not(feature = "stealth-mode"))]
111        _ => unreachable!(),
112
113        #[cfg(feature = "stealth-mode")]
114        _ => std::process::abort(),
115    }
116}