Check program paths against entry points in Occlum.json

This commit is contained in:
Zhengde Zhai 2019-11-01 05:42:38 +00:00 committed by Tate, Hongliang Tian
parent 4cb63a4d99
commit 1a56fc4b72
6 changed files with 74 additions and 13 deletions

@ -10,6 +10,9 @@
"env": [ "env": [
"OCCLUM=yes" "OCCLUM=yes"
], ],
"entry_points": [
"/bin"
],
"mount": [ "mount": [
{ {
"target": "/", "target": "/",

@ -80,6 +80,7 @@ pub struct Config {
pub vm: ConfigVM, pub vm: ConfigVM,
pub process: ConfigProcess, pub process: ConfigProcess,
pub env: Vec<CString>, pub env: Vec<CString>,
pub entry_points: Vec<PathBuf>,
pub mount: Vec<ConfigMount>, pub mount: Vec<ConfigMount>,
} }
@ -128,6 +129,17 @@ impl Config {
} }
env env
}; };
let entry_points = {
let mut entry_points = Vec::new();
for ep in &input.entry_points {
let ep_path = Path::new(ep).to_path_buf();
if !ep_path.is_absolute() {
return_errno!(EINVAL, "entry point must be an absolute path")
}
entry_points.push(ep_path);
}
entry_points
};
let mount = { let mount = {
let mut mount = Vec::new(); let mut mount = Vec::new();
for input_mount in &input.mount { for input_mount in &input.mount {
@ -139,6 +151,7 @@ impl Config {
vm, vm,
process, process,
env, env,
entry_points,
mount, mount,
}) })
} }
@ -246,6 +259,8 @@ struct InputConfig {
#[serde(default)] #[serde(default)]
pub env: Vec<String>, pub env: Vec<String>,
#[serde(default)] #[serde(default)]
pub entry_points: Vec<String>,
#[serde(default)]
pub mount: Vec<InputConfigMount>, pub mount: Vec<InputConfigMount>,
} }
@ -269,7 +284,6 @@ impl Default for InputConfigVM {
} }
} }
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct InputConfigProcess { struct InputConfigProcess {

@ -2,7 +2,7 @@ use super::*;
use exception::*; use exception::*;
use process::pid_t; use process::pid_t;
use std::ffi::{CStr, CString, OsString}; use std::ffi::{CStr, CString, OsString};
use std::path::Path; use std::path::{Path, PathBuf};
use util::mem_util::from_untrusted::*; use util::mem_util::from_untrusted::*;
const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum.signed.so"; const ENCLAVE_PATH: &'static str = ".occlum/build/lib/libocclum.signed.so";
@ -60,15 +60,18 @@ pub extern "C" fn dummy_ecall() -> i32 {
const EXIT_STATUS_INTERNAL_ERROR: i32 = 127; const EXIT_STATUS_INTERNAL_ERROR: i32 = 127;
fn parse_arguments( fn parse_arguments(
path_buf: *const c_char, path_ptr: *const c_char,
argv: *const *const c_char, argv: *const *const c_char,
) -> Result<(String, Vec<CString>)> { ) -> Result<(PathBuf, Vec<CString>)> {
let path_string = { let path_buf = {
let path_cstring = clone_cstring_safely(path_buf)?; let path_cstring = clone_cstring_safely(path_ptr)?;
path_cstring.to_string_lossy().into_owned() let path_string = path_cstring
.into_string()
.map_err(|e| errno!(EINVAL, "path contains valid utf-8 data"))?;
Path::new(&path_string).to_path_buf()
}; };
let program_cstring = { let program_cstring = {
let program_osstr = Path::new(&path_string) let program_osstr = path_buf
.file_name() .file_name()
.ok_or_else(|| errno!(EINVAL, "invalid path"))?; .ok_or_else(|| errno!(EINVAL, "invalid path"))?;
let program_str = program_osstr let program_str = program_osstr
@ -79,18 +82,20 @@ fn parse_arguments(
let mut args = clone_cstrings_safely(argv)?; let mut args = clone_cstrings_safely(argv)?;
args.insert(0, program_cstring); args.insert(0, program_cstring);
Ok((path_string, args)) Ok((path_buf, args))
} }
// TODO: make sure do_boot can only be called once // TODO: make sure do_boot can only be called once
fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<()> { fn do_boot(program_path: &PathBuf, argv: &Vec<CString>) -> Result<()> {
// info!("boot: path: {:?}, argv: {:?}", path_str, argv); // info!("boot: path: {:?}, argv: {:?}", path_str, argv);
util::mpx_util::mpx_enable()?; util::mpx_util::mpx_enable()?;
validate_program_path(program_path)?;
let envp = &config::LIBOS_CONFIG.env; let envp = &config::LIBOS_CONFIG.env;
let file_actions = Vec::new(); let file_actions = Vec::new();
let parent = &process::IDLE_PROCESS; let parent = &process::IDLE_PROCESS;
process::do_spawn(&path_str, argv, envp, &file_actions, parent)?; process::do_spawn(&program_path, argv, envp, &file_actions, parent)?;
Ok(()) Ok(())
} }
@ -106,3 +111,32 @@ fn do_run(host_tid: pid_t) -> Result<i32> {
Ok(exit_status) Ok(exit_status)
} }
fn validate_program_path(target_path: &PathBuf) -> Result<()> {
if !target_path.is_absolute() {
return_errno!(EINVAL, "program path must be absolute");
}
// Forbid paths like /bin/../root, which may circument our prefix-based path matching
let has_parent_component = {
target_path
.components()
.any(|component| component == std::path::Component::ParentDir)
};
if has_parent_component {
return_errno!(
EINVAL,
"program path cannot contain any parent component (i.e., \"..\")"
);
}
// Check whether the prefix of the program path matches one of the entry points
let is_valid_entry_point = &config::LIBOS_CONFIG
.entry_points
.iter()
.any(|valid_path_prefix| target_path.starts_with(valid_path_prefix));
if !is_valid_entry_point {
return_errno!(EINVAL, "program path is a valid entry point");
}
Ok(())
}

@ -11,6 +11,9 @@
"OCCLUM=yes", "OCCLUM=yes",
"TEST=true" "TEST=true"
], ],
"entry_points": [
"/bin"
],
"mount": [ "mount": [
{ {
"target": "/", "target": "/",

@ -52,6 +52,11 @@ get_conf_env() {
python -c "import sys, json; print json.dumps(json.load(sys.stdin)['env'])" python -c "import sys, json; print json.dumps(json.load(sys.stdin)['env'])"
} }
get_conf_entry_points() {
cat "$working_dir/Occlum.json" | \
python -c "import sys, json; print json.dumps(json.load(sys.stdin)['entry_points'])"
}
get_occlum_conf_file_mac() { get_occlum_conf_file_mac() {
"$occlum_dir/build/bin/occlum-protect-integrity" show-mac "$context_dir/build/Occlum.json.protected" "$occlum_dir/build/bin/occlum-protect-integrity" show-mac "$context_dir/build/Occlum.json.protected"
} }
@ -121,6 +126,7 @@ cmd_build() {
export OCCLUM_CONF_DEFAULT_HEAP_SIZE=`get_conf_default_heap_size` export OCCLUM_CONF_DEFAULT_HEAP_SIZE=`get_conf_default_heap_size`
export OCCLUM_CONF_DEFAULT_MMAP_SIZE=`get_conf_default_mmap_size` export OCCLUM_CONF_DEFAULT_MMAP_SIZE=`get_conf_default_mmap_size`
export OCCLUM_CONF_ENV=`get_conf_env` export OCCLUM_CONF_ENV=`get_conf_env`
export OCCLUM_CONF_ENTRY_POINTS=`get_conf_entry_points`
cd "$context_dir/build" cd "$context_dir/build"
"$occlum_dir/build/bin/occlum-gen-default-occlum-json"\ "$occlum_dir/build/bin/occlum-gen-default-occlum-json"\
> "Occlum.json" > "Occlum.json"

@ -34,6 +34,7 @@ cat <<EOF
"type": "ramfs" "type": "ramfs"
} }
], ],
"env": $OCCLUM_CONF_ENV "env": $OCCLUM_CONF_ENV,
"entry_points": $OCCLUM_CONF_ENTRY_POINTS
} }
EOF EOF