Enforce unsafe_op_in_unsafe_fn

This commit is contained in:
Gary Guo 2021-08-26 01:51:59 +01:00
parent dd94e27b1f
commit 28f545a5c8
5 changed files with 164 additions and 151 deletions

View File

@ -19,7 +19,7 @@ impl Arch {
} }
impl fmt::Debug for Context { impl fmt::Debug for Context {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fmt = fmt.debug_struct("Context"); let mut fmt = fmt.debug_struct("Context");
for i in 0..=15 { for i in 0..=15 {
fmt.field( fmt.field(
@ -91,43 +91,45 @@ pub extern "C-unwind" fn save_context() -> Context {
#[naked] #[naked]
pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! { pub unsafe extern "C" fn restore_context(ctx: &Context) -> ! {
asm!( unsafe {
" asm!(
/* Restore stack */ "
mov rsp, [rdi + 0x38] /* Restore stack */
mov rsp, [rdi + 0x38]
/* Restore callee-saved control registers */ /* Restore callee-saved control registers */
ldmxcsr [rdi + 0x88] ldmxcsr [rdi + 0x88]
fldcw [rdi + 0x90] fldcw [rdi + 0x90]
/* Restore return address */ /* Restore return address */
mov rax, [rdi + 0x80] mov rax, [rdi + 0x80]
push rax push rax
/* /*
* Restore general-purpose registers. Non-callee-saved registers are * Restore general-purpose registers. Non-callee-saved registers are
* also restored because sometimes it's used to pass unwind arguments. * also restored because sometimes it's used to pass unwind arguments.
*/ */
mov rax, [rdi + 0x00] mov rax, [rdi + 0x00]
mov rdx, [rdi + 0x08] mov rdx, [rdi + 0x08]
mov rcx, [rdi + 0x10] mov rcx, [rdi + 0x10]
mov rbx, [rdi + 0x18] mov rbx, [rdi + 0x18]
mov rsi, [rdi + 0x20] mov rsi, [rdi + 0x20]
mov rbp, [rdi + 0x30] mov rbp, [rdi + 0x30]
mov r8 , [rdi + 0x40] mov r8 , [rdi + 0x40]
mov r9 , [rdi + 0x48] mov r9 , [rdi + 0x48]
mov r10, [rdi + 0x50] mov r10, [rdi + 0x50]
mov r11, [rdi + 0x58] mov r11, [rdi + 0x58]
mov r12, [rdi + 0x60] mov r12, [rdi + 0x60]
mov r13, [rdi + 0x68] mov r13, [rdi + 0x68]
mov r14, [rdi + 0x70] mov r14, [rdi + 0x70]
mov r15, [rdi + 0x78] mov r15, [rdi + 0x78]
/* RDI resotred last */ /* RDI resotred last */
mov rdi, [rdi + 0x28] mov rdi, [rdi + 0x28]
ret ret
", ",
options(noreturn) options(noreturn)
); );
}
} }

View File

@ -29,84 +29,96 @@ unsafe extern "C" fn phdr_callback(
_size: usize, _size: usize,
data: *mut c_void, data: *mut c_void,
) -> c_int { ) -> c_int {
let data = &mut *(data as *mut CallbackData); unsafe {
let phdrs = slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize); let data = &mut *(data as *mut CallbackData);
let phdrs = slice::from_raw_parts((*info).dlpi_phdr, (*info).dlpi_phnum as usize);
let mut text = None; let mut text = None;
let mut eh_frame_hdr = None; let mut eh_frame_hdr = None;
let mut dynamic = None; let mut dynamic = None;
for phdr in phdrs { for phdr in phdrs {
let start = (*info).dlpi_addr + phdr.p_vaddr; let start = (*info).dlpi_addr + phdr.p_vaddr;
match phdr.p_type { match phdr.p_type {
PT_LOAD => { PT_LOAD => {
let end = start + phdr.p_memsz; let end = start + phdr.p_memsz;
let range = start..end; let range = start..end;
if range.contains(&(data.pc as _)) { if range.contains(&(data.pc as _)) {
text = Some(range); text = Some(range);
}
} }
PT_GNU_EH_FRAME => {
eh_frame_hdr = Some(start);
}
PT_DYNAMIC => {
dynamic = Some(start);
}
_ => (),
} }
PT_GNU_EH_FRAME => {
eh_frame_hdr = Some(start);
}
PT_DYNAMIC => {
dynamic = Some(start);
}
_ => (),
} }
}
let text = match text { let text = match text {
Some(v) => v, Some(v) => v,
None => return 0, None => return 0,
}; };
let eh_frame_hdr = match eh_frame_hdr { let eh_frame_hdr = match eh_frame_hdr {
Some(v) => v, Some(v) => v,
None => return 0, None => return 0,
}; };
let mut bases = BaseAddresses::default() let mut bases = BaseAddresses::default()
.set_eh_frame_hdr(eh_frame_hdr as _) .set_eh_frame_hdr(eh_frame_hdr as _)
.set_text(text.start as _); .set_text(text.start as _);
// Find the GOT section. // Find the GOT section.
if let Some(start) = dynamic { if let Some(start) = dynamic {
const DT_NULL: usize = 0; const DT_NULL: usize = 0;
const DT_PLTGOT: usize = 3; const DT_PLTGOT: usize = 3;
let mut tags = start as *const [usize; 2]; let mut tags = start as *const [usize; 2];
let mut tag = *tags; let mut tag = *tags;
while tag[0] != DT_NULL { while tag[0] != DT_NULL {
if tag[0] == DT_PLTGOT { if tag[0] == DT_PLTGOT {
bases = bases.set_got(tag[1] as _); bases = bases.set_got(tag[1] as _);
break; break;
}
tags = tags.add(1);
tag = *tags;
} }
tags = tags.add(1);
tag = *tags;
} }
}
// Parse .eh_frame_hdr section. // Parse .eh_frame_hdr section.
let eh_frame_hdr = EhFrameHdr::new( let eh_frame_hdr = EhFrameHdr::new(
get_unlimited_slice(eh_frame_hdr as usize as _), get_unlimited_slice(eh_frame_hdr as usize as _),
NativeEndian, NativeEndian,
) )
.parse(&bases, mem::size_of::<usize>() as _); .parse(&bases, mem::size_of::<usize>() as _);
let eh_frame_hdr = match eh_frame_hdr { let eh_frame_hdr = match eh_frame_hdr {
Ok(v) => v, Ok(v) => v,
Err(_) => return 0, Err(_) => return 0,
}; };
let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr()); let eh_frame = deref_pointer(eh_frame_hdr.eh_frame_ptr());
bases = bases.set_eh_frame(eh_frame as _); bases = bases.set_eh_frame(eh_frame as _);
let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as usize as _), NativeEndian); let eh_frame = EhFrame::new(get_unlimited_slice(eh_frame as usize as _), NativeEndian);
// Use binary search table for address if available. // Use binary search table for address if available.
if let Some(table) = eh_frame_hdr.table() { if let Some(table) = eh_frame_hdr.table() {
if let Ok(fde) = if let Ok(fde) =
table.fde_for_address(&eh_frame, &bases, data.pc as _, EhFrame::cie_from_offset) table.fde_for_address(&eh_frame, &bases, data.pc as _, EhFrame::cie_from_offset)
{ {
data.result = Some(FDESearchResult {
fde,
bases,
eh_frame,
});
return 1;
}
}
// Otherwise do the linear search.
if let Ok(fde) = eh_frame.fde_for_address(&bases, data.pc as _, EhFrame::cie_from_offset) {
data.result = Some(FDESearchResult { data.result = Some(FDESearchResult {
fde, fde,
bases, bases,
@ -114,17 +126,7 @@ unsafe extern "C" fn phdr_callback(
}); });
return 1; return 1;
} }
}
// Otherwise do the linear search. 0
if let Ok(fde) = eh_frame.fde_for_address(&bases, data.pc as _, EhFrame::cie_from_offset) {
data.result = Some(FDESearchResult {
fde,
bases,
eh_frame,
});
return 1;
} }
0
} }

View File

@ -41,9 +41,9 @@ pub fn get_finder() -> &'static Registry {
impl super::FDEFinder for Registry { impl super::FDEFinder for Registry {
fn find_fde(&self, pc: usize) -> Option<FDESearchResult> { fn find_fde(&self, pc: usize) -> Option<FDESearchResult> {
let guard = get_finder().inner.lock().unwrap(); let guard = get_finder().inner.lock().unwrap();
let mut cur = guard.object;
unsafe { unsafe {
let mut cur = guard.object;
while !cur.is_null() { while !cur.is_null() {
let bases = BaseAddresses::default() let bases = BaseAddresses::default()
.set_text((*cur).tbase as _) .set_text((*cur).tbase as _)
@ -103,21 +103,23 @@ unsafe extern "C" fn __register_frame_info_bases(
return; return;
} }
ob.write(Object { unsafe {
next: core::ptr::null_mut(), ob.write(Object {
tbase: tbase as _, next: core::ptr::null_mut(),
dbase: dbase as _, tbase: tbase as _,
table: Table::Single(begin), dbase: dbase as _,
}); table: Table::Single(begin),
});
let mut guard = get_finder().inner.lock().unwrap(); let mut guard = get_finder().inner.lock().unwrap();
(*ob).next = guard.object; (*ob).next = guard.object;
guard.object = ob; guard.object = ob;
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn __register_frame_info(begin: *const c_void, ob: *mut Object) { unsafe extern "C" fn __register_frame_info(begin: *const c_void, ob: *mut Object) {
__register_frame_info_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut()); unsafe { __register_frame_info_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut()) }
} }
#[no_mangle] #[no_mangle]
@ -127,7 +129,7 @@ unsafe extern "C" fn __register_frame(begin: *const c_void) {
} }
let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object; let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object;
__register_frame_info(begin, storage); unsafe { __register_frame_info(begin, storage) }
} }
#[no_mangle] #[no_mangle]
@ -137,21 +139,25 @@ unsafe extern "C" fn __register_frame_info_table_bases(
tbase: *const c_void, tbase: *const c_void,
dbase: *const c_void, dbase: *const c_void,
) { ) {
ob.write(Object { unsafe {
next: core::ptr::null_mut(), ob.write(Object {
tbase: tbase as _, next: core::ptr::null_mut(),
dbase: dbase as _, tbase: tbase as _,
table: Table::Multiple(begin as _), dbase: dbase as _,
}); table: Table::Multiple(begin as _),
});
let mut guard = get_finder().inner.lock().unwrap(); let mut guard = get_finder().inner.lock().unwrap();
(*ob).next = guard.object; (*ob).next = guard.object;
guard.object = ob; guard.object = ob;
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn __register_frame_info_table(begin: *const c_void, ob: *mut Object) { unsafe extern "C" fn __register_frame_info_table(begin: *const c_void, ob: *mut Object) {
__register_frame_info_table_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut()); unsafe {
__register_frame_info_table_bases(begin, ob, core::ptr::null_mut(), core::ptr::null_mut())
}
} }
#[no_mangle] #[no_mangle]
@ -161,37 +167,39 @@ unsafe extern "C" fn __register_frame_table(begin: *const c_void) {
} }
let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object; let storage = Box::into_raw(Box::new(MaybeUninit::<Object>::uninit())) as *mut Object;
__register_frame_info_table(begin, storage); unsafe { __register_frame_info_table(begin, storage) }
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn __deregister_frame_info_bases(begin: *const c_void) -> *mut Object { extern "C" fn __deregister_frame_info_bases(begin: *const c_void) -> *mut Object {
if begin.is_null() { if begin.is_null() {
return core::ptr::null_mut(); return core::ptr::null_mut();
} }
let mut guard = get_finder().inner.lock().unwrap(); let mut guard = get_finder().inner.lock().unwrap();
let mut prev = &mut guard.object; unsafe {
let mut cur = *prev; let mut prev = &mut guard.object;
let mut cur = *prev;
while !cur.is_null() { while !cur.is_null() {
let found = match (*cur).table { let found = match (*cur).table {
Table::Single(addr) => addr == begin, Table::Single(addr) => addr == begin,
_ => false, _ => false,
}; };
if found { if found {
*prev = (*cur).next; *prev = (*cur).next;
return cur; return cur;
}
prev = &mut (*cur).next;
cur = *prev;
} }
prev = &mut (*cur).next;
cur = *prev;
} }
core::ptr::null_mut() core::ptr::null_mut()
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn __deregister_frame_info(begin: *const c_void) -> *mut Object { extern "C" fn __deregister_frame_info(begin: *const c_void) -> *mut Object {
__deregister_frame_info_bases(begin) __deregister_frame_info_bases(begin)
} }
@ -201,5 +209,5 @@ unsafe extern "C" fn __deregister_frame(begin: *const c_void) {
return; return;
} }
let storage = __deregister_frame_info(begin); let storage = __deregister_frame_info(begin);
drop(Box::from_raw(storage as *mut MaybeUninit<Object>)) drop(unsafe { Box::from_raw(storage as *mut MaybeUninit<Object>) })
} }

View File

@ -1,7 +1,8 @@
#![feature(c_unwind)] #![feature(c_unwind)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(asm)] #![feature(asm)]
#![allow(unused_unsafe)] #![warn(rust_2018_idioms)]
#![warn(unsafe_op_in_unsafe_fn)]
mod arch; mod arch;
mod find_fde; mod find_fde;

View File

@ -7,12 +7,12 @@ pub unsafe fn get_unlimited_slice<'a>(start: *const u8) -> &'a [u8] {
let start = start as usize; let start = start as usize;
let end = start.saturating_add(isize::MAX as _); let end = start.saturating_add(isize::MAX as _);
let len = end - start; let len = end - start;
core::slice::from_raw_parts(start as *const _, len) unsafe { core::slice::from_raw_parts(start as *const _, len) }
} }
pub unsafe fn deref_pointer(ptr: Pointer) -> usize { pub unsafe fn deref_pointer(ptr: Pointer) -> usize {
match ptr { match ptr {
Pointer::Direct(x) => x as _, Pointer::Direct(x) => x as _,
Pointer::Indirect(x) => *(x as *const _), Pointer::Indirect(x) => unsafe { *(x as *const _) },
} }
} }