From df3464661bfd651f1046bd732041b821aea16f79 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Thu, 21 Sep 2023 13:19:02 -0700 Subject: [PATCH 1/3] Adjust frame IP in SGX relative to image base --- src/backtrace/libunwind.rs | 13 ++++++++- src/backtrace/mod.rs | 31 +++++++++++++++++++++ src/lib.rs | 6 ++++ src/print.rs | 11 +------- tests/sgx-image-base.rs | 56 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 11 deletions(-) create mode 100644 tests/sgx-image-base.rs diff --git a/src/backtrace/libunwind.rs b/src/backtrace/libunwind.rs index aefa8b094..0cf6365f7 100644 --- a/src/backtrace/libunwind.rs +++ b/src/backtrace/libunwind.rs @@ -40,7 +40,18 @@ impl Frame { Frame::Raw(ctx) => ctx, Frame::Cloned { ip, .. } => return ip, }; - unsafe { uw::_Unwind_GetIP(ctx) as *mut c_void } + #[allow(unused_mut)] + let mut ip = unsafe { uw::_Unwind_GetIP(ctx) as *mut c_void }; + + // To reduce TCB size in SGX enclaves, we do not want to implement + // symbol resolution functionality. Rather, we can print the offset of + // the address here, which could be later mapped to correct function. + #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] + { + let image_base = super::get_image_base(); + ip = usize::wrapping_sub(ip as usize, image_base as _) as _; + } + ip } pub fn sp(&self) -> *mut c_void { diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index 6ca1080c4..c414d0514 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -125,6 +125,37 @@ impl fmt::Debug for Frame { } } +#[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] +mod sgx_no_std_image_base { + use core::sync::atomic::{AtomicU64, Ordering::SeqCst}; + + static IMAGE_BASE: AtomicU64 = AtomicU64::new(0); + + /// Set the image base address. This is only available for Fortanix SGX + /// target when the `std` feature is not enabled. This can be used in the + /// standard library to set the correct base address. + pub fn set_image_base(base_addr: u64) { + IMAGE_BASE.store(base_addr, SeqCst); + } + + pub(crate) fn get_image_base() -> u64 { + IMAGE_BASE.load(SeqCst) + } +} + +#[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] +pub use self::sgx_no_std_image_base::set_image_base; + +#[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] +#[deny(unused)] +pub(crate) use self::sgx_no_std_image_base::get_image_base; + +#[cfg(all(target_env = "sgx", target_vendor = "fortanix", feature = "std"))] +#[deny(unused)] +pub(crate) fn get_image_base() -> u64 { + std::os::fortanix_sgx::mem::image_base() +} + cfg_if::cfg_if! { // This needs to come first, to ensure that // Miri takes priority over the host platform diff --git a/src/lib.rs b/src/lib.rs index 4615e1f96..090687fce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -134,6 +134,12 @@ cfg_if::cfg_if! { } } +cfg_if::cfg_if! { + if #[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] { + pub use self::backtrace::set_image_base; + } +} + #[allow(dead_code)] struct Bomb { enabled: bool, diff --git a/src/print.rs b/src/print.rs index 395328a0a..de8569182 100644 --- a/src/print.rs +++ b/src/print.rs @@ -219,7 +219,7 @@ impl BacktraceFrameFmt<'_, '_, '_> { #[allow(unused_mut)] fn print_raw_generic( &mut self, - mut frame_ip: *mut c_void, + frame_ip: *mut c_void, symbol_name: Option>, filename: Option>, lineno: Option, @@ -233,15 +233,6 @@ impl BacktraceFrameFmt<'_, '_, '_> { } } - // To reduce TCB size in Sgx enclave, we do not want to implement symbol - // resolution functionality. Rather, we can print the offset of the - // address here, which could be later mapped to correct function. - #[cfg(all(feature = "std", target_env = "sgx", target_vendor = "fortanix"))] - { - let image_base = std::os::fortanix_sgx::mem::image_base(); - frame_ip = usize::wrapping_sub(frame_ip as usize, image_base as _) as _; - } - // Print the index of the frame as well as the optional instruction // pointer of the frame. If we're beyond the first symbol of this frame // though we just print appropriate whitespace. diff --git a/tests/sgx-image-base.rs b/tests/sgx-image-base.rs new file mode 100644 index 000000000..d8bacf3da --- /dev/null +++ b/tests/sgx-image-base.rs @@ -0,0 +1,56 @@ +#![cfg(all(target_env = "sgx", target_vendor = "fortanix"))] +#![feature(sgx_platform)] + +#[cfg(feature = "std")] +#[test] +fn sgx_image_base_with_std() { + use backtrace::trace; + + let image_base = std::os::fortanix_sgx::mem::image_base(); + + let mut frame_ips = Vec::new(); + trace(|frame| { + frame_ips.push(frame.ip()); + true + }); + + assert!(frame_ips.len() > 0); + for ip in frame_ips { + let ip: u64 = ip as _; + assert!(ip < image_base); + } +} + +#[cfg(not(feature = "std"))] +#[test] +fn sgx_image_base_no_std() { + use backtrace::trace_unsynchronized; + + fn guess_image_base() -> u64 { + let mut top_frame_ip = None; + unsafe { + trace_unsynchronized(|frame| { + top_frame_ip = Some(frame.ip()); + false + }); + } + top_frame_ip.unwrap() as u64 & 0xFFFFFF000000 + } + + let image_base = guess_image_base(); + backtrace::set_image_base(image_base); + + let mut frame_ips = Vec::new(); + unsafe { + trace_unsynchronized(|frame| { + frame_ips.push(frame.ip()); + true + }); + } + + assert!(frame_ips.len() > 0); + for ip in frame_ips { + let ip: u64 = ip as _; + assert!(ip < image_base); + } +} From f09114ad5aaa74fa254854201e1ff1b944fc73d9 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Mon, 2 Oct 2023 16:04:46 -0700 Subject: [PATCH 2/3] Hide set_image_base API --- src/backtrace/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index c414d0514..c098755a3 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -134,6 +134,7 @@ mod sgx_no_std_image_base { /// Set the image base address. This is only available for Fortanix SGX /// target when the `std` feature is not enabled. This can be used in the /// standard library to set the correct base address. + #[doc(hidden)] pub fn set_image_base(base_addr: u64) { IMAGE_BASE.store(base_addr, SeqCst); } From 43d785942c40e8fd4f8a190e1cc75208ead0857c Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Fri, 6 Oct 2023 11:42:35 -0700 Subject: [PATCH 3/3] Use pointer types for SGX image base address --- src/backtrace/mod.rs | 17 +++++++++-------- tests/sgx-image-base.rs | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/backtrace/mod.rs b/src/backtrace/mod.rs index c098755a3..b6cfb1669 100644 --- a/src/backtrace/mod.rs +++ b/src/backtrace/mod.rs @@ -127,20 +127,21 @@ impl fmt::Debug for Frame { #[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] mod sgx_no_std_image_base { - use core::sync::atomic::{AtomicU64, Ordering::SeqCst}; + use core::ffi::c_void; + use core::sync::atomic::{AtomicUsize, Ordering::SeqCst}; - static IMAGE_BASE: AtomicU64 = AtomicU64::new(0); + static IMAGE_BASE: AtomicUsize = AtomicUsize::new(0); /// Set the image base address. This is only available for Fortanix SGX /// target when the `std` feature is not enabled. This can be used in the /// standard library to set the correct base address. #[doc(hidden)] - pub fn set_image_base(base_addr: u64) { - IMAGE_BASE.store(base_addr, SeqCst); + pub fn set_image_base(base_addr: *mut c_void) { + IMAGE_BASE.store(base_addr as _, SeqCst); } - pub(crate) fn get_image_base() -> u64 { - IMAGE_BASE.load(SeqCst) + pub(crate) fn get_image_base() -> *mut c_void { + IMAGE_BASE.load(SeqCst) as _ } } @@ -153,8 +154,8 @@ pub(crate) use self::sgx_no_std_image_base::get_image_base; #[cfg(all(target_env = "sgx", target_vendor = "fortanix", feature = "std"))] #[deny(unused)] -pub(crate) fn get_image_base() -> u64 { - std::os::fortanix_sgx::mem::image_base() +pub(crate) fn get_image_base() -> *mut c_void { + std::os::fortanix_sgx::mem::image_base() as _ } cfg_if::cfg_if! { diff --git a/tests/sgx-image-base.rs b/tests/sgx-image-base.rs index d8bacf3da..c29a8b67a 100644 --- a/tests/sgx-image-base.rs +++ b/tests/sgx-image-base.rs @@ -38,7 +38,7 @@ fn sgx_image_base_no_std() { } let image_base = guess_image_base(); - backtrace::set_image_base(image_base); + backtrace::set_image_base(image_base as _); let mut frame_ips = Vec::new(); unsafe {