/rust/registry/src/index.crates.io-1949cf8c6b5b557f/getrandom-0.3.4/src/backends/sanitizer.rs
Line | Count | Source |
1 | | use core::mem::MaybeUninit; |
2 | | |
3 | | /// Unpoisons `buf` if MSAN support is enabled. |
4 | | /// |
5 | | /// Most backends do not need to unpoison their output. Rust language- and |
6 | | /// library- provided functionality unpoisons automatically. Similarly, libc |
7 | | /// either natively supports MSAN and/or MSAN hooks libc-provided functions |
8 | | /// to unpoison outputs on success. Only when all of these things are |
9 | | /// bypassed do we need to do it ourselves. |
10 | | /// |
11 | | /// The call to unpoison should be done as close to the write as possible. |
12 | | /// For example, if the backend partially fills the output buffer in chunks, |
13 | | /// each chunk should be unpoisoned individually. This way, the correctness of |
14 | | /// the chunking logic can be validated (in part) using MSAN. |
15 | 0 | pub unsafe fn unpoison(buf: &mut [MaybeUninit<u8>]) { |
16 | | cfg_if! { |
17 | | if #[cfg(getrandom_msan)] { |
18 | | extern "C" { |
19 | | fn __msan_unpoison(a: *mut core::ffi::c_void, size: usize); |
20 | | } |
21 | | let a = buf.as_mut_ptr().cast(); |
22 | | let size = buf.len(); |
23 | | #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. |
24 | | unsafe { |
25 | | __msan_unpoison(a, size); |
26 | | } |
27 | | } else { |
28 | 0 | let _ = buf; |
29 | | } |
30 | | } |
31 | 0 | } |
32 | | |
33 | | /// Interprets the result of the `getrandom` syscall of Linux, unpoisoning any |
34 | | /// written part of `buf`. |
35 | | /// |
36 | | /// `buf` must be the output buffer that was originally passed to the `getrandom` |
37 | | /// syscall. |
38 | | /// |
39 | | /// `ret` must be the result returned by `getrandom`. If `ret` is negative or |
40 | | /// larger than the length of `buf` then nothing is done. |
41 | | /// |
42 | | /// Memory Sanitizer only intercepts `getrandom` on this condition (from its |
43 | | /// source code): |
44 | | /// ```c |
45 | | /// #define SANITIZER_INTERCEPT_GETRANDOM \ |
46 | | /// ((SI_LINUX && __GLIBC_PREREQ(2, 25)) || SI_FREEBSD || SI_SOLARIS) |
47 | | /// ``` |
48 | | /// So, effectively, we have to assume that it is never intercepted on Linux. |
49 | | #[cfg(any(target_os = "android", target_os = "linux"))] |
50 | 0 | pub unsafe fn unpoison_linux_getrandom_result(buf: &mut [MaybeUninit<u8>], ret: isize) { |
51 | 0 | if let Ok(bytes_written) = usize::try_from(ret) { |
52 | 0 | if let Some(written) = buf.get_mut(..bytes_written) { |
53 | | #[allow(unused_unsafe)] // TODO(MSRV 1.65): Remove this. |
54 | | unsafe { |
55 | 0 | unpoison(written) |
56 | | } |
57 | 0 | } |
58 | 0 | } |
59 | 0 | } |