Skip to content

Commit c2cbaa7

Browse files
committed
Remove some unsafe code; fix a soundness hole
Replace a number of lines of unsafe code with safe equivalents, some using `zerocopy`. In one instance, fix a soundness hole (#720). Closes #720
1 parent b65ab93 commit c2cbaa7

File tree

9 files changed

+63
-26
lines changed

9 files changed

+63
-26
lines changed

Cargo.lock

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ exclude = [
2828
[dependencies]
2929
cfg-if = "1.0"
3030
rustc-demangle = "0.1.24"
31+
zerocopy = { version = "0.8.26", features = ["derive"] }
3132

3233
# Optionally enable the ability to serialize a `Backtrace`, controlled through
3334
# the `serialize-serde` feature below.

src/backtrace/win32.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use super::super::{dbghelp, windows_sys::*};
1313
use core::ffi::c_void;
1414
use core::mem;
1515

16+
use zerocopy::{FromBytes, FromZeros};
17+
1618
#[derive(Clone, Copy)]
1719
pub enum StackFrame {
1820
New(STACKFRAME_EX),
@@ -92,6 +94,7 @@ impl Frame {
9294
}
9395

9496
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in windows metadata right now
97+
#[derive(FromBytes)]
9598
struct MyContext(CONTEXT);
9699

97100
#[inline(always)]
@@ -100,7 +103,7 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
100103
let process = GetCurrentProcess();
101104
let thread = GetCurrentThread();
102105

103-
let mut context = mem::zeroed::<MyContext>();
106+
let mut context = MyContext::new_zeroed();
104107
RtlCaptureContext(&mut context.0);
105108

106109
// Ensure this process's symbols are initialized

src/backtrace/win64.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
99
use super::super::windows_sys::*;
1010
use core::ffi::c_void;
11+
use zerocopy::{FromBytes, FromZeros};
1112

1213
#[derive(Clone, Copy)]
1314
pub struct Frame {
@@ -46,6 +47,7 @@ impl Frame {
4647
}
4748
}
4849

50+
#[derive(FromBytes)]
4951
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in windows metadata right now
5052
struct MyContext(CONTEXT);
5153

@@ -80,8 +82,7 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
8082
use core::ptr;
8183

8284
// Capture the initial context to start walking from.
83-
// FIXME: shouldn't this have a Default impl?
84-
let mut context = unsafe { core::mem::zeroed::<MyContext>() };
85+
let mut context = MyContext::new_zeroed();
8586
unsafe { RtlCaptureContext(&mut context.0) };
8687

8788
loop {

src/print/fuchsia.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use core::fmt::{self, Write};
2-
use core::mem::{size_of, transmute};
2+
use core::mem::size_of;
33
use core::slice::from_raw_parts;
44
use libc::c_char;
5+
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
56

67
unsafe extern "C" {
78
// dl_iterate_phdr takes a callback that will receive a dl_phdr_info pointer
@@ -119,6 +120,7 @@ const NT_GNU_BUILD_ID: u32 = 3;
119120
// Elf_Nhdr represents an ELF note header in the endianness of the target.
120121
#[allow(non_camel_case_types)]
121122
#[repr(C)]
123+
#[derive(FromBytes, IntoBytes, KnownLayout, Immutable)]
122124
struct Elf_Nhdr {
123125
n_namesz: u32,
124126
n_descsz: u32,
@@ -181,15 +183,9 @@ fn take_bytes_align4<'a>(num: usize, bytes: &mut &'a [u8]) -> Option<&'a [u8]> {
181183
// architectures correctness). The values in the Elf_Nhdr fields might
182184
// be nonsense but this function ensures no such thing.
183185
fn take_nhdr<'a>(bytes: &mut &'a [u8]) -> Option<&'a Elf_Nhdr> {
184-
if size_of::<Elf_Nhdr>() > bytes.len() {
185-
return None;
186-
}
187-
// This is safe as long as there is enough space and we just confirmed that
188-
// in the if statement above so this should not be unsafe.
189-
let out = unsafe { transmute::<*const u8, &'a Elf_Nhdr>(bytes.as_ptr()) };
190-
// Note that sice_of::<Elf_Nhdr>() is always 4-byte aligned.
186+
let prefix = &bytes[..size_of::<Elf_Nhdr>()];
191187
*bytes = &bytes[size_of::<Elf_Nhdr>()..];
192-
Some(out)
188+
Elf_Nhdr::ref_from_bytes(prefix).ok()
193189
}
194190

195191
impl<'a> Iterator for NoteIter<'a> {

src/symbolize/dbghelp.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,20 @@ unsafe fn do_resolve(
222222
get_line_from_addr: impl FnOnce(&mut IMAGEHLP_LINEW64) -> BOOL,
223223
cb: &mut dyn FnMut(&super::Symbol),
224224
) {
225-
const SIZE: usize = 2 * MAX_SYM_NAME as usize + mem::size_of::<SYMBOL_INFOW>();
226-
let mut data = Aligned8([0u8; SIZE]);
227-
let info = unsafe { &mut *data.0.as_mut_ptr().cast::<SYMBOL_INFOW>() };
225+
const TRAILER_SIZE: usize = 2 * MAX_SYM_NAME as usize;
226+
227+
#[repr(C)]
228+
#[derive(zerocopy::IntoBytes)]
229+
struct Data {
230+
symbol_infow: SYMBOL_INFOW,
231+
__max_sym_name: [u8; TRAILER_SIZE],
232+
}
233+
234+
let mut data = Aligned8(Data {
235+
symbol_infow: zerocopy::transmute!([0u8; size_of::<SYMBOL_INFOW>()]),
236+
__max_sym_name: [0u8; TRAILER_SIZE],
237+
});
238+
let info = &mut data.0.symbol_infow;
228239
info.MaxNameLen = MAX_SYM_NAME as u32;
229240
// the struct size in C. the value is different to
230241
// `size_of::<SYMBOL_INFOW>() - MAX_SYM_NAME + 1` (== 81)

src/symbolize/gimli/libs_illumos.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ pub(super) fn native_libraries() -> Vec<Library> {
3838
let mut libs = Vec::new();
3939

4040
// Request the current link map from the runtime linker:
41+
let mut map: *const LinkMap = <*const _>::null();
4142
let map = unsafe {
42-
let mut map: *const LinkMap = mem::zeroed();
4343
if dlinfo(
4444
RTLD_SELF,
4545
RTLD_DI_LINKMAP,

src/symbolize/gimli/libs_windows.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ unsafe fn add_loaded_images(ret: &mut Vec<Library>) {
2323
return;
2424
}
2525

26-
// huge struct, probably should avoid manually initializing it even if we can
27-
let mut me = MaybeUninit::<MODULEENTRY32W>::zeroed().assume_init();
26+
let mut me = MODULEENTRY32W::new_zeroed();
2827
me.dwSize = mem::size_of_val(&me) as u32;
2928
if Module32FirstW(snap, &mut me) == TRUE {
3029
loop {

src/windows_sys.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
dead_code,
88
clippy::all
99
)]
10+
11+
use zerocopy::{FromBytes, Immutable, IntoBytes};
12+
1013
windows_targets::link!("dbghelp.dll" "system" fn EnumerateLoadedModulesW64(hprocess : HANDLE, enumloadedmodulescallback : PENUMLOADED_MODULES_CALLBACKW64, usercontext : *const core::ffi::c_void) -> BOOL);
1114
windows_targets::link!("dbghelp.dll" "system" fn StackWalk64(machinetype : u32, hprocess : HANDLE, hthread : HANDLE, stackframe : *mut STACKFRAME64, contextrecord : *mut core::ffi::c_void, readmemoryroutine : PREAD_PROCESS_MEMORY_ROUTINE64, functiontableaccessroutine : PFUNCTION_TABLE_ACCESS_ROUTINE64, getmodulebaseroutine : PGET_MODULE_BASE_ROUTINE64, translateaddress : PTRANSLATE_ADDRESS_ROUTINE64) -> BOOL);
1215
windows_targets::link!("dbghelp.dll" "system" fn StackWalkEx(machinetype : u32, hprocess : HANDLE, hthread : HANDLE, stackframe : *mut STACKFRAME_EX, contextrecord : *mut core::ffi::c_void, readmemoryroutine : PREAD_PROCESS_MEMORY_ROUTINE64, functiontableaccessroutine : PFUNCTION_TABLE_ACCESS_ROUTINE64, getmodulebaseroutine : PGET_MODULE_BASE_ROUTINE64, translateaddress : PTRANSLATE_ADDRESS_ROUTINE64, flags : u32) -> BOOL);
@@ -58,7 +61,7 @@ pub struct ADDRESS64 {
5861
}
5962
pub type ADDRESS_MODE = i32;
6063
#[repr(C)]
61-
#[derive(Clone, Copy)]
64+
#[derive(Clone, Copy, FromBytes, Immutable)]
6265
pub union ARM64_NT_NEON128 {
6366
pub Anonymous: ARM64_NT_NEON128_0,
6467
pub D: [f64; 2],
@@ -67,7 +70,7 @@ pub union ARM64_NT_NEON128 {
6770
pub B: [u8; 16],
6871
}
6972
#[repr(C)]
70-
#[derive(Clone, Copy)]
73+
#[derive(Clone, Copy, FromBytes, Immutable)]
7174
pub struct ARM64_NT_NEON128_0 {
7275
pub Low: u64,
7376
pub High: i64,
@@ -76,7 +79,7 @@ pub const AddrModeFlat: ADDRESS_MODE = 3i32;
7679
pub type BOOL = i32;
7780
#[repr(C)]
7881
#[cfg(target_arch = "aarch64")]
79-
#[derive(Clone, Copy)]
82+
#[derive(Clone, Copy, FromBytes)]
8083
pub struct CONTEXT {
8184
pub ContextFlags: CONTEXT_FLAGS,
8285
pub Cpsr: u32,
@@ -93,14 +96,14 @@ pub struct CONTEXT {
9396
}
9497
#[repr(C)]
9598
#[cfg(target_arch = "aarch64")]
96-
#[derive(Clone, Copy)]
99+
#[derive(Clone, Copy, FromBytes, Immutable)]
97100
pub union CONTEXT_0 {
98101
pub Anonymous: CONTEXT_0_0,
99102
pub X: [u64; 31],
100103
}
101104
#[repr(C)]
102105
#[cfg(target_arch = "aarch64")]
103-
#[derive(Clone, Copy)]
106+
#[derive(Clone, Copy, FromBytes, Immutable)]
104107
pub struct CONTEXT_0_0 {
105108
pub X0: u64,
106109
pub X1: u64,
@@ -217,7 +220,7 @@ pub struct CONTEXT_0_0 {
217220
}
218221
#[repr(C)]
219222
#[cfg(target_arch = "x86")]
220-
#[derive(Clone, Copy)]
223+
#[derive(Clone, Copy, FromBytes)]
221224
pub struct CONTEXT {
222225
pub ContextFlags: CONTEXT_FLAGS,
223226
pub Dr0: u32,
@@ -292,7 +295,7 @@ pub struct FLOATING_SAVE_AREA {
292295
}
293296
#[repr(C)]
294297
#[cfg(target_arch = "x86")]
295-
#[derive(Clone, Copy)]
298+
#[derive(Clone, Copy, FromBytes)]
296299
pub struct FLOATING_SAVE_AREA {
297300
pub ControlWord: u32,
298301
pub StatusWord: u32,
@@ -563,7 +566,7 @@ pub struct STACKFRAME_EX {
563566
pub InlineFrameContext: u32,
564567
}
565568
#[repr(C)]
566-
#[derive(Clone, Copy)]
569+
#[derive(Clone, Copy, FromBytes, IntoBytes)]
567570
pub struct SYMBOL_INFOW {
568571
pub SizeOfStruct: u32,
569572
pub TypeIndex: u32,
@@ -572,6 +575,7 @@ pub struct SYMBOL_INFOW {
572575
pub Size: u32,
573576
pub ModBase: u64,
574577
pub Flags: SYMBOL_INFO_FLAGS,
578+
__padding0: [u8; 4],
575579
pub Value: u64,
576580
pub Address: u64,
577581
pub Register: u32,
@@ -580,6 +584,7 @@ pub struct SYMBOL_INFOW {
580584
pub NameLen: u32,
581585
pub MaxNameLen: u32,
582586
pub Name: [u16; 1],
587+
__padding1: [u8; 2],
583588
}
584589
pub type SYMBOL_INFO_FLAGS = u32;
585590
pub const SYMOPT_DEFERRED_LOADS: u32 = 4u32;

0 commit comments

Comments
 (0)