Report the underlying SGX protected file I/O error
This commit is contained in:
parent
9a47791ae3
commit
230e6fa380
2
deps/sefs
vendored
2
deps/sefs
vendored
@ -1 +1 @@
|
||||
Subproject commit 7ad4158794622216e47439534e3a34996f2bbd77
|
||||
Subproject commit 4fcf7d39f54a74628473310ab25bc2b678883ab6
|
@ -36,7 +36,13 @@ resources.
|
||||
|
||||
- Solution: Enlarge `resource_limits.kernel_space_heap_size`
|
||||
|
||||
5. LibOS thread execution error:
|
||||
5. SGX protected file I/O error:
|
||||
- Error message: `SGX protected file I/O error: EIO (#5, I/O error): Cannot
|
||||
allocate memory (os error: 12)`
|
||||
|
||||
- Solution: Enlarge `resource_limits.kernel_space_heap_size`
|
||||
|
||||
6. LibOS thread execution error:
|
||||
- Error message: `[ERROR] occlum-pal: Failed to enter the enclave to
|
||||
execute a LibOS thread (host tid = XXX): Unknown SGX error`
|
||||
|
||||
|
@ -86,7 +86,7 @@ impl ToErrno for rcore_fs::vfs::FsError {
|
||||
FsError::DirRemoved => ENOENT,
|
||||
FsError::DirNotEmpty => ENOTEMPTY,
|
||||
FsError::WrongFs => EINVAL,
|
||||
FsError::DeviceError => EIO,
|
||||
FsError::DeviceError(err) => EIO,
|
||||
FsError::SymLoop => ELOOP,
|
||||
FsError::NoDevice => ENXIO,
|
||||
FsError::IOCTLError => EINVAL,
|
||||
|
@ -1,5 +1,7 @@
|
||||
use super::*;
|
||||
use rcore_fs_sefs::dev::{DevResult, DeviceError, File, SefsMac, Storage};
|
||||
use crate::error::*;
|
||||
use rcore_fs::dev::{DevError, DevResult};
|
||||
use rcore_fs_sefs::dev::{File, SefsMac, Storage};
|
||||
use std::boxed::Box;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::BTreeMap;
|
||||
@ -10,6 +12,20 @@ use std::sgxfs::{remove, OpenOptions, SgxFile};
|
||||
use std::sync::{Arc, SgxMutex as Mutex};
|
||||
use std::untrusted::fs;
|
||||
|
||||
/// A helper macro to automatically convert a block of code that returns `std::result::Result<T, E1>`
|
||||
/// to one that returns `std::result::Result<T, E2>`, where `E1` satisfies `impl From<E1> for Error`
|
||||
/// and `E2` satisfies `impl From<Error> for E2`.
|
||||
///
|
||||
/// This macro is designed to workaround the limitation that `From<E1>` cannot be implemented for
|
||||
/// `E2` when both `E1` and `E2` are foreign types. For example, when `E1` is `std::io::Error` and
|
||||
/// `E2` is `rcore_fs::dev::DevError`.
|
||||
macro_rules! convert_result {
|
||||
($body: block) => {{
|
||||
let mut closure_fn = || -> Result<_> { $body };
|
||||
Ok(closure_fn()?)
|
||||
}};
|
||||
}
|
||||
|
||||
pub struct SgxStorage {
|
||||
path: PathBuf,
|
||||
integrity_only: bool,
|
||||
@ -23,7 +39,7 @@ impl SgxStorage {
|
||||
integrity_only: bool,
|
||||
file_mac: Option<sgx_aes_gcm_128bit_tag_t>,
|
||||
) -> Self {
|
||||
// assert!(path.as_ref().is_dir());
|
||||
// assert!(path.as_ref().is_dir());
|
||||
SgxStorage {
|
||||
path: path.as_ref().to_path_buf(),
|
||||
integrity_only: integrity_only,
|
||||
@ -38,8 +54,8 @@ impl SgxStorage {
|
||||
fn get(
|
||||
&self,
|
||||
file_id: &str,
|
||||
open_fn: impl FnOnce(&Self) -> DevResult<LockedFile>,
|
||||
) -> DevResult<LockedFile> {
|
||||
open_fn: impl FnOnce(&Self) -> Result<LockedFile>,
|
||||
) -> Result<LockedFile> {
|
||||
// query cache
|
||||
let key = self.calculate_hash(file_id);
|
||||
let mut caches = self.file_cache.lock().unwrap();
|
||||
@ -64,8 +80,8 @@ impl SgxStorage {
|
||||
fn get(
|
||||
&self,
|
||||
file_id: &str,
|
||||
open_fn: impl FnOnce(&Self) -> DevResult<LockedFile>,
|
||||
) -> LockedFile {
|
||||
open_fn: impl FnOnce(&Self) -> Result<LockedFile>,
|
||||
) -> Result<LockedFile> {
|
||||
open_fn(self)
|
||||
}
|
||||
|
||||
@ -73,7 +89,7 @@ impl SgxStorage {
|
||||
///
|
||||
/// By giving this root MAC, we can be sure that the root file (file_id = 0) opened
|
||||
/// by the storage has a MAC that is equal to the given root MAC.
|
||||
pub fn set_root_mac(&mut self, mac: sgx_aes_gcm_128bit_tag_t) -> DevResult<()> {
|
||||
pub fn set_root_mac(&mut self, mac: sgx_aes_gcm_128bit_tag_t) -> Result<()> {
|
||||
self.root_mac = Some(mac);
|
||||
Ok(())
|
||||
}
|
||||
@ -89,16 +105,10 @@ impl Storage for SgxStorage {
|
||||
options.read(true).update(true);
|
||||
options
|
||||
};
|
||||
let file = {
|
||||
let open_res = if !self.integrity_only {
|
||||
options.open(path)
|
||||
} else {
|
||||
options.open_integrity_only(path)
|
||||
};
|
||||
if open_res.is_err() {
|
||||
return Err(DeviceError);
|
||||
}
|
||||
open_res.unwrap()
|
||||
let file = if !self.integrity_only {
|
||||
options.open(path)?
|
||||
} else {
|
||||
options.open_integrity_only(path)?
|
||||
};
|
||||
|
||||
// Check the MAC of the root file against the given root MAC of the storage
|
||||
@ -110,7 +120,7 @@ impl Storage for SgxStorage {
|
||||
self.root_mac.unwrap(),
|
||||
root_file_mac
|
||||
);
|
||||
return Err(DeviceError);
|
||||
return_errno!(EACCES);
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,16 +138,10 @@ impl Storage for SgxStorage {
|
||||
options.write(true).update(true);
|
||||
options
|
||||
};
|
||||
let file = {
|
||||
let open_res = if !self.integrity_only {
|
||||
options.open(path)
|
||||
} else {
|
||||
options.open_integrity_only(path)
|
||||
};
|
||||
if open_res.is_err() {
|
||||
return Err(DeviceError);
|
||||
}
|
||||
open_res.unwrap()
|
||||
let file = if !self.integrity_only {
|
||||
options.open(path)?
|
||||
} else {
|
||||
options.open_integrity_only(path)?
|
||||
};
|
||||
Ok(LockedFile(Arc::new(Mutex::new(file))))
|
||||
})?;
|
||||
@ -145,14 +149,16 @@ impl Storage for SgxStorage {
|
||||
}
|
||||
|
||||
fn remove(&self, file_id: &str) -> DevResult<()> {
|
||||
let mut path = self.path.to_path_buf();
|
||||
path.push(file_id);
|
||||
remove(path).expect("failed to remove SgxFile");
|
||||
// remove from cache
|
||||
let key = self.calculate_hash(file_id);
|
||||
let mut caches = self.file_cache.lock().unwrap();
|
||||
caches.remove(&key);
|
||||
Ok(())
|
||||
convert_result!({
|
||||
let mut path = self.path.to_path_buf();
|
||||
path.push(file_id);
|
||||
remove(path)?;
|
||||
// remove from cache
|
||||
let key = self.calculate_hash(file_id);
|
||||
let mut caches = self.file_cache.lock().unwrap();
|
||||
caches.remove(&key);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn is_integrity_only(&self) -> bool {
|
||||
@ -160,14 +166,16 @@ impl Storage for SgxStorage {
|
||||
}
|
||||
|
||||
fn clear(&self) -> DevResult<()> {
|
||||
for child in fs::read_dir(&self.path).expect("faild to read dir") {
|
||||
let child = child.expect("faild to get dir entry");
|
||||
remove(&child.path()).expect("failed to remove SgxFile");
|
||||
}
|
||||
// clear cache
|
||||
let mut caches = self.file_cache.lock().unwrap();
|
||||
caches.clear();
|
||||
Ok(())
|
||||
convert_result!({
|
||||
for child in fs::read_dir(&self.path)? {
|
||||
let child = child?;
|
||||
remove(&child.path())?;
|
||||
}
|
||||
// clear cache
|
||||
let mut caches = self.file_cache.lock().unwrap();
|
||||
caches.clear();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,49 +188,51 @@ unsafe impl Sync for LockedFile {}
|
||||
|
||||
impl File for LockedFile {
|
||||
fn read_at(&self, buf: &mut [u8], offset: usize) -> DevResult<usize> {
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut file = self.0.lock().unwrap();
|
||||
convert_result!({
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut file = self.0.lock().unwrap();
|
||||
|
||||
// SgxFile does not support to seek a position beyond the end.
|
||||
// So check if file_size < offset and return zero(indicates end of file).
|
||||
let file_size = file.seek(SeekFrom::End(0)).expect("failed to tell SgxFile") as usize;
|
||||
if file_size < offset {
|
||||
return Ok(0);
|
||||
}
|
||||
// SgxFile does not support to seek a position beyond the end.
|
||||
// So check if file_size < offset and return zero(indicates end of file).
|
||||
let file_size = file.seek(SeekFrom::End(0))? as usize;
|
||||
if file_size < offset {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let offset = offset as u64;
|
||||
file.seek(SeekFrom::Start(offset))
|
||||
.expect("failed to seek SgxFile");
|
||||
let len = file.read(buf).expect("failed to read SgxFile");
|
||||
Ok(len)
|
||||
let offset = offset as u64;
|
||||
file.seek(SeekFrom::Start(offset))?;
|
||||
let len = file.read(buf)?;
|
||||
Ok(len)
|
||||
})
|
||||
}
|
||||
|
||||
fn write_at(&self, buf: &[u8], offset: usize) -> DevResult<usize> {
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let mut file = self.0.lock().unwrap();
|
||||
|
||||
// SgxFile does not support to seek a position beyond the end.
|
||||
// So check if file_size < offset and padding null bytes.
|
||||
let file_size = file.seek(SeekFrom::End(0)).expect("failed to tell SgxFile") as usize;
|
||||
if file_size < offset {
|
||||
static ZEROS: [u8; 0x1000] = [0; 0x1000];
|
||||
let mut rest_len = offset - file_size;
|
||||
while rest_len != 0 {
|
||||
let l = rest_len.min(0x1000);
|
||||
let len = file.write(&ZEROS[..l]).expect("failed to write SgxFile");
|
||||
rest_len -= len;
|
||||
convert_result!({
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
let mut file = self.0.lock().unwrap();
|
||||
|
||||
let offset = offset as u64;
|
||||
file.seek(SeekFrom::Start(offset))
|
||||
.expect("failed to seek SgxFile");
|
||||
let len = file.write(buf).expect("failed to write SgxFile");
|
||||
Ok(len)
|
||||
// SgxFile does not support to seek a position beyond the end.
|
||||
// So check if file_size < offset and padding null bytes.
|
||||
let file_size = file.seek(SeekFrom::End(0))? as usize;
|
||||
if file_size < offset {
|
||||
static ZEROS: [u8; 0x1000] = [0; 0x1000];
|
||||
let mut rest_len = offset - file_size;
|
||||
while rest_len != 0 {
|
||||
let l = rest_len.min(0x1000);
|
||||
let len = file.write(&ZEROS[..l])?;
|
||||
rest_len -= len;
|
||||
}
|
||||
}
|
||||
|
||||
let offset = offset as u64;
|
||||
file.seek(SeekFrom::Start(offset))?;
|
||||
let len = file.write(buf)?;
|
||||
Ok(len)
|
||||
})
|
||||
}
|
||||
|
||||
fn set_len(&self, len: usize) -> DevResult<()> {
|
||||
@ -231,9 +241,11 @@ impl File for LockedFile {
|
||||
}
|
||||
|
||||
fn flush(&self) -> DevResult<()> {
|
||||
let mut file = self.0.lock().unwrap();
|
||||
file.flush().expect("failed to flush SgxFile");
|
||||
Ok(())
|
||||
convert_result!({
|
||||
let mut file = self.0.lock().unwrap();
|
||||
file.flush()?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_file_mac(&self) -> DevResult<SefsMac> {
|
||||
@ -241,3 +253,10 @@ impl File for LockedFile {
|
||||
Ok(SefsMac(file.get_mac().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for DevError {
|
||||
fn from(e: Error) -> Self {
|
||||
error!("SGX protected file I/O error: {}", e.backtrace());
|
||||
DevError(e.errno() as i32)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user