Add open, read, write and close
This commit is contained in:
parent
757d3f2f4d
commit
a66c55f95f
@ -1,34 +1,46 @@
|
||||
use xmas_elf::{ElfFile, program, P64};
|
||||
use xmas_elf::sections;
|
||||
use prelude::*;
|
||||
|
||||
use xmas_elf::{sections, ElfFile, program, P64};
|
||||
use xmas_elf::symbol_table::{Entry64, DynEntry64};
|
||||
use xmas_elf::program::{ProgramHeader};
|
||||
use xmas_elf::sections::{Rela};
|
||||
use xmas_elf::symbol_table::Entry;
|
||||
|
||||
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), &'static str> {
|
||||
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), Error> {
|
||||
println!("Program headers:");
|
||||
let ph_iter = elf_file.program_iter();
|
||||
for sect in ph_iter {
|
||||
program::sanity_check(sect, &elf_file)?;
|
||||
program::sanity_check(sect, &elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Sanity check for program header failed"))?;
|
||||
println!("\t{:?}", sect.get_type());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_sections(elf_file: &ElfFile) -> Result<(), &'static str> {
|
||||
pub fn print_sections(elf_file: &ElfFile) -> Result<(), Error> {
|
||||
println!("Sections:");
|
||||
let mut sect_iter = elf_file.section_iter();
|
||||
sect_iter.next(); // Skip the first, dummy section
|
||||
for sect in sect_iter {
|
||||
sections::sanity_check(sect, &elf_file)?;
|
||||
println!("\t{}\n{:?}", sect.get_name(&elf_file)?, sect);
|
||||
sections::sanity_check(sect, &elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Sanity check for program header failed"))?;
|
||||
let sec_name = sect.get_name(&elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Failed to get section name"))?;
|
||||
println!("\t{}\n{:?}", sec_name, sect);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), &'static str> {
|
||||
let rela_entries = get_pltrel_entries(elf_file)?;
|
||||
let dynsym_entries = get_dynsym_entries(elf_file)?;
|
||||
pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), Error> {
|
||||
let rela_entries = get_pltrel_entries(elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Failed to get .pltrel entries"))?;
|
||||
let dynsym_entries = get_dynsym_entries(elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Failed to get .dynsym entries"))?;
|
||||
|
||||
println!(".plt.rela section:");
|
||||
for entry in rela_entries {
|
||||
@ -40,51 +52,55 @@ pub fn print_pltrel_section(elf_file: &ElfFile) -> Result<(), &'static str> {
|
||||
|
||||
let symidx = entry.get_symbol_table_index() as usize;
|
||||
let dynsym_entry = &dynsym_entries[symidx];
|
||||
println!("\t\t{} = {:?}",
|
||||
dynsym_entry.get_name(&elf_file)?, dynsym_entry);
|
||||
let dynsym_name = dynsym_entry.get_name(&elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC,
|
||||
"Failed to get the name of a dynamic symbol"))?;
|
||||
println!("\t\t{} = {:?}", dynsym_name, dynsym_entry);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_data_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<ProgramHeader<'a>, &'static str>
|
||||
-> Result<ProgramHeader<'a>, Error>
|
||||
{
|
||||
let mut ph_iter = elf_file.program_iter();
|
||||
ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) &&
|
||||
!ph.flags().is_execute() &&
|
||||
ph.flags().is_write() &&
|
||||
ph.flags().is_read())
|
||||
.ok_or("Cannot find .data in the program header of ELF")
|
||||
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get the data segment").into())
|
||||
}
|
||||
|
||||
pub fn get_code_program_header<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<ProgramHeader<'a>, &'static str>
|
||||
-> Result<ProgramHeader<'a>, Error>
|
||||
{
|
||||
let mut ph_iter = elf_file.program_iter();
|
||||
ph_iter.find(|&ph| ph.get_type() == Ok(program::Type::Load) &&
|
||||
ph.flags().is_execute() &&
|
||||
!ph.flags().is_write() &&
|
||||
ph.flags().is_read())
|
||||
.ok_or("Cannot find .text in the program header of ELF")
|
||||
.ok_or_else(|| (Errno::ENOEXEC, "Failed to get the code segment").into())
|
||||
}
|
||||
|
||||
pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<usize, &'static str>
|
||||
-> Result<usize, Error>
|
||||
{
|
||||
let sym_entries = get_sym_entries(elf_file)?;
|
||||
|
||||
for sym_entry in sym_entries {
|
||||
let sym_str = sym_entry.get_name(elf_file)?;
|
||||
let sym_str = sym_entry.get_name(elf_file)
|
||||
.map_err(|e| Error::new(Errno::ENOEXEC,
|
||||
"Failed to get the name of a symbol"))?;
|
||||
if sym_str == "_start" {
|
||||
return Ok(sym_entry.value() as usize)
|
||||
}
|
||||
}
|
||||
|
||||
Err("Cannot find _start symbol")
|
||||
Err((Errno::ENOEXEC, "Failed to get the _start symbol").into())
|
||||
}
|
||||
|
||||
pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<&'a [Entry64], &'static str>
|
||||
-> Result<&'a [Entry64], Error>
|
||||
{
|
||||
elf_file.find_section_by_name(".symtab")
|
||||
.and_then(|symtab_section| {
|
||||
@ -94,11 +110,11 @@ pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
sections::SectionData::SymbolTable64(entries) => Some(entries),
|
||||
_ => None,
|
||||
}
|
||||
}).ok_or("Cannot find or load .dynsym section")
|
||||
}).ok_or_else(|| (Errno::ENOEXEC, "Failed get the symbol entries").into())
|
||||
}
|
||||
|
||||
pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<&'a [Rela<P64>], &'static str>
|
||||
-> Result<&'a [Rela<P64>], Error>
|
||||
{
|
||||
elf_file.find_section_by_name(".rela.plt")
|
||||
.and_then(|plt_rela_section| {
|
||||
@ -108,11 +124,11 @@ pub fn get_pltrel_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
sections::SectionData::Rela64(entries) => Some(entries),
|
||||
_ => None,
|
||||
}
|
||||
}).ok_or("Cannot find or load .rela.plt section")
|
||||
}).ok_or_else(|| (Errno::ENOEXEC, "Failed to get .rela.plt entries").into())
|
||||
}
|
||||
|
||||
pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
-> Result<&'a [DynEntry64], &'static str>
|
||||
-> Result<&'a [DynEntry64], Error>
|
||||
{
|
||||
elf_file.find_section_by_name(".dynsym")
|
||||
.and_then(|dynamic_section| {
|
||||
@ -122,5 +138,5 @@ pub fn get_dynsym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>)
|
||||
sections::SectionData::DynSymbolTable64(entries) => Some(entries),
|
||||
_ => None,
|
||||
}
|
||||
}).ok_or("Cannot find or load .dynsym section")
|
||||
}).ok_or_else(|| (Errno::ENOEXEC, "Failed to get .dynsym entries").into())
|
||||
}
|
||||
|
@ -1,9 +1,51 @@
|
||||
use std;
|
||||
use std::fmt;
|
||||
use prelude::*;
|
||||
use std::{fmt, error, convert,};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum Errno {
|
||||
OK = 0,
|
||||
pub struct Error {
|
||||
pub errno: Errno,
|
||||
pub desc: &'static str,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(errno: Errno, desc: &'static str) -> Error {
|
||||
let ret = Error {
|
||||
errno,
|
||||
desc,
|
||||
};
|
||||
println!("{}", ret);
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl convert::From<(Errno, &'static str)> for Error {
|
||||
fn from(info: (Errno, &'static str)) -> Error {
|
||||
Error::new(
|
||||
info.0,
|
||||
info.1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
self.desc
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Error: {} ({})", self.desc, self.errno)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Errno {
|
||||
EUNDEF = 0,
|
||||
EPERM = 1,
|
||||
ENOENT = 2,
|
||||
ESRCH = 3,
|
||||
@ -44,23 +86,16 @@ enum Errno {
|
||||
}
|
||||
|
||||
impl Errno {
|
||||
fn as_retval(&self) -> i32 {
|
||||
*self as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Errno {
|
||||
fn default() -> Errno {
|
||||
Errno::OK
|
||||
pub fn as_retval(&self) -> i32 {
|
||||
- (*self as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Errno {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} ({})",
|
||||
*self as i32,
|
||||
write!(f, "errno = {}, \"{}\"",
|
||||
*self as u32,
|
||||
match *self {
|
||||
Errno::OK => "Ok",
|
||||
Errno::EPERM => "Operation not permitted",
|
||||
Errno::ENOENT => "No such file or directory",
|
||||
Errno::ESRCH => "No such process",
|
||||
@ -98,7 +133,10 @@ impl fmt::Display for Errno {
|
||||
Errno::EDEADLK => "Resource deadlock would occur",
|
||||
Errno::ENAMETOOLONG => "File name too long",
|
||||
Errno::ENOLCK => "No record locks available",
|
||||
_ => "Unknown",
|
||||
})
|
||||
_ => "Unknown error",
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
177
src/libos/src/file.rs
Normal file
177
src/libos/src/file.rs
Normal file
@ -0,0 +1,177 @@
|
||||
use prelude::*;
|
||||
use {std};
|
||||
use std::{fmt};
|
||||
|
||||
use std::sgxfs as fs_impl;
|
||||
use std::io::{Read, Write, Seek, SeekFrom};
|
||||
|
||||
pub trait File : Debug + Sync + Send {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error>;
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error>;
|
||||
//pub seek(&mut self, ) -> Result<usize, Error>;
|
||||
|
||||
}
|
||||
|
||||
pub type FileRef = Arc<Box<File>>;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct SgxFile {
|
||||
inner: SgxMutex<SgxFileInner>,
|
||||
}
|
||||
|
||||
impl SgxFile {
|
||||
pub fn new(file: Arc<SgxMutex<fs_impl::SgxFile>>,
|
||||
is_readable: bool, is_writable: bool, is_append: bool) -> SgxFile
|
||||
{
|
||||
SgxFile {
|
||||
inner: SgxMutex::new(SgxFileInner {
|
||||
pos: 0 as usize,
|
||||
file: file,
|
||||
is_readable,
|
||||
is_writable,
|
||||
is_append,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File for SgxFile {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let mut inner_guard = self.inner.lock().unwrap();
|
||||
let inner = inner_guard.borrow_mut();
|
||||
inner.read(buf)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
let mut inner_guard = self.inner.lock().unwrap();
|
||||
let inner = inner_guard.borrow_mut();
|
||||
inner.write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
struct SgxFileInner {
|
||||
// perms: FilePerms,
|
||||
pos: usize,
|
||||
file: Arc<SgxMutex<fs_impl::SgxFile>>,
|
||||
is_readable: bool,
|
||||
is_writable: bool,
|
||||
is_append: bool,
|
||||
}
|
||||
|
||||
impl SgxFileInner {
|
||||
pub fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
|
||||
let mut file_guard = self.file.lock().unwrap();
|
||||
let file = file_guard.borrow_mut();
|
||||
|
||||
let seek_pos = SeekFrom::Start(self.pos as u64);
|
||||
file.seek(seek_pos).map_err(
|
||||
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
|
||||
|
||||
let write_len = {
|
||||
file.write(buf).map_err(
|
||||
|e| Error::new(Errno::EINVAL, "Failed to write"))?
|
||||
};
|
||||
|
||||
self.pos += write_len;
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let mut file_guard = self.file.lock().unwrap();
|
||||
let file = file_guard.borrow_mut();
|
||||
|
||||
let seek_pos = SeekFrom::Start(self.pos as u64);
|
||||
file.seek(seek_pos).map_err(
|
||||
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
|
||||
|
||||
let read_len = {
|
||||
file.read(buf).map_err(
|
||||
|e| Error::new(Errno::EINVAL, "Failed to write"))?
|
||||
};
|
||||
|
||||
self.pos += read_len;
|
||||
Ok(read_len)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for SgxFileInner {}
|
||||
unsafe impl Sync for SgxFileInner {}
|
||||
|
||||
impl Debug for SgxFileInner {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "SgxFileInner {{ pos: {}, file: ??? }}", self.pos)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StdoutFile {
|
||||
inner: std::io::Stdout,
|
||||
}
|
||||
|
||||
impl StdoutFile {
|
||||
pub fn new() -> StdoutFile {
|
||||
StdoutFile {
|
||||
inner: std::io::stdout(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File for StdoutFile {
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
let write_len = {
|
||||
self.inner.lock().write(buf).map_err(|e| (Errno::EINVAL,
|
||||
"Failed to write"))?
|
||||
};
|
||||
Ok(write_len)
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
Err(Error::new(Errno::EBADF, "Stdout does not support reading"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for StdoutFile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "StdoutFile")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for StdoutFile {}
|
||||
unsafe impl Sync for StdoutFile {}
|
||||
|
||||
pub struct StdinFile {
|
||||
inner: std::io::Stdin,
|
||||
}
|
||||
|
||||
impl StdinFile {
|
||||
pub fn new() -> StdinFile {
|
||||
StdinFile {
|
||||
inner: std::io::stdin(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl File for StdinFile {
|
||||
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let read_len = {
|
||||
self.inner.lock().read(buf).map_err(|e| (Errno::EINVAL,
|
||||
"Failed to read"))?
|
||||
};
|
||||
Ok(read_len)
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
|
||||
Err(Error::new(Errno::EBADF, "Stdin does not support reading"))
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for StdinFile {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "StdinFile")
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for StdinFile {}
|
||||
unsafe impl Sync for StdinFile {}
|
81
src/libos/src/file_table.rs
Normal file
81
src/libos/src/file_table.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use prelude::*;
|
||||
use {std, file};
|
||||
use file::{File, FileRef};
|
||||
|
||||
pub type FileDesc = u32;
|
||||
|
||||
// Invariant 1: fd < max_fd, where fd is any fd in the table
|
||||
// Invariant 2: max_fd = table.size()
|
||||
// Invariant 3: num_fds <= table.size()
|
||||
#[derive(Clone, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct FileTable {
|
||||
table: Vec<Option<FileRef>>,
|
||||
max_fd: FileDesc,
|
||||
num_fds: u32,
|
||||
}
|
||||
|
||||
impl FileTable {
|
||||
pub fn new() -> FileTable {
|
||||
FileTable {
|
||||
table: Vec::with_capacity(0),
|
||||
max_fd: 0,
|
||||
num_fds: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put(&mut self, file: FileRef) -> FileDesc {
|
||||
let mut table = &mut self.table;
|
||||
|
||||
let free_fd = if self.num_fds < self.max_fd {
|
||||
table.iter().enumerate()
|
||||
.find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc
|
||||
} else {
|
||||
table.push(None);
|
||||
self.max_fd += 1;
|
||||
self.num_fds
|
||||
};
|
||||
|
||||
table[free_fd as usize] = Some(file);
|
||||
self.num_fds += 1;
|
||||
|
||||
free_fd
|
||||
}
|
||||
|
||||
pub fn get(&self, fd: FileDesc) -> Option<FileRef> {
|
||||
if fd >= self.max_fd {
|
||||
return None;
|
||||
}
|
||||
|
||||
let table = &self.table;
|
||||
table[fd as usize].as_ref().map(|file_ref| file_ref.clone())
|
||||
}
|
||||
|
||||
pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> {
|
||||
if fd >= self.max_fd {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut del_file = None;
|
||||
let table = &mut self.table;
|
||||
std::mem::swap(&mut del_file, &mut table[fd as usize]);
|
||||
if del_file.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.num_fds -= 1;
|
||||
if fd + 1 == self.max_fd {
|
||||
self.max_fd = table.iter().enumerate().rev()
|
||||
.find(|&(idx, opt)| opt.is_some())
|
||||
.map_or(0, |(max_used_fd,opt)| max_used_fd + 1) as FileDesc;
|
||||
}
|
||||
del_file
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FileTable {
|
||||
fn default() -> FileTable {
|
||||
FileTable::new()
|
||||
}
|
||||
}
|
||||
|
74
src/libos/src/fs.rs
Normal file
74
src/libos/src/fs.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use prelude::*;
|
||||
use {std, file, file_table, process};
|
||||
use file::{File, SgxFile};
|
||||
use file_table::{FileDesc};
|
||||
|
||||
use std::sgxfs as fs_impl;
|
||||
|
||||
pub const O_RDONLY : u32 = 0x00000000;
|
||||
pub const O_WRONLY : u32 = 0x00000001;
|
||||
pub const O_RDWR : u32 = 0x00000002;
|
||||
pub const O_CREAT : u32 = 0x00000040;
|
||||
pub const O_TRUNC : u32 = 0x00000200;
|
||||
pub const O_APPEND : u32 = 0x00000400;
|
||||
|
||||
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
|
||||
let open_options = {
|
||||
let mut open_options = fs_impl::OpenOptions::new();
|
||||
|
||||
if ((flags & O_TRUNC) != 0 || (flags & O_CREAT) != 0) {
|
||||
open_options.write(true);
|
||||
}
|
||||
else {
|
||||
open_options.read(true);
|
||||
}
|
||||
open_options.update(true).binary(true);
|
||||
|
||||
open_options
|
||||
};
|
||||
|
||||
let mut sgx_file = {
|
||||
let key : sgx_key_128bit_t = [0 as uint8_t; 16];
|
||||
let sgx_file = open_options.open_ex(path, &key)
|
||||
.map_err(|e| (Errno::ENOENT, "Failed to open the SGX-protected file") )?;
|
||||
Arc::new(SgxMutex::new(sgx_file))
|
||||
};
|
||||
|
||||
let is_readable = (flags & O_RDONLY != 0) || (flags & O_RDWR != 0);
|
||||
let is_writable = (flags & O_WRONLY != 0) || (flags & O_RDWR != 0);
|
||||
let is_append = (flags & O_APPEND != 0);
|
||||
let file_ref : Arc<Box<File>> = Arc::new(Box::new(
|
||||
SgxFile::new(sgx_file, is_readable, is_writable, is_append)));
|
||||
|
||||
let current_ref = process::get_current();
|
||||
let mut current_process = current_ref.lock().unwrap();
|
||||
let fd = current_process.file_table.put(file_ref);
|
||||
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
|
||||
let current_ref = process::get_current();
|
||||
let current_process = current_ref.lock().unwrap();
|
||||
let file_ref = current_process.file_table.get(fd)
|
||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor"))?;
|
||||
file_ref.write(buf)
|
||||
}
|
||||
|
||||
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
||||
let current_ref = process::get_current();
|
||||
let current_process = current_ref.lock().unwrap();
|
||||
let file_ref = current_process.file_table.get(fd)
|
||||
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor"))?;
|
||||
file_ref.read(buf)
|
||||
}
|
||||
|
||||
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
|
||||
let current_ref = process::get_current();
|
||||
let mut current_process = current_ref.lock().unwrap();
|
||||
let file_table = &mut current_process.file_table;
|
||||
match file_table.del(fd) {
|
||||
Some(_) => Ok(()),
|
||||
None => Err(Error::new(Errno::EBADF, "Invalid file descriptor")),
|
||||
}
|
||||
}
|
@ -24,12 +24,16 @@ use std::panic;
|
||||
use sgx_types::*;
|
||||
use sgx_trts::libc;
|
||||
|
||||
mod vma;
|
||||
mod prelude;
|
||||
mod elf_helper;
|
||||
mod errno;
|
||||
mod file;
|
||||
mod file_table;
|
||||
mod fs;
|
||||
mod mm;
|
||||
mod process;
|
||||
mod syscall;
|
||||
mod elf_helper;
|
||||
mod mm;
|
||||
mod errno;
|
||||
mod vma;
|
||||
|
||||
/// Export system calls
|
||||
pub use syscall::*;
|
||||
@ -44,8 +48,7 @@ pub extern "C" fn libos_boot(path_buf: *const i8) -> i32 {
|
||||
let _ = backtrace::enable_backtrace("librusgx.signed.so", PrintFormat::Short);
|
||||
panic::catch_unwind(||{
|
||||
backtrace::__rust_begin_short_backtrace(||{
|
||||
let mut pid = 0;
|
||||
let _ = process::do_spawn(&mut pid, &path_str);
|
||||
process::do_spawn(&path_str);
|
||||
})
|
||||
}).ok();
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
use sgx_types::{c_void, c_int, size_t};
|
||||
use sgx_trts::libc;
|
||||
use prelude::*;
|
||||
|
||||
use std::mem;
|
||||
use std::marker::Send;
|
||||
use std::marker::Sync;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MemObj {
|
||||
@ -13,16 +11,16 @@ pub struct MemObj {
|
||||
|
||||
impl MemObj {
|
||||
pub fn new(mem_size: usize, mem_align: usize)
|
||||
-> Result<Self, &'static str>
|
||||
-> Result<Self, Error>
|
||||
{
|
||||
if mem_size == 0 || !is_power_of_two(mem_align) ||
|
||||
mem_align % mem::size_of::<*const c_void>() != 0 {
|
||||
return Err("Invalid argument");
|
||||
return Err((Errno::EINVAL, "Invalid argument").into());
|
||||
}
|
||||
|
||||
let mem_ptr = unsafe { aligned_malloc(mem_size, mem_align) };
|
||||
if mem_ptr == (0 as *mut c_void) {
|
||||
return Err("Out of memory");
|
||||
return Err((Errno::ENOMEM, "Out of memory").into());
|
||||
};
|
||||
unsafe { memset(mem_ptr, 0 as c_int, mem_size as size_t) };
|
||||
|
||||
@ -59,7 +57,6 @@ impl Drop for MemObj {
|
||||
unsafe impl Send for MemObj {}
|
||||
unsafe impl Sync for MemObj {}
|
||||
|
||||
|
||||
fn is_power_of_two(x: usize) -> bool {
|
||||
return (x != 0) && ((x & (x - 1)) == 0);
|
||||
}
|
||||
|
18
src/libos/src/prelude.rs
Normal file
18
src/libos/src/prelude.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use std;
|
||||
pub use sgx_types::*;
|
||||
pub use sgx_trts::libc;
|
||||
|
||||
//pub use {elf_helper, errno, file, file_table, fs, mm, process, syscall, vma, };
|
||||
|
||||
pub use std::marker::{Sync, Send};
|
||||
pub use std::sync::{Arc, SgxMutex, SgxMutexGuard, SgxRwLock,
|
||||
SgxRwLockReadGuard, SgxRwLockWriteGuard};
|
||||
pub use std::result::Result;
|
||||
pub use std::borrow::BorrowMut;
|
||||
pub use std::boxed::Box;
|
||||
pub use std::vec::Vec;
|
||||
pub use std::collections::{HashMap, VecDeque};
|
||||
pub use std::fmt::{Debug, Display};
|
||||
|
||||
pub use errno::Error as Error;
|
||||
pub use errno::Errno;
|
@ -1,26 +1,20 @@
|
||||
use std;
|
||||
use std::vec::Vec;
|
||||
use prelude::*;
|
||||
use {std, elf_helper, vma, syscall, file, file_table};
|
||||
use std::{io, mem};
|
||||
use std::path::Path;
|
||||
use std::sgxfs::SgxFile;
|
||||
use std::io;
|
||||
use std::io::{Read};
|
||||
use std::mem;
|
||||
|
||||
use sgx_types::*;
|
||||
|
||||
use xmas_elf::{ElfFile, header, program};
|
||||
use xmas_elf::sections;
|
||||
use xmas_elf::symbol_table::Entry;
|
||||
|
||||
use {elf_helper, vma, syscall};
|
||||
use vma::Vma;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::{SgxMutex, SgxMutexGuard};
|
||||
use std::sync::Arc;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::sgxfs::SgxFile;
|
||||
use std::thread;
|
||||
use std::cell::Cell;
|
||||
|
||||
use xmas_elf::{ElfFile, header, program, sections};
|
||||
use xmas_elf::symbol_table::Entry;
|
||||
|
||||
use vma::Vma;
|
||||
use file::{File, StdinFile, StdoutFile/*, StderrFile*/};
|
||||
use file_table::{FileTable};
|
||||
|
||||
lazy_static! {
|
||||
static ref PROCESS_TABLE: SgxMutex<HashMap<u32, ProcessRef>> = {
|
||||
SgxMutex::new(HashMap::new())
|
||||
@ -51,30 +45,56 @@ fn free_pid(pid: u32) {
|
||||
}
|
||||
|
||||
|
||||
pub fn do_spawn<P: AsRef<Path>>(new_pid: &mut u32, elf_path: &P) -> Result<(), &'static str> {
|
||||
let elf_buf = open_elf(elf_path).unwrap();
|
||||
let elf_file = ElfFile::new(&elf_buf).unwrap();
|
||||
header::sanity_check(&elf_file).unwrap();
|
||||
/*
|
||||
pub fn do_spawn<P: AsRef<Path>>(elf_path: &P) -> Result<u32, Error> {
|
||||
let elf_buf = open_elf(elf_path)
|
||||
.map_err(|e| (e.errno, "Failed to open the ELF file"))?;
|
||||
|
||||
let elf_file = {
|
||||
let elf_file = ElfFile::new(&elf_buf)
|
||||
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
|
||||
header::sanity_check(&elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
|
||||
|
||||
/*
|
||||
elf_helper::print_program_headers(&elf_file)?;
|
||||
elf_helper::print_sections(&elf_file)?;
|
||||
elf_helper::print_pltrel_section(&elf_file)?;
|
||||
*/
|
||||
let new_process = Process::new(&elf_file)?;
|
||||
*new_pid = new_process.pid;
|
||||
let new_process = Arc::new(SgxMutex::new(new_process));
|
||||
//println!("new_process: {:#x?}", &new_process);
|
||||
*/
|
||||
elf_file
|
||||
};
|
||||
|
||||
enqueue_new_process(new_process.clone());
|
||||
put_into_pid_table(*new_pid, new_process);
|
||||
let new_process = {
|
||||
let mut new_process = Process::new(&elf_file)
|
||||
.map_err(|e| (Errno::EUNDEF, "Failed to create the process"))?;
|
||||
|
||||
{
|
||||
let file_table = &mut new_process.file_table;
|
||||
|
||||
//let stdin = Arc::new(SgxMutex::new(Box::new(StdinFile::new())));
|
||||
let stdin : Arc<Box<File>> = Arc::new(Box::new(StdinFile::new()));
|
||||
let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new()));
|
||||
let stderr = stdout.clone();
|
||||
file_table.put(stdin);
|
||||
file_table.put(stdout);
|
||||
file_table.put(stderr);
|
||||
};
|
||||
|
||||
new_process
|
||||
};
|
||||
|
||||
let new_pid = new_process.pid;
|
||||
let new_process_ref = Arc::new(SgxMutex::new(new_process));
|
||||
enqueue_new_process(new_process_ref.clone());
|
||||
put_into_pid_table(new_pid, new_process_ref.clone());
|
||||
|
||||
// FIXME: if ocall_new_task failed, then new_process will not be dropped
|
||||
let mut ret = 0;
|
||||
let ocall_status = unsafe { ocall_run_new_task(&mut ret) };
|
||||
if ocall_status != sgx_status_t::SGX_SUCCESS || ret != 0 {
|
||||
return Err("ocall_run_new_task failed");
|
||||
return Err((Errno::EUNDEF, "Failed to start the process").into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(new_pid)
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
@ -127,12 +147,14 @@ pub fn do_exit(exit_code: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_wait4(child_pid: u32, exit_code: &mut i32) -> Result<(), &'static str> {
|
||||
let child_process = look_up_pid_table(child_pid).ok_or("Not found")?;
|
||||
pub fn do_wait4(child_pid: u32) -> Result<i32, Error> {
|
||||
let child_process = look_up_pid_table(child_pid)
|
||||
.ok_or_else(|| (Errno::ECHILD, "Cannot find child process with the given PID"))?;
|
||||
let mut exit_code = 0;
|
||||
loop {
|
||||
let guard = child_process.lock().unwrap();
|
||||
if guard.status == Status::ZOMBIE {
|
||||
*exit_code = guard.exit_code;
|
||||
exit_code = guard.exit_code;
|
||||
break;
|
||||
}
|
||||
drop(guard);
|
||||
@ -141,11 +163,12 @@ pub fn do_wait4(child_pid: u32, exit_code: &mut i32) -> Result<(), &'static str>
|
||||
let child_pid = child_process.lock().unwrap().pid;
|
||||
del_from_pid_table(child_pid);
|
||||
|
||||
Ok(())
|
||||
Ok(exit_code)
|
||||
}
|
||||
|
||||
pub fn run_task() -> Result<(), &'static str> {
|
||||
let new_process : ProcessRef = dequeue_new_process().ok_or("No new process to run")?;
|
||||
pub fn run_task() -> Result<(), Error> {
|
||||
let new_process : ProcessRef = dequeue_new_process()
|
||||
.ok_or_else(|| (Errno::EAGAIN, "No new processes to run"))?;
|
||||
set_current(&new_process);
|
||||
|
||||
let pid;
|
||||
@ -171,13 +194,14 @@ pub fn run_task() -> Result<(), &'static str> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn open_elf<P: AsRef<Path>>(path: &P) -> io::Result<Vec<u8>> {
|
||||
fn open_elf<P: AsRef<Path>>(path: &P) -> Result<Vec<u8>, Error> {
|
||||
let key : sgx_key_128bit_t = [0 as uint8_t; 16];
|
||||
let mut elf_file = SgxFile::open_ex(path, &key)?;
|
||||
let mut elf_file = SgxFile::open_ex(path, &key)
|
||||
.map_err(|e| (Errno::ENOENT, "Failed to open the SGX-protected file"))?;
|
||||
|
||||
let mut elf_buf = Vec::<u8>::new();
|
||||
elf_file.read_to_end(&mut elf_buf);
|
||||
drop(elf_file);
|
||||
|
||||
Ok(elf_buf)
|
||||
}
|
||||
|
||||
@ -194,11 +218,12 @@ pub struct Process {
|
||||
pub stack_vma: Vma,
|
||||
pub program_base_addr: usize,
|
||||
pub program_entry_addr: usize,
|
||||
pub file_table: FileTable,
|
||||
}
|
||||
pub type ProcessRef = Arc<SgxMutex<Process>>;
|
||||
|
||||
impl Process {
|
||||
pub fn new(elf_file: &ElfFile) -> Result<Process, &'static str> {
|
||||
pub fn new(elf_file: &ElfFile) -> Result<Process, Error> {
|
||||
let mut new_process : Process = Default::default();
|
||||
new_process.create_process_image(elf_file)?;
|
||||
new_process.link_syscalls(elf_file)?;
|
||||
@ -217,10 +242,12 @@ impl Process {
|
||||
}
|
||||
|
||||
fn create_process_image(self: &mut Process, elf_file: &ElfFile)
|
||||
-> Result<(), &'static str>
|
||||
-> Result<(), Error>
|
||||
{
|
||||
let code_ph = elf_helper::get_code_program_header(elf_file)?;
|
||||
let data_ph = elf_helper::get_data_program_header(elf_file)?;
|
||||
let code_ph = elf_helper::get_code_program_header(elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?;
|
||||
let data_ph = elf_helper::get_data_program_header(elf_file)
|
||||
.map_err(|e| (Errno::ENOEXEC, "Failed to get the program header of code"))?;
|
||||
|
||||
self.code_vma = Vma::from_program_header(&code_ph)?;
|
||||
self.data_vma = Vma::from_program_header(&data_ph)?;
|
||||
@ -231,14 +258,14 @@ impl Process {
|
||||
self.program_entry_addr = self.program_base_addr +
|
||||
elf_helper::get_start_address(elf_file)?;
|
||||
if !self.code_vma.contains(self.program_entry_addr) {
|
||||
return Err("Entry address is out of the code segment");
|
||||
return Err((Errno::EINVAL, "Entry address is out of the code segment").into());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn alloc_mem_for_vmas(self: &mut Process, elf_file: &ElfFile)
|
||||
-> Result<usize, &'static str>
|
||||
-> Result<usize, Error>
|
||||
{
|
||||
let mut vma_list = vec![&mut self.code_vma, &mut self.data_vma, &mut self.stack_vma];
|
||||
let base_addr = vma::malloc_batch(&mut vma_list, elf_file.input)?;
|
||||
@ -247,7 +274,7 @@ impl Process {
|
||||
}
|
||||
|
||||
fn link_syscalls(self: &mut Process, elf_file: &ElfFile)
|
||||
-> Result<(), &'static str>
|
||||
-> Result<(), Error>
|
||||
{
|
||||
let syscall_addr = rusgx_syscall as *const () as usize;
|
||||
|
||||
@ -256,7 +283,9 @@ impl Process {
|
||||
for rela_entry in rela_entries {
|
||||
let dynsym_idx = rela_entry.get_symbol_table_index() as usize;
|
||||
let dynsym_entry = &dynsym_entries[dynsym_idx];
|
||||
let dynsym_str = dynsym_entry.get_name(&elf_file)?;
|
||||
let dynsym_str = dynsym_entry.get_name(elf_file)
|
||||
.map_err(|e| Error::new(Errno::ENOEXEC,
|
||||
"Failed to get the name of dynamic symbol"))?;
|
||||
|
||||
if dynsym_str == "rusgx_syscall" {
|
||||
let rela_addr = self.program_base_addr + rela_entry.get_offset() as usize;
|
||||
@ -269,7 +298,7 @@ impl Process {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mprotect(self: &mut Process) -> Result<(), &'static str> {
|
||||
fn mprotect(self: &mut Process) -> Result<(), Error> {
|
||||
let vma_list = vec![&self.code_vma, &self.data_vma, &self.stack_vma];
|
||||
vma::mprotect_batch(&vma_list)
|
||||
}
|
||||
|
@ -8,6 +8,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int rusgx_open(const char* path, int flags, int mode);
|
||||
extern int rusgx_close(int fd);
|
||||
extern ssize_t rusgx_read(int fd, void* buf, size_t size);
|
||||
extern ssize_t rusgx_write(int fd, const void* buf, size_t size);
|
||||
extern int rusgx_spawn(int* child_pid, const char* path,
|
||||
const char** argv,
|
||||
|
@ -1,36 +1,76 @@
|
||||
use sgx_types::*;
|
||||
|
||||
use process;
|
||||
use prelude::*;
|
||||
use {std, file, file_table, fs, process};
|
||||
use std::ffi::CStr; // a borrowed C string
|
||||
use std::collections::HashMap;
|
||||
// Use the internal syscall wrappers from sgx_tstd
|
||||
//use std::libc_fs as fs;
|
||||
//use std::libc_io as io;
|
||||
|
||||
// TODO: check all pointer passed from user belongs to user space
|
||||
|
||||
/*
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sys_open(path: * const c_char, flags: c_int, mode: c_int) -> c_int {
|
||||
fs::open64(path, flags, mode)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sys_close(fd: c_int) -> c_int {
|
||||
io::close(fd)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sys_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
|
||||
io::read(fd, buf, size)
|
||||
}
|
||||
*/
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_open(path_buf: * const c_char, flags: c_int, mode: c_int) -> c_int {
|
||||
let path = unsafe {
|
||||
CStr::from_ptr(path_buf as * const i8).to_string_lossy().into_owned()
|
||||
};
|
||||
match fs::do_open(&path, flags as u32, mode as u32) {
|
||||
Ok(fd) => {
|
||||
fd as c_int
|
||||
},
|
||||
Err(e) => {
|
||||
e.errno.as_retval()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_close(fd: c_int) -> c_int {
|
||||
match fs::do_close(fd as file_table::FileDesc) {
|
||||
Ok(()) => {
|
||||
0
|
||||
},
|
||||
Err(e) => {
|
||||
e.errno.as_retval()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_read(fd: c_int, buf: * mut c_void, size: size_t) -> ssize_t {
|
||||
let buf = unsafe {
|
||||
std::slice::from_raw_parts_mut(buf as *mut u8, size as usize)
|
||||
};
|
||||
match fs::do_read(fd as file_table::FileDesc, buf) {
|
||||
Ok(read_len) => {
|
||||
read_len as ssize_t
|
||||
},
|
||||
Err(e) => {
|
||||
e.errno.as_retval() as ssize_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_write(fd: c_int, buf: * const c_void, size: size_t) -> ssize_t {
|
||||
let str_from_c = unsafe {
|
||||
/* let str_from_c = unsafe {
|
||||
CStr::from_ptr(buf as * const i8).to_string_lossy().into_owned()
|
||||
};
|
||||
println!("rusgx_write: {}", str_from_c);
|
||||
size as ssize_t
|
||||
*/
|
||||
let buf = unsafe {
|
||||
std::slice::from_raw_parts(buf as *const u8, size as usize)
|
||||
};
|
||||
match fs::do_write(fd as file_table::FileDesc, buf) {
|
||||
Ok(write_len) => {
|
||||
write_len as ssize_t
|
||||
},
|
||||
Err(e) => {
|
||||
e.errno.as_retval() as ssize_t
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -46,31 +86,35 @@ pub extern "C" fn rusgx_exit(status: i32)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_spawn(_child_pid: *mut c_int, path: *const c_char,
|
||||
pub extern "C" fn rusgx_spawn(child_pid: *mut c_int, path: *const c_char,
|
||||
argv: *const *const c_char, envp: *const *const c_char) -> c_int
|
||||
{
|
||||
let mut ret = 0;
|
||||
let mut child_pid = 0;
|
||||
let path_str = unsafe {
|
||||
CStr::from_ptr(path as * const i8).to_string_lossy().into_owned()
|
||||
};
|
||||
if process::do_spawn(&mut child_pid, &path_str) != Ok(()) {
|
||||
ret = -1;
|
||||
match process::do_spawn(&path_str) {
|
||||
Ok(new_pid) => unsafe {
|
||||
*child_pid = new_pid as c_int;
|
||||
0
|
||||
},
|
||||
Err(e) => {
|
||||
e.errno.as_retval()
|
||||
}
|
||||
unsafe {
|
||||
*_child_pid = child_pid as c_int;
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rusgx_wait4(child_pid: c_int, _exit_code: *mut c_int,
|
||||
options: c_int/*, rusage: *mut Rusage*/) -> c_int
|
||||
{
|
||||
let mut exit_code = 0;
|
||||
process::do_wait4(child_pid as u32, &mut exit_code);
|
||||
unsafe {
|
||||
match process::do_wait4(child_pid as u32) {
|
||||
Ok(exit_code) => unsafe {
|
||||
*_exit_code = exit_code;
|
||||
}
|
||||
0
|
||||
}
|
||||
Err(e) => {
|
||||
e.errno.as_retval()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,18 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
|
||||
do_exit_task();
|
||||
break;
|
||||
}
|
||||
case SYS_open: {
|
||||
DECL_SYSCALL_ARG(const void*, path, arg0);
|
||||
DECL_SYSCALL_ARG(int, flags, arg1);
|
||||
DECL_SYSCALL_ARG(int, mode, arg2);
|
||||
ret = rusgx_open(path, flags, mode);
|
||||
break;
|
||||
}
|
||||
case SYS_close: {
|
||||
DECL_SYSCALL_ARG(int, fd, arg0);
|
||||
ret = rusgx_close(fd);
|
||||
break;
|
||||
}
|
||||
case SYS_write: {
|
||||
DECL_SYSCALL_ARG(int, fd, arg0);
|
||||
DECL_SYSCALL_ARG(const void*, buf, arg1);
|
||||
@ -21,6 +33,13 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
|
||||
ret = rusgx_write(fd, buf, buf_size);
|
||||
break;
|
||||
}
|
||||
case SYS_read: {
|
||||
DECL_SYSCALL_ARG(int, fd, arg0);
|
||||
DECL_SYSCALL_ARG(void*, buf, arg1);
|
||||
DECL_SYSCALL_ARG(size_t, buf_size, arg2);
|
||||
ret = rusgx_read(fd, buf, buf_size);
|
||||
break;
|
||||
}
|
||||
case SYS_spawn: {
|
||||
DECL_SYSCALL_ARG(int*, child_pid, arg0);
|
||||
DECL_SYSCALL_ARG(const char*, path, arg1);
|
||||
|
@ -1,11 +1,11 @@
|
||||
/// Virtuam Memory Area (VMA)
|
||||
use prelude::*;
|
||||
use {std};
|
||||
|
||||
use xmas_elf::program;
|
||||
use xmas_elf::program::{ProgramHeader};
|
||||
use std;
|
||||
use std::sync::Arc;
|
||||
|
||||
use mm::MemObj;
|
||||
use sgx_types::*;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[repr(C)]
|
||||
@ -31,11 +31,11 @@ const VMA_MIN_MEM_ALIGN: usize = (4 * 1024);
|
||||
|
||||
impl Vma {
|
||||
pub fn from_program_header<'a>(ph: &ProgramHeader<'a>)
|
||||
-> Result<Vma, &'static str>
|
||||
-> Result<Vma, Error>
|
||||
{
|
||||
let ph64 = match ph {
|
||||
ProgramHeader::Ph32(ph) => {
|
||||
return Err("Not support 32-bit ELF")
|
||||
return Err((Errno::ENOEXEC, "Not support 32-bit ELF").into())
|
||||
}
|
||||
ProgramHeader::Ph64(ph64) => {
|
||||
ph64
|
||||
@ -43,10 +43,12 @@ impl Vma {
|
||||
};
|
||||
if ph64.align > 1 && ((ph64.offset % ph64.align) !=
|
||||
(ph64.virtual_addr % ph64.align)) {
|
||||
return Err("Memory address and file offset is not equal, per modulo");
|
||||
return Err((Errno::EINVAL,
|
||||
"Memory address and file offset is not equal, per modulo").into());
|
||||
}
|
||||
if ph64.mem_size < ph64.file_size {
|
||||
return Err("Memory size must be greater than file size");
|
||||
return Err((Errno::EINVAL,
|
||||
"Memory size must be greater than file size").into());
|
||||
}
|
||||
|
||||
let mut new_vma = Vma::new(ph64.mem_size as usize,
|
||||
@ -62,13 +64,15 @@ impl Vma {
|
||||
}
|
||||
|
||||
pub fn new(mem_size: usize, mem_align: usize, mem_flags: Perms)
|
||||
-> Result<Self, &'static str>
|
||||
-> Result<Self, Error>
|
||||
{
|
||||
if mem_align == 0 || mem_align % VMA_MIN_MEM_ALIGN != 0 {
|
||||
return Err("Memory alignment is not a multiple of 4KB");
|
||||
return Err((Errno::EINVAL,
|
||||
"Memory alignment is not a multiple of 4KB").into());
|
||||
}
|
||||
if mem_size == 0 {
|
||||
return Err("Memory size must be greater than zero");
|
||||
return Err((Errno::EINVAL,
|
||||
"Memory size must be greater than zero").into());
|
||||
}
|
||||
|
||||
Ok(Vma {
|
||||
@ -85,7 +89,7 @@ impl Vma {
|
||||
}
|
||||
|
||||
pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
|
||||
-> Result<usize, &'static str>
|
||||
-> Result<usize, Error>
|
||||
{
|
||||
let mut max_align = VMA_MIN_MEM_ALIGN;
|
||||
let mut total_size = 0;
|
||||
@ -96,11 +100,13 @@ pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
|
||||
if vma.file_is_mapped {
|
||||
if vma.mem_addr < mem_begin ||
|
||||
vma.mem_addr + vma.mem_size > mem_end {
|
||||
return Err("Impossible memory layout for the VMA");
|
||||
return Err((Errno::EINVAL,
|
||||
"Impossible memory layout for the VMA").into());
|
||||
}
|
||||
if vma.file_offset > mapped_data.len() ||
|
||||
vma.file_offset + vma.file_size > mapped_data.len() {
|
||||
return Err("Impossible to load data from file");
|
||||
return Err((Errno::EINVAL,
|
||||
"Impossible to load data from file").into());
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +140,7 @@ pub fn malloc_batch(vma_list: &mut [&mut Vma], mapped_data: &[u8])
|
||||
}
|
||||
|
||||
pub fn mprotect_batch(vma_list: &[&Vma])
|
||||
-> Result<(), &'static str>
|
||||
-> Result<(), Error>
|
||||
{
|
||||
for vma in vma_list.into_iter() {
|
||||
// If don't need to change memory permissions
|
||||
@ -153,7 +159,7 @@ pub fn mprotect_batch(vma_list: &[&Vma])
|
||||
trts_mprotect(start, size, (PERM_R | PERM_W | PERM_X) as uint64_t)
|
||||
};
|
||||
if (status != sgx_status_t::SGX_SUCCESS) {
|
||||
return Err("trts_mprotect failed");
|
||||
return Err((Errno::EACCES, "trts_mprotect failed").into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -1,7 +1,7 @@
|
||||
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||
PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
||||
|
||||
TEST_SUITES := hello_world_raw spawn_and_wait4_raw getpid
|
||||
TEST_SUITES := hello_world_raw spawn_and_wait4_raw getpid file_io
|
||||
BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
|
||||
RUN_TEST_SUITES := $(TEST_SUITES:%=run-%)
|
||||
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)
|
||||
|
4
test/file_io/Makefile
Normal file
4
test/file_io/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS := -fno-builtin
|
||||
EXTRA_LINK_FLAGS := -nostdlib
|
66
test/file_io/main.c
Normal file
66
test/file_io/main.c
Normal file
@ -0,0 +1,66 @@
|
||||
#include "rusgx_stub.h"
|
||||
|
||||
static char success_str_buf[] = "Success!\n";
|
||||
static unsigned long success_str_size = sizeof(success_str_buf);
|
||||
|
||||
static void print_ok(void) {
|
||||
__rusgx_write(1, success_str_buf, success_str_size);
|
||||
}
|
||||
|
||||
|
||||
static int test_write(const char* file_path) {
|
||||
int write_fd = __rusgx_open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (write_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char write_buf[] = "Hello World!\n";
|
||||
size_t write_len = sizeof(write_buf);
|
||||
if (__rusgx_write(write_fd, write_buf, write_len) != write_len) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (__rusgx_close(write_fd) < 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_read(const char* file_path) {
|
||||
int read_fd = __rusgx_open(file_path, O_RDONLY, 0);
|
||||
if (read_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char read_buf[256] = { 0 };
|
||||
size_t read_len;
|
||||
if ((read_len = __rusgx_read(read_fd, read_buf, 256)) < 0 ) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
__rusgx_write(1, read_buf, read_len);
|
||||
|
||||
if (__rusgx_close(read_fd) < 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _start(void) {
|
||||
int ret = 0;
|
||||
const char* file_path = "tmp.txt.protected";
|
||||
|
||||
if ((ret = test_write(file_path)) < 0) {
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
if ((ret = test_read(file_path)) < 0) {
|
||||
goto on_exit;
|
||||
}
|
||||
|
||||
print_ok();
|
||||
on_exit:
|
||||
__rusgx_exit(ret);
|
||||
}
|
@ -20,12 +20,32 @@
|
||||
* host syscalls provided by the default implementation of this library.
|
||||
*/
|
||||
|
||||
#define SYS_read 0
|
||||
#define SYS_write 1
|
||||
#define SYS_open 2
|
||||
#define SYS_close 3
|
||||
#define SYS_getpid 39
|
||||
#define SYS_exit 60
|
||||
#define SYS_wait4 61
|
||||
#define SYS_spawn 360
|
||||
|
||||
#define O_RDONLY 0x00000000U
|
||||
#define O_WRONLY 0x00000001U
|
||||
#define O_RDWR 0x00000002U
|
||||
#define O_CREAT 0x00000040U
|
||||
#define O_EXCL 0x00000080U
|
||||
#define O_NOCTTY 0x00000100U
|
||||
#define O_TRUNC 0x00000200U
|
||||
#define O_APPEND 0x00000400U
|
||||
#define O_NONBLOCK 0x00000800U
|
||||
#define O_NDELAY 0x00000800U
|
||||
#define O_DSYNC 0x00001000U
|
||||
#define O_DIRECTORY 0x00010000U
|
||||
#define O_NOFOLLOW 0x00020000U
|
||||
#define O_CLOEXEC 0x00080000U
|
||||
#define O_SYNC 0x00101000U
|
||||
|
||||
|
||||
long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg4);
|
||||
|
||||
#define RUSGX_SYSCALL0(num) \
|
||||
@ -41,10 +61,24 @@ long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg
|
||||
#define RUSGX_SYSCALL5(num, arg0, arg1, arg2, arg3, arg4) \
|
||||
rusgx_syscall((num), (long)(arg0), (long)(arg1), (long)(arg2), (long)(arg3), (long)(arg4))
|
||||
|
||||
|
||||
static inline ssize_t __rusgx_read(int fd, void* buf, unsigned long size) {
|
||||
return (ssize_t) RUSGX_SYSCALL3(SYS_read, fd, buf, size);
|
||||
}
|
||||
|
||||
static inline ssize_t __rusgx_write(int fd, const void* buf, unsigned long size) {
|
||||
return (ssize_t) RUSGX_SYSCALL3(SYS_write, fd, buf, size);
|
||||
}
|
||||
|
||||
static inline int __rusgx_open(const void* buf, int flags, int mode) {
|
||||
return (int) RUSGX_SYSCALL3(SYS_open, buf, flags, mode);
|
||||
}
|
||||
|
||||
static inline int __rusgx_close(int fd) {
|
||||
return (int) RUSGX_SYSCALL1(SYS_close, fd);
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned int __rusgx_getpid(void) {
|
||||
return (unsigned int) RUSGX_SYSCALL0(SYS_getpid);
|
||||
}
|
||||
|
@ -1,5 +1,16 @@
|
||||
#include "rusgx_stub.h"
|
||||
|
||||
static long __read(int fd, void* buf, unsigned long size) {
|
||||
long ret;
|
||||
__asm__ __volatile__ (
|
||||
"syscall"
|
||||
: "=a" (ret)
|
||||
: "0" (SYS_read), "D" (fd), "S" (buf), "d" (size)
|
||||
: "cc", "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long __write(int fd, const void* buf, unsigned long size) {
|
||||
long ret;
|
||||
__asm__ __volatile__ (
|
||||
@ -11,6 +22,27 @@ static long __write(int fd, const void* buf, unsigned long size) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long __open(const char* path, int flags, int mode) {
|
||||
long ret;
|
||||
__asm__ __volatile__ (
|
||||
"syscall"
|
||||
: "=a" (ret)
|
||||
: "0" (SYS_open), "D" (path), "S" (flags), "d" (mode)
|
||||
: "cc", "rcx", "r11", "memory"
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long __close(int fd) {
|
||||
long ret;
|
||||
__asm__ __volatile__ (
|
||||
"syscall"
|
||||
: "=a" (ret)
|
||||
: "a" (SYS_close), "D" (fd)
|
||||
: "cc", "rcx", "r11", "memory" );
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit(int status) {
|
||||
__asm__ __volatile__ (
|
||||
"syscall"
|
||||
@ -26,9 +58,18 @@ long rusgx_syscall(int num, long arg0, long arg1, long arg2, long arg3, long arg
|
||||
case SYS_exit:
|
||||
__exit((int)arg0);
|
||||
break;
|
||||
case SYS_read:
|
||||
ret = __read((int)arg0, (void*)arg1, (unsigned long)arg2);
|
||||
break;
|
||||
case SYS_write:
|
||||
ret = __write((int)arg0, (const void*)arg1, (unsigned long)arg2);
|
||||
break;
|
||||
case SYS_open:
|
||||
ret = __open((const char*)arg0, (int)arg1, (int)arg2);
|
||||
break;
|
||||
case SYS_close:
|
||||
ret = __close((int)arg0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user