Fix a potential memory issue in fpregs' free
This commit is contained in:
parent
89c292e2df
commit
85f5bc7ccc
@ -5,7 +5,7 @@ use self::rdtsc::{handle_rdtsc_exception, RDTSC_OPCODE};
|
||||
use self::syscall::{handle_syscall_exception, SYSCALL_OPCODE};
|
||||
use super::*;
|
||||
use crate::signal::{FaultSignal, SigSet};
|
||||
use crate::syscall::{CpuContext, SyscallNum};
|
||||
use crate::syscall::{CpuContext, FpRegs, SyscallNum};
|
||||
use aligned::{Aligned, A16};
|
||||
use core::arch::x86_64::_fxsave;
|
||||
use sgx_types::*;
|
||||
@ -26,19 +26,26 @@ pub fn register_exception_handlers() {
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn handle_exception(info: *mut sgx_exception_info_t) -> i32 {
|
||||
// Rust compiler would complain about passing to external C functions a CpuContext
|
||||
// pointer, which includes a FpRegs pointer that is not safe to use by external
|
||||
// modules. In our case, the FpRegs pointer will not be used actually. So the
|
||||
// Rust warning is a false alarm. We suppress it here.
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
fn __occlum_syscall_c_abi(
|
||||
num: u32,
|
||||
info: *mut sgx_exception_info_t,
|
||||
fpregs: *mut u8,
|
||||
fpregs: *mut FpRegs,
|
||||
) -> u32;
|
||||
}
|
||||
|
||||
let mut fpregs: Aligned<A16, _> = Aligned([0u8; 512]);
|
||||
let mut fpregs = fpregs.as_mut_ptr();
|
||||
let mut fpregs = FpRegs::save();
|
||||
unsafe {
|
||||
_fxsave(fpregs);
|
||||
__occlum_syscall_c_abi(SyscallNum::HandleException as u32, info, fpregs)
|
||||
__occlum_syscall_c_abi(
|
||||
SyscallNum::HandleException as u32,
|
||||
info,
|
||||
&mut fpregs as *mut FpRegs,
|
||||
)
|
||||
};
|
||||
unreachable!();
|
||||
}
|
||||
@ -46,7 +53,7 @@ extern "C" fn handle_exception(info: *mut sgx_exception_info_t) -> i32 {
|
||||
/// Exceptions are handled as a special kind of system calls.
|
||||
pub fn do_handle_exception(
|
||||
info: *mut sgx_exception_info_t,
|
||||
fpregs: *mut u8,
|
||||
fpregs: *mut FpRegs,
|
||||
user_context: *mut CpuContext,
|
||||
) -> Result<isize> {
|
||||
let info = unsafe { &mut *info };
|
||||
@ -54,6 +61,7 @@ pub fn do_handle_exception(
|
||||
|
||||
let user_context = unsafe { &mut *user_context };
|
||||
*user_context = CpuContext::from_sgx(&info.cpu_context);
|
||||
user_context.fpregs = fpregs;
|
||||
|
||||
// Try to do instruction emulation first
|
||||
if info.exception_vector == sgx_exception_vector_t::SGX_EXCEPTION_VECTOR_UD {
|
||||
@ -78,7 +86,6 @@ pub fn do_handle_exception(
|
||||
//
|
||||
// As the thread cannot proceed without handling the exception, we choose to force
|
||||
// delivering the signal regardless of the current signal mask.
|
||||
user_context.fpregs = fpregs;
|
||||
let signal = Box::new(FaultSignal::new(info));
|
||||
crate::signal::force_signal(signal, user_context);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
pub use self::sgx::sgx_interrupt_info_t;
|
||||
use crate::prelude::*;
|
||||
use crate::process::ThreadRef;
|
||||
use crate::syscall::{CpuContext, SyscallNum};
|
||||
use crate::syscall::{CpuContext, FpRegs, SyscallNum};
|
||||
use aligned::{Aligned, A16};
|
||||
use core::arch::x86_64::_fxsave;
|
||||
|
||||
@ -15,26 +15,33 @@ pub fn init() {
|
||||
}
|
||||
|
||||
extern "C" fn handle_interrupt(info: *mut sgx_interrupt_info_t) -> i32 {
|
||||
// Rust compiler would complain about passing to external C functions a CpuContext
|
||||
// pointer, which includes a FpRegs pointer that is not safe to use by external
|
||||
// modules. In our case, the FpRegs pointer will not be used actually. So the
|
||||
// Rust warning is a false alarm. We suppress it here.
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
fn __occlum_syscall_c_abi(
|
||||
num: u32,
|
||||
info: *mut sgx_interrupt_info_t,
|
||||
fpregs: *mut u8,
|
||||
fpregs: *mut FpRegs,
|
||||
) -> u32;
|
||||
}
|
||||
|
||||
let mut fpregs: Aligned<A16, _> = Aligned([0u8; 512]);
|
||||
let mut fpregs = fpregs.as_mut_ptr();
|
||||
let mut fpregs = FpRegs::save();
|
||||
unsafe {
|
||||
_fxsave(fpregs);
|
||||
__occlum_syscall_c_abi(SyscallNum::HandleInterrupt as u32, info, fpregs)
|
||||
__occlum_syscall_c_abi(
|
||||
SyscallNum::HandleInterrupt as u32,
|
||||
info,
|
||||
&mut fpregs as *mut FpRegs,
|
||||
)
|
||||
};
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub fn do_handle_interrupt(
|
||||
info: *mut sgx_interrupt_info_t,
|
||||
fpregs: *mut u8,
|
||||
fpregs: *mut FpRegs,
|
||||
cpu_context: *mut CpuContext,
|
||||
) -> Result<isize> {
|
||||
let info = unsafe { &*info };
|
||||
|
@ -5,7 +5,7 @@ use super::{SigAction, SigActionFlags, SigDefaultAction, SigSet, Signal};
|
||||
use crate::lazy_static::__Deref;
|
||||
use crate::prelude::*;
|
||||
use crate::process::{ProcessRef, TermStatus, ThreadRef};
|
||||
use crate::syscall::CpuContext;
|
||||
use crate::syscall::{CpuContext, FpRegs};
|
||||
use aligned::{Aligned, A16};
|
||||
use core::arch::x86_64::{_fxrstor, _fxsave};
|
||||
use std::{ptr, slice};
|
||||
@ -36,9 +36,8 @@ pub fn do_rt_sigreturn(curr_user_ctxt: &mut CpuContext) -> Result<()> {
|
||||
// Restore the floating point registers to a temp area
|
||||
// The floating point registers would be recoved just
|
||||
// before return to user's code
|
||||
let mut fpregs: Box<Aligned<A16, [u8]>> = Box::new(Aligned([0u8; 512]));
|
||||
fpregs.copy_from_slice(&last_ucontext.fpregs);
|
||||
curr_user_ctxt.fpregs = Box::into_raw(fpregs) as *mut u8;
|
||||
let mut fpregs = Box::new(unsafe { FpRegs::from_slice(&last_ucontext.fpregs) });
|
||||
curr_user_ctxt.fpregs = Box::into_raw(fpregs);
|
||||
curr_user_ctxt.fpregs_on_heap = 1; // indicates the fpregs is on heap
|
||||
Ok(())
|
||||
}
|
||||
@ -266,18 +265,17 @@ fn handle_signals_by_user(
|
||||
|
||||
// Save the floating point registers
|
||||
if curr_user_ctxt.fpregs != ptr::null_mut() {
|
||||
let fpregs =
|
||||
unsafe { slice::from_raw_parts(curr_user_ctxt.fpregs, ucontext.fpregs.len()) };
|
||||
ucontext.fpregs.copy_from_slice(fpregs);
|
||||
ucontext
|
||||
.fpregs
|
||||
.copy_from_slice(unsafe { curr_user_ctxt.fpregs.as_ref().unwrap().as_slice() });
|
||||
// Clear the floating point registers, since we do not need to recover is when this syscall return
|
||||
curr_user_ctxt.fpregs = ptr::null_mut();
|
||||
} else {
|
||||
// We need a correct fxsave structure in the buffer,
|
||||
// because the app may modify part of it to update the
|
||||
// floating point after the signal handler finished.
|
||||
let mut fpregs: Aligned<A16, _> = Aligned([0u8; 512]);
|
||||
unsafe { _fxsave(fpregs.as_mut_ptr()) };
|
||||
ucontext.fpregs.copy_from_slice(fpregs.deref());
|
||||
let fpregs = FpRegs::save();
|
||||
ucontext.fpregs.copy_from_slice(fpregs.as_slice());
|
||||
}
|
||||
|
||||
ucontext as *mut ucontext_t
|
||||
|
@ -8,11 +8,13 @@
|
||||
//! 4. Call `do_*` to process the system call (in other modules)
|
||||
|
||||
use aligned::{Aligned, A16};
|
||||
use core::arch::x86_64::_fxrstor;
|
||||
use core::arch::x86_64::{_fxrstor, _fxsave};
|
||||
use std::any::Any;
|
||||
use std::convert::TryFrom;
|
||||
use std::default::Default;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use time::{clockid_t, timespec_t, timeval_t};
|
||||
use util::log::{self, LevelFilter};
|
||||
@ -410,8 +412,8 @@ macro_rules! process_syscall_table_with_callback {
|
||||
|
||||
// Occlum-specific system calls
|
||||
(Spawn = 360) => do_spawn(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fdop_list: *const FdOp),
|
||||
(HandleException = 361) => do_handle_exception(info: *mut sgx_exception_info_t, fpregs: *mut u8, context: *mut CpuContext),
|
||||
(HandleInterrupt = 362) => do_handle_interrupt(info: *mut sgx_interrupt_info_t, fpregs: *mut u8, context: *mut CpuContext),
|
||||
(HandleException = 361) => do_handle_exception(info: *mut sgx_exception_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
||||
(HandleInterrupt = 362) => do_handle_interrupt(info: *mut sgx_interrupt_info_t, fpregs: *mut FpRegs, context: *mut CpuContext),
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -714,6 +716,11 @@ fn do_syscall(user_context: &mut CpuContext) {
|
||||
|
||||
/// Return to the user space according to the given CPU context
|
||||
fn do_sysret(user_context: &mut CpuContext) -> ! {
|
||||
// Rust compiler would complain about passing to external C functions a CpuContext
|
||||
// pointer, which includes a FpRegs pointer that is not safe to use by external
|
||||
// modules. In our case, the FpRegs pointer will not be used actually. So the
|
||||
// Rust warning is a false alarm. We suppress it here.
|
||||
#[allow(improper_ctypes)]
|
||||
extern "C" {
|
||||
fn __occlum_sysret(user_context: *mut CpuContext) -> !;
|
||||
fn do_exit_task() -> !;
|
||||
@ -721,20 +728,20 @@ fn do_sysret(user_context: &mut CpuContext) -> ! {
|
||||
if current!().status() != ThreadStatus::Exited {
|
||||
// Restore the floating point registers
|
||||
// Todo: Is it correct to do fxstor in kernel?
|
||||
let fpregs: *const u8 = user_context.fpregs;
|
||||
if (fpregs != ptr::null()) {
|
||||
unsafe { _fxrstor(fpregs) };
|
||||
|
||||
let fpregs = user_context.fpregs;
|
||||
if (fpregs != ptr::null_mut()) {
|
||||
if user_context.fpregs_on_heap == 1 {
|
||||
// Converting the raw pointer back into a Box with Box::from_raw for automatic cleanup
|
||||
unsafe {
|
||||
let buf: &mut [u8] = core::slice::from_raw_parts_mut(user_context.fpregs, 512);
|
||||
let _ = Box::from_raw(buf);
|
||||
}
|
||||
let fpregs = unsafe { Box::from_raw(user_context.fpregs as *mut FpRegs) };
|
||||
fpregs.restore();
|
||||
} else {
|
||||
unsafe { fpregs.as_ref().unwrap().restore() };
|
||||
}
|
||||
}
|
||||
unsafe { __occlum_sysret(user_context) } // jump to user space
|
||||
} else {
|
||||
if user_context.fpregs != ptr::null_mut() && user_context.fpregs_on_heap == 1 {
|
||||
drop(unsafe { Box::from_raw(user_context.fpregs as *mut FpRegs) });
|
||||
}
|
||||
unsafe { do_exit_task() } // exit enclave
|
||||
}
|
||||
unreachable!("__occlum_sysret never returns!");
|
||||
@ -888,6 +895,49 @@ fn handle_unsupported() -> Result<isize> {
|
||||
return_errno!(ENOSYS, "Unimplemented or unknown syscall")
|
||||
}
|
||||
|
||||
/// Floating point registers
|
||||
///
|
||||
/// Note. The area is used to save fxsave result
|
||||
//#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct FpRegs {
|
||||
inner: Aligned<A16, [u8; 512]>,
|
||||
}
|
||||
|
||||
impl FpRegs {
|
||||
/// Save the current CPU floating pointer states to an instance of FpRegs
|
||||
pub fn save() -> Self {
|
||||
let mut fpregs = FpRegs {
|
||||
inner: Aligned([0u8; 512]),
|
||||
};
|
||||
unsafe { _fxsave(fpregs.inner.as_mut_ptr()) };
|
||||
fpregs
|
||||
}
|
||||
|
||||
/// Restore the current CPU floating pointer states from this FpRegs instance
|
||||
pub fn restore(&self) {
|
||||
unsafe { _fxrstor(self.inner.as_ptr()) };
|
||||
}
|
||||
|
||||
/// Construct a FpRegs from a slice of u8.
|
||||
///
|
||||
/// It is up to the caller to ensure that the src slice contains data that
|
||||
/// is the xsave/xrstor format.
|
||||
pub unsafe fn from_slice(src: &[u8]) -> Self {
|
||||
let mut uninit = MaybeUninit::<Self>::uninit();
|
||||
let dst_buf: &mut [u8] = std::slice::from_raw_parts_mut(
|
||||
uninit.as_mut_ptr() as *mut u8,
|
||||
std::mem::size_of::<FpRegs>(),
|
||||
);
|
||||
dst_buf.copy_from_slice(&src);
|
||||
uninit.assume_init()
|
||||
}
|
||||
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
/// Cpu context.
|
||||
///
|
||||
/// Note. The definition of this struct must be kept in sync with the assembly
|
||||
@ -914,7 +964,7 @@ pub struct CpuContext {
|
||||
pub rip: u64,
|
||||
pub rflags: u64,
|
||||
pub fpregs_on_heap: u64,
|
||||
pub fpregs: *mut u8,
|
||||
pub fpregs: *mut FpRegs,
|
||||
}
|
||||
|
||||
impl CpuContext {
|
||||
|
@ -28,8 +28,8 @@ __occlum_syscall_linux_abi:
|
||||
// Save the target CPU state when `call __occlum_syscall` is returned in
|
||||
// a CpuContext struct. The registers are saved in the reverse order of
|
||||
// the fields in CpuContext.
|
||||
push $0 // default fpregs is NULL
|
||||
push $0 // default fpregs is allocated on stack
|
||||
pushq $0 // default fpregs is NULL
|
||||
pushq $0 // default fpregs is allocated on stack
|
||||
pushfq
|
||||
push %rcx // save %rip
|
||||
push %r11 // save %rsp
|
||||
|
@ -142,7 +142,12 @@ impl InnerAgent {
|
||||
let mut quote_len: u32 = 0;
|
||||
let mut rt = Default::default();
|
||||
let status = unsafe {
|
||||
occlum_ocall_sgx_calc_quote_size(&mut rt as _, sigrl_ptr, sigrl_size, &mut quote_len as _)
|
||||
occlum_ocall_sgx_calc_quote_size(
|
||||
&mut rt as _,
|
||||
sigrl_ptr,
|
||||
sigrl_size,
|
||||
&mut quote_len as _,
|
||||
)
|
||||
};
|
||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
||||
if rt != sgx_status_t::SGX_SUCCESS {
|
||||
|
Loading…
Reference in New Issue
Block a user