Skip to content

Commit

Permalink
Use goblin as elf parser and only load segments on demand
Browse files Browse the repository at this point in the history
Libos now Only read in headers and needed segments. Also reduce a memory
copy.
  • Loading branch information
jessehui committed Jan 28, 2021
1 parent c2aefca commit 925669e
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 127 deletions.
8 changes: 4 additions & 4 deletions .gitmodules
Expand Up @@ -2,10 +2,6 @@
path = deps/rust-sgx-sdk
url = https://github.com/occlum/incubator-teaclave-sgx-sdk.git
branch = sgx_2.11_for_occlum
[submodule "deps/xmas-elf"]
path = deps/xmas-elf
url = https://github.com/occlum/xmas-elf
branch = master
[submodule "deps/sefs"]
path = deps/sefs
url = https://github.com/occlum/sefs.git
Expand All @@ -26,3 +22,7 @@
[submodule "deps/ringbuf"]
path = deps/ringbuf
url = https://github.com/agerasev/ringbuf.git
[submodule "deps/goblin"]
path = deps/goblin
url = https://github.com/jessehui/goblin.git
branch = lazy_parse
1 change: 1 addition & 0 deletions deps/goblin
Submodule goblin added at 6f9297
2 changes: 1 addition & 1 deletion deps/sefs
Submodule sefs updated 1 files
+10 −0 rcore-fs/src/vfs.rs
1 change: 0 additions & 1 deletion deps/xmas-elf
Submodule xmas-elf deleted from 792105
51 changes: 37 additions & 14 deletions src/libos/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/libos/Cargo.toml
Expand Up @@ -25,6 +25,7 @@ rcore-fs-devfs = { path = "../../deps/sefs/rcore-fs-devfs" }
serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] }
serde_json = { path = "../../deps/serde-json-sgx" }
memoffset = "0.6.1"
scroll = { version = "0.10.2", default-features = false }

[patch.'https://github.com/apache/teaclave-sgx-sdk.git']
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd" }
Expand All @@ -39,10 +40,10 @@ dcap = [] # DCAP support. The compilation relies on DCAP package.
cov = ["sgx_cov"] # Enable coverage colletcion.

[target.'cfg(not(target_env = "sgx"))'.dependencies]
xmas-elf = { path = "../../deps/xmas-elf" }
sgx_types = { path = "../../deps/rust-sgx-sdk/sgx_types" }
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace"] }
sgx_trts = { path = "../../deps/rust-sgx-sdk/sgx_trts" }
sgx_tse = { path = "../../deps/rust-sgx-sdk/sgx_tse" }
sgx_tcrypto = { path = "../../deps/rust-sgx-sdk/sgx_tcrypto" }
sgx_cov = { path = "../../deps/rust-sgx-sdk/sgx_cov", optional = true }
goblin = { path = "../../deps/goblin", default-features = false, features = ["elf64", "elf32", "endian_fd"] }
3 changes: 2 additions & 1 deletion src/libos/src/lib.rs
Expand Up @@ -29,10 +29,11 @@ extern crate sgx_types;
#[cfg(not(target_env = "sgx"))]
#[macro_use]
extern crate sgx_tstd as std;
extern crate goblin;
extern crate scroll;
extern crate sgx_tcrypto;
extern crate sgx_trts;
extern crate sgx_tse;
extern crate xmas_elf;
#[macro_use]
extern crate lazy_static;
#[macro_use]
Expand Down
54 changes: 38 additions & 16 deletions src/libos/src/process/do_spawn/exec_loader.rs
@@ -1,21 +1,27 @@
use super::super::elf_file::*;
use super::ThreadRef;
use crate::fs::{FileMode, INodeExt};
use crate::prelude::*;
use rcore_fs::vfs::INode;
use std::ffi::CString;

/// Load an ELF file itself or a script's interpreter into a vector.
/// Load an ELF file header or a script's interpreter header into a vector.
///
/// If the file is an executable binary, then just load this file.
/// If the file is an executable binary, then just load this file's header.
/// If the file is an script text, then parse the shebang and load
/// the interpreter.
pub fn load_exec_file_to_vec(
/// the interpreter header.
pub fn load_exec_file_hdr_to_vec(
file_path: &str,
current_ref: &ThreadRef,
) -> Result<(Option<String>, Vec<u8>)> {
let file_buf = load_file_to_vec(&file_path, current_ref)?;
let is_script = is_script_file(&file_buf);
if is_script {
) -> Result<(Option<String>, Arc<dyn INode>, Vec<u8>, ElfHeader)> {
let (inode, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?;
if elf_hdr.is_some() {
Ok((None, inode, file_buf, elf_hdr.unwrap()))
} else {
// loaded file is not Elf format, try script file
if !is_script_file(&file_buf) {
return_errno!(ENOEXEC, "unknown executable file format");
}
// load interpreter
let interpreter_path = parse_script_interpreter(&file_buf)?;
if interpreter_path.starts_with("/host/") {
Expand All @@ -24,10 +30,14 @@ pub fn load_exec_file_to_vec(
"libos doesn't support executing binaries from \"/host\" directory"
);
}
let elf_buf = load_file_to_vec(&interpreter_path, current_ref)?;
Ok((Some(interpreter_path), elf_buf))
} else {
Ok((None, file_buf))
let (interp_inode, interp_buf, interp_hdr) =
load_file_hdr_to_vec(&interpreter_path, current_ref)?;
let interp_hdr = if interp_hdr.is_none() {
return_errno!(ENOEXEC, "scrip interpreter is not ELF format");
} else {
interp_hdr.unwrap()
};
Ok((Some(interpreter_path), interp_inode, interp_buf, interp_hdr))
}
}

Expand Down Expand Up @@ -59,7 +69,10 @@ fn parse_script_interpreter(file_buf: &Vec<u8>) -> Result<String> {
Ok(interpreter.to_owned())
}

pub fn load_file_to_vec(file_path: &str, current_ref: &ThreadRef) -> Result<Vec<u8>> {
pub fn load_file_hdr_to_vec(
file_path: &str,
current_ref: &ThreadRef,
) -> Result<(Arc<dyn INode>, Vec<u8>, Option<ElfHeader>)> {
let inode = current_ref
.fs()
.lock()
Expand All @@ -79,7 +92,16 @@ pub fn load_file_to_vec(file_path: &str, current_ref: &ThreadRef) -> Result<Vec<
file_mode
);
}
inode
.read_as_vec()
.map_err(|e| errno!(e.errno(), "failed to read the file"))

// Try to read the file as ELF64
let mut file_buf = inode
.read_elf64_as_vec()
.map_err(|e| errno!(e.errno(), "failed to read the file"))?;

if let Ok(elf_header) = ElfFile::parse_elf_hdr(&inode, &mut file_buf) {
Ok((inode, file_buf, Some(elf_header)))
} else {
// this file is not ELF format
Ok((inode, file_buf, None))
}
}
55 changes: 25 additions & 30 deletions src/libos/src/process/do_spawn/mod.rs
Expand Up @@ -2,8 +2,8 @@ use std::ffi::{CStr, CString};
use std::path::Path;

use self::aux_vec::{AuxKey, AuxVec};
use self::exec_loader::{load_exec_file_to_vec, load_file_to_vec};
use super::elf_file::{ElfFile, ElfHeader, ProgramHeader, ProgramHeaderExt, SegmentData};
use self::exec_loader::{load_exec_file_hdr_to_vec, load_file_hdr_to_vec};
use super::elf_file::{ElfFile, ElfHeader, ProgramHeaderExt};
use super::process::ProcessBuilder;
use super::task::Task;
use super::thread::ThreadName;
Expand Down Expand Up @@ -102,7 +102,8 @@ fn new_process(
current_ref: &ThreadRef,
) -> Result<ProcessRef> {
let mut argv = argv.clone().to_vec();
let (is_script, elf_buf) = load_exec_file_to_vec(file_path, current_ref)?;
let (is_script, elf_inode, mut elf_buf, elf_header) =
load_exec_file_hdr_to_vec(file_path, current_ref)?;

// elf_path might be different from file_path because file_path could lead to a script text file.
// And intepreter will be the loaded ELF.
Expand All @@ -117,30 +118,28 @@ fn new_process(
file_path.to_string()
};

let exec_elf_file =
ElfFile::new(&elf_buf).cause_err(|e| errno!(e.errno(), "invalid executable"))?;
// Get the ldso_path of the executable
let exec_interp_segment = exec_elf_file
.program_headers()
.find(|segment| segment.is_interpreter())
let exec_elf_hdr = ElfFile::new(&elf_inode, &mut elf_buf, elf_header)
.cause_err(|e| errno!(e.errno(), "invalid executable"))?;
let ldso_path = exec_elf_hdr
.elf_interpreter()
.ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?;
let ldso_path = match exec_interp_segment.get_content(&exec_elf_file) {
SegmentData::Undefined(bytes) => std::ffi::CStr::from_bytes_with_nul(bytes)
.unwrap()
.to_str()
.unwrap(),
_ => return_errno!(EINVAL, "cannot get ldso_path from executable"),
trace!("ldso_path = {:?}", ldso_path);
let (ldso_inode, mut ldso_elf_hdr_buf, ldso_elf_header) =
load_file_hdr_to_vec(ldso_path, current_ref)
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
let ldso_elf_header = if ldso_elf_header.is_none() {
return_errno!(ENOEXEC, "ldso header is not ELF format");
} else {
ldso_elf_header.unwrap()
};
let ldso_elf_buf = load_file_to_vec(ldso_path, current_ref)
.cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?;
let ldso_elf_file =
ElfFile::new(&ldso_elf_buf).cause_err(|e| errno!(e.errno(), "invalid ld.so"))?;
let ldso_elf_hdr = ElfFile::new(&ldso_inode, &mut ldso_elf_hdr_buf, ldso_elf_header)
.cause_err(|e| errno!(e.errno(), "invalid ld.so"))?;

let new_process_ref = {
let process_ref = current_ref.process().clone();

let vm = init_vm::do_init(&exec_elf_file, &ldso_elf_file)?;
let mut auxvec = init_auxvec(&vm, &exec_elf_file)?;
let vm = init_vm::do_init(&exec_elf_hdr, &ldso_elf_hdr)?;
let mut auxvec = init_auxvec(&vm, &exec_elf_hdr)?;

// Notify debugger to load the symbols from elf file
let ldso_elf_base = vm.get_elf_ranges()[1].start() as u64;
Expand All @@ -163,8 +162,7 @@ fn new_process(
let task = {
let ldso_entry = {
let ldso_range = vm.get_elf_ranges()[1];
let ldso_entry =
ldso_range.start() + ldso_elf_file.elf_header().entry_point() as usize;
let ldso_entry = ldso_range.start() + ldso_elf_hdr.elf_header().e_entry as usize;
if !ldso_range.contains(ldso_entry) {
return_errno!(EINVAL, "Invalid program entry");
}
Expand Down Expand Up @@ -309,13 +307,10 @@ fn init_auxvec(process_vm: &ProcessVM, exec_elf_file: &ElfFile) -> Result<AuxVec

let exec_elf_base = process_vm.get_elf_ranges()[0].start() as u64;
let exec_elf_header = exec_elf_file.elf_header();
auxvec.set(AuxKey::AT_PHENT, exec_elf_header.ph_entry_size() as u64)?;
auxvec.set(AuxKey::AT_PHNUM, exec_elf_header.ph_count() as u64)?;
auxvec.set(AuxKey::AT_PHDR, exec_elf_base + exec_elf_header.ph_offset())?;
auxvec.set(
AuxKey::AT_ENTRY,
exec_elf_base + exec_elf_header.entry_point(),
)?;
auxvec.set(AuxKey::AT_PHENT, exec_elf_header.e_phentsize as u64)?;
auxvec.set(AuxKey::AT_PHNUM, exec_elf_header.e_phnum as u64)?;
auxvec.set(AuxKey::AT_PHDR, exec_elf_base + exec_elf_header.e_phoff)?;
auxvec.set(AuxKey::AT_ENTRY, exec_elf_base + exec_elf_header.e_entry)?;

let ldso_elf_base = process_vm.get_elf_ranges()[1].start() as u64;
auxvec.set(AuxKey::AT_BASE, ldso_elf_base)?;
Expand Down

0 comments on commit 925669e

Please sign in to comment.