|
| 1 | +// Support for raw system calls on Linux. |
| 2 | +// |
| 3 | +// # Sanitizers |
| 4 | +// |
| 5 | +// Currently only Memory Sanitizer is actively supported. |
| 6 | +// |
| 7 | +// TODO: Support address sanitizer, in particular in `pre_write_range`. |
| 8 | +// |
| 9 | +// ## Memory Sanitizer |
| 10 | +// |
| 11 | +// See https://github.com/llvm/llvm-project/commit/ac9ee01fcbfac745aaedca0393a8e1c8a33acd8d: |
| 12 | +// LLVM uses: |
| 13 | +// ```c |
| 14 | +// COMMON_INTERCEPTOR_ENTER(ctx, getrandom, buf, buflen, flags); |
| 15 | +// SSIZE_T n = REAL(getrandom)(buf, buflen, flags); |
| 16 | +// if (n > 0) { |
| 17 | +// COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, n); |
| 18 | +// } |
| 19 | +// ``` |
| 20 | +// and: |
| 21 | +// ```c |
| 22 | +// #define PRE_SYSCALL(name) \ |
| 23 | +// SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name |
| 24 | +// #define PRE_WRITE(p, s) COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) |
| 25 | +// #define POST_WRITE(p, s) COMMON_SYSCALL_POST_WRITE_RANGE(p, s) |
| 26 | +// PRE_SYSCALL(getrandom)(void *buf, uptr count, long flags) { |
| 27 | +// if (buf) { |
| 28 | +// PRE_WRITE(buf, count); |
| 29 | +// } |
| 30 | +// } |
| 31 | +// |
| 32 | +// POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { |
| 33 | +// if (res > 0 && buf) { |
| 34 | +// POST_WRITE(buf, res); |
| 35 | +// } |
| 36 | +// } |
| 37 | +// ``` |
| 38 | + |
| 39 | +use core::mem::MaybeUninit; |
| 40 | + |
| 41 | +// MSAN defines: |
| 42 | +// |
| 43 | +// ```c |
| 44 | +// #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ |
| 45 | +// if (msan_init_is_running) \ |
| 46 | +// return REAL(func)(__VA_ARGS__); \ |
| 47 | +// ENSURE_MSAN_INITED(); \ |
| 48 | +// MSanInterceptorContext msan_ctx = {IsInInterceptorScope()}; \ |
| 49 | +// ctx = (void *)&msan_ctx; \ |
| 50 | +// (void)ctx; \ |
| 51 | +// InterceptorScope interceptor_scope; \ |
| 52 | +// __msan_unpoison(__errno_location(), sizeof(int)); |
| 53 | +// ``` |
| 54 | +// |
| 55 | +// * We assume that memory sanitizer will not use the this crate during the |
| 56 | +// initialization of msan, so we don't have to worry about |
| 57 | +// `msan_init_is_running`. |
| 58 | +// * We assume that rustc/LLVM initializes MSAN before executing any Rust code, |
| 59 | +// so we don't need to call `ENSURE_MSAN_INITED`. |
| 60 | +// * Notice that `COMMON_INTERCEPTOR_WRITE_RANGE` doesn't use `ctx`, which |
| 61 | +// means it is oblivious to `IsInInterceptorScope()`, so we don't have to |
| 62 | +// call it. More generally, we don't have to worry about interceptor scopes |
| 63 | +// because we are not an interceptor. |
| 64 | +// * We don't read from `__errno_location()` so we don't need to unpoison it. |
| 65 | +// |
| 66 | +// Consequently, MSAN's `COMMON_INTERCEPTOR_ENTER` is a no-op. |
| 67 | +// |
| 68 | +// MSAN defines: |
| 69 | +// ```c |
| 70 | +// #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \ |
| 71 | +// do { \ |
| 72 | +// } while (false) |
| 73 | +// ``` |
| 74 | +// So MSAN's PRE_SYSCALL hook is also a no-op. |
| 75 | +// |
| 76 | +// Consequently, we have nothing to do before invoking the syscall unless/until |
| 77 | +// we support other sanitizers like ASAN. |
| 78 | +#[allow(unused_variables)] |
| 79 | +pub fn pre_write_range(_ptr: *mut MaybeUninit<u8>, _size: usize) {} |
| 80 | + |
| 81 | +// MSNA defines: |
| 82 | +// ```c |
| 83 | +// #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ |
| 84 | +// __msan_unpoison(ptr, size) |
| 85 | +// ``` |
| 86 | +// and: |
| 87 | +// ```c |
| 88 | +// #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s) |
| 89 | +// ``` |
| 90 | +#[allow(unused_variables)] |
| 91 | +pub unsafe fn post_write_range(ptr: *mut MaybeUninit<u8>, size: usize) { |
| 92 | + #[cfg(feature = "unstable-sanitize")] |
| 93 | + { |
| 94 | + #[cfg(sanitize = "memory")] |
| 95 | + { |
| 96 | + use core::ffi::c_void; |
| 97 | + extern "C" { |
| 98 | + // void __msan_unpoison(const volatile void *a, size_t size); |
| 99 | + fn __msan_unpoison(a: *mut c_void, size: usize); |
| 100 | + } |
| 101 | + __msan_unpoison(ptr.cast::<c_void>(), size) |
| 102 | + } |
| 103 | + } |
| 104 | +} |
0 commit comments