From 2347951743f8e237741498f4d39ced6c3d0f84f6 Mon Sep 17 00:00:00 2001 From: "Zheng, Qi" Date: Tue, 17 May 2022 09:32:09 +0800 Subject: [PATCH] Combine two config json files as one --- .../init_ra_flow/init_ra/src/main.rs | 16 +- etc/template/Occlum.json | 8 - example/init_ra/src/main.rs | 16 +- src/libos/src/config.rs | 101 ++++-- src/libos/src/entry.rs | 9 +- src/libos/src/fs/fs_ops/mount.rs | 10 +- src/libos/src/fs/mod.rs | 2 +- src/libos/src/fs/rootfs.rs | 115 +++++- src/libos/src/fs/syscalls.rs | 20 +- src/libos/src/syscall/mod.rs | 6 +- tools/gen_internal_conf/src/main.rs | 326 ++++++++++-------- tools/init/src/main.rs | 17 +- tools/occlum | 4 +- tools/occlum_build.mk | 31 +- 14 files changed, 421 insertions(+), 260 deletions(-) diff --git a/demos/remote_attestation/init_ra_flow/init_ra/src/main.rs b/demos/remote_attestation/init_ra_flow/init_ra/src/main.rs index 6902bd28..d133ab73 100644 --- a/demos/remote_attestation/init_ra_flow/init_ra/src/main.rs +++ b/demos/remote_attestation/init_ra_flow/init_ra/src/main.rs @@ -39,14 +39,6 @@ fn main() -> Result<(), Box> { const IMAGE_CONFIG_FILE: &str = "/etc/image_config.json"; let image_config = load_config(IMAGE_CONFIG_FILE)?; - // Get the MAC of Occlum.json.protected file - let occlum_json_mac = { - let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default(); - parse_str_to_bytes(&image_config.occlum_json_mac, &mut mac)?; - mac - }; - let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t; - // Get client secrets through grpc-ratls let server_addr = CString::new("localhost:50051").unwrap(); let config_json = CString::new("dynamic_config.json").unwrap(); @@ -136,7 +128,10 @@ fn main() -> Result<(), Box> { // Mount the image const SYS_MOUNT_FS: i64 = 363; - let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, occlum_json_mac_ptr) }; + // User can provide valid path for runtime mount and boot + // Otherwise, just pass null pointer to do general mount and boot + let root_config_path: *const i8 = std::ptr::null(); + let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, root_config_path) }; if ret < 0 { return Err(Box::new(std::io::Error::last_os_error())); } @@ -150,13 +145,10 @@ fn main() -> Result<(), Box> { #[allow(non_camel_case_types)] type sgx_key_128bit_t = [u8; 16]; -#[allow(non_camel_case_types)] -type sgx_aes_gcm_128bit_tag_t = [u8; 16]; #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] struct ImageConfig { - occlum_json_mac: String, image_type: String, } diff --git a/etc/template/Occlum.json b/etc/template/Occlum.json index 99a07de6..be56e8b4 100644 --- a/etc/template/Occlum.json +++ b/etc/template/Occlum.json @@ -62,14 +62,6 @@ "target": "/host", "type": "hostfs", "source": "." - }, - { - "target": "/proc", - "type": "procfs" - }, - { - "target": "/dev", - "type": "devfs" } ] } diff --git a/example/init_ra/src/main.rs b/example/init_ra/src/main.rs index c02aa149..930d99b9 100644 --- a/example/init_ra/src/main.rs +++ b/example/init_ra/src/main.rs @@ -29,14 +29,6 @@ fn main() -> Result<(), Box> { const IMAGE_CONFIG_FILE: &str = "/etc/image_config.json"; let image_config = load_config(IMAGE_CONFIG_FILE)?; - // Get the MAC of Occlum.json.protected file - let occlum_json_mac = { - let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default(); - parse_str_to_bytes(&image_config.occlum_json_mac, &mut mac)?; - mac - }; - let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t; - // Get grpc server address from environment GRPC_SERVER let server_addr = CString::new( env::var("GRPC_SERVER").unwrap_or("localhost:50051".to_string())) @@ -99,7 +91,10 @@ fn main() -> Result<(), Box> { // Mount the image const SYS_MOUNT_FS: i64 = 363; - let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, occlum_json_mac_ptr) }; + // User can provide valid path for runtime mount and boot + // Otherwise, just pass null pointer to do general mount and boot + let root_config_path: *const i8 = std::ptr::null(); + let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, root_config_path) }; if ret < 0 { return Err(Box::new(std::io::Error::last_os_error())); } @@ -112,13 +107,10 @@ fn main() -> Result<(), Box> { #[allow(non_camel_case_types)] type sgx_key_128bit_t = [u8; 16]; -#[allow(non_camel_case_types)] -type sgx_aes_gcm_128bit_tag_t = [u8; 16]; #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] struct ImageConfig { - occlum_json_mac: String, image_type: String, } diff --git a/src/libos/src/config.rs b/src/libos/src/config.rs index 772da652..68acb1c6 100644 --- a/src/libos/src/config.rs +++ b/src/libos/src/config.rs @@ -94,8 +94,7 @@ pub struct Config { pub resource_limits: ConfigResourceLimits, pub process: ConfigProcess, pub env: ConfigEnv, - pub entry_points: Vec, - pub mount: Vec, + pub app: Vec, } #[derive(Debug)] @@ -116,7 +115,7 @@ pub struct ConfigEnv { pub untrusted: HashSet, } -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ConfigMount { pub type_: ConfigMountFsType, pub target: PathBuf, @@ -124,7 +123,14 @@ pub struct ConfigMount { pub options: ConfigMountOptions, } -#[derive(Debug, PartialEq)] +#[derive(Clone, Debug)] +pub struct ConfigApp { + pub entry_points: Vec, + pub stage: String, + pub mount: Vec, +} + +#[derive(Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] pub enum ConfigMountFsType { TYPE_SEFS, @@ -154,12 +160,13 @@ impl ConfigMountFsType { } } -#[derive(Default, Debug)] +#[derive(Clone, Default, Debug)] pub struct ConfigMountOptions { pub mac: Option, pub layers: Option>, pub temporary: bool, pub cache_size: Option, + pub index: u32, } impl Config { @@ -167,32 +174,32 @@ impl Config { let resource_limits = ConfigResourceLimits::from_input(&input.resource_limits)?; let process = ConfigProcess::from_input(&input.process)?; let env = ConfigEnv::from_input(&input.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); + + let app = { + let mut app = Vec::new(); + for input_app in &input.app { + app.push(ConfigApp::from_input(&input_app)?); } - entry_points - }; - let mount = { - let mut mount = Vec::new(); - for input_mount in &input.mount { - mount.push(ConfigMount::from_input(&input_mount)?); - } - mount + app }; + Ok(Config { resource_limits, process, env, - entry_points, - mount, + app, }) } + + pub fn get_app_config(&self, stage: &str) -> Result<&ConfigApp> { + let config_app = self + .app + .iter() + .find(|m| m.stage.eq(stage)) + .ok_or_else(|| errno!(Errno::ENOENT, "No expected config app"))?; + + Ok(config_app) + } } impl ConfigResourceLimits { @@ -224,6 +231,36 @@ impl ConfigEnv { } } +impl ConfigApp { + fn from_input(input: &InputConfigApp) -> Result { + let stage = input.stage.clone(); + 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 mut mount = Vec::new(); + for input_mount in &input.mount { + mount.push(ConfigMount::from_input(&input_mount)?); + } + mount + }; + + Ok(ConfigApp { + stage, + entry_points, + mount, + }) + } +} + impl ConfigMount { fn from_input(input: &InputConfigMount) -> Result { let type_ = ConfigMountFsType::from_input(input.type_.as_str())?; @@ -277,6 +314,7 @@ impl ConfigMountOptions { layers, temporary: input.temporary, cache_size, + index: input.index, }) } } @@ -316,9 +354,7 @@ struct InputConfig { #[serde(default)] pub env: InputConfigEnv, #[serde(default)] - pub entry_points: Vec, - #[serde(default)] - pub mount: Vec, + pub app: Vec, } #[derive(Deserialize, Debug)] @@ -415,4 +451,17 @@ struct InputConfigMountOptions { pub temporary: bool, #[serde(default)] pub cache_size: Option, + #[serde(default)] + pub index: u32, +} + +#[derive(Deserialize, Debug)] +#[serde(deny_unknown_fields)] +struct InputConfigApp { + #[serde(default)] + pub stage: String, + #[serde(default)] + pub entry_points: Vec, + #[serde(default)] + pub mount: Vec, } diff --git a/src/libos/src/entry.rs b/src/libos/src/entry.rs index bd2458e3..e3c341f5 100644 --- a/src/libos/src/entry.rs +++ b/src/libos/src/entry.rs @@ -24,8 +24,13 @@ static mut ENCLAVE_PATH: String = String::new(); lazy_static! { static ref INIT_ONCE: Once = Once::new(); static ref HAS_INIT: AtomicBool = AtomicBool::new(false); - pub static ref ENTRY_POINTS: RwLock> = - RwLock::new(config::LIBOS_CONFIG.entry_points.clone()); + pub static ref ENTRY_POINTS: RwLock> = RwLock::new( + config::LIBOS_CONFIG + .get_app_config("init") + .unwrap() + .entry_points + .clone() + ); pub static ref RESOLV_CONF_STR: RwLock> = RwLock::new(None); pub static ref HOSTNAME_STR: RwLock> = RwLock::new(None); pub static ref HOSTS_STR: RwLock> = RwLock::new(None); diff --git a/src/libos/src/fs/fs_ops/mount.rs b/src/libos/src/fs/fs_ops/mount.rs index 4979b9fc..6525f057 100644 --- a/src/libos/src/fs/fs_ops/mount.rs +++ b/src/libos/src/fs/fs_ops/mount.rs @@ -13,7 +13,7 @@ lazy_static! { } pub fn do_mount_rootfs( - user_config: &config::Config, + user_app_config: &config::ConfigApp, user_key: &Option, ) -> Result<()> { debug!("mount rootfs"); @@ -21,13 +21,15 @@ pub fn do_mount_rootfs( if MOUNT_ONCE.is_completed() { return_errno!(EPERM, "rootfs cannot be mounted more than once"); } - let new_rootfs = open_root_fs_according_to(&user_config.mount, user_key)?; - mount_nonroot_fs_according_to(&new_rootfs.root_inode(), &user_config.mount, user_key, true)?; + + let mount_config = &user_app_config.mount; + let new_rootfs = open_root_fs_according_to(mount_config, user_key)?; + mount_nonroot_fs_according_to(&new_rootfs.root_inode(), mount_config, user_key, true)?; MOUNT_ONCE.call_once(|| { let mut rootfs = ROOT_FS.write().unwrap(); rootfs.sync().expect("failed to sync old rootfs"); *rootfs = new_rootfs; - *ENTRY_POINTS.write().unwrap() = user_config.entry_points.to_owned(); + *ENTRY_POINTS.write().unwrap() = user_app_config.entry_points.to_owned(); }); // Write resolv.conf file into mounted file system diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 8d752b8f..bc378edf 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -33,7 +33,7 @@ pub use self::locks::range_lock::{ FileRange, RangeLock, RangeLockBuilder, RangeLockList, RangeLockType, OFFSET_MAX, }; pub use self::pipe::PipeType; -pub use self::rootfs::ROOT_FS; +pub use self::rootfs::{gen_config_app, user_rootfs_config, ROOT_FS}; pub use self::stdio::{HostStdioFds, StdinFile, StdoutFile}; pub use self::syscalls::*; pub use self::timer_file::{AsTimer, TimerCreationFlags, TimerFile}; diff --git a/src/libos/src/fs/rootfs.rs b/src/libos/src/fs/rootfs.rs index 9a3c2506..ca2eafdf 100644 --- a/src/libos/src/fs/rootfs.rs +++ b/src/libos/src/fs/rootfs.rs @@ -3,7 +3,7 @@ use super::hostfs::HostFS; use super::procfs::ProcFS; use super::sefs::{SgxStorage, SgxUuidProvider}; use super::*; -use config::ConfigMountFsType; +use config::{ConfigApp, ConfigMountFsType}; use std::path::{Path, PathBuf}; use std::untrusted::path::PathEx; @@ -13,11 +13,13 @@ use rcore_fs_sefs::dev::*; use rcore_fs_sefs::SEFS; use rcore_fs_unionfs::UnionFS; +use util::mem_util::from_user; + lazy_static! { /// The root of file system pub static ref ROOT_FS: RwLock> = { fn init_root_fs() -> Result> { - let mount_config = &config::LIBOS_CONFIG.mount; + let mount_config = &config::LIBOS_CONFIG.get_app_config("init").unwrap().mount; let rootfs = open_root_fs_according_to(mount_config, &None)?; mount_nonroot_fs_according_to(&rootfs.root_inode(), mount_config, &None, true)?; Ok(rootfs) @@ -49,7 +51,7 @@ pub fn open_root_fs_according_to( .find(|m| { m.target == Path::new("/") && m.type_ == ConfigMountFsType::TYPE_SEFS - && m.options.mac.is_some() + && (m.options.mac.is_some() || m.options.index == 1) }) .ok_or_else(|| errno!(Errno::ENOENT, "the image SEFS in layers is not valid"))?; let root_image_sefs = @@ -61,6 +63,7 @@ pub fn open_root_fs_according_to( m.target == Path::new("/") && m.type_ == ConfigMountFsType::TYPE_SEFS && m.options.mac.is_none() + && m.options.index == 0 }) .ok_or_else(|| errno!(Errno::ENOENT, "the container SEFS in layers is not valid"))?; let root_container_sefs = @@ -262,3 +265,109 @@ fn open_or_create_sefs_according_to( }; Ok(sefs) } + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub struct user_rootfs_config { + upper_layer_path: *const i8, + lower_layer_path: *const i8, + entry_point: *const i8, + hostfs_source: *const i8, + hostfs_target: *const i8, +} + +impl user_rootfs_config { + pub fn from_raw_ptr(ptr: *const user_rootfs_config) -> Result { + let config = unsafe { *ptr }; + Ok(config) + } +} + +fn to_option_pathbuf(path: *const i8) -> Result> { + let path = if path.is_null() { + None + } else { + Some(PathBuf::from( + from_user::clone_cstring_safely(path)? + .to_string_lossy() + .into_owned(), + )) + }; + + Ok(path) +} + +pub fn gen_config_app(config: &user_rootfs_config) -> Result { + let upper_layer = to_option_pathbuf(config.upper_layer_path)?; + let lower_layer = to_option_pathbuf(config.lower_layer_path)?; + let entry_point = to_option_pathbuf(config.entry_point)?; + let hostfs_source = to_option_pathbuf(config.hostfs_source)?; + + let hostfs_target = if config.hostfs_target.is_null() { + PathBuf::from("/host") + } else { + PathBuf::from( + from_user::clone_cstring_safely(config.hostfs_target)? + .to_string_lossy() + .into_owned(), + ) + }; + + let mut config_app = config::LIBOS_CONFIG.get_app_config("app").unwrap().clone(); + let root_mount_config = config_app + .mount + .iter_mut() + .find(|m| m.target == Path::new("/") && m.type_ == ConfigMountFsType::TYPE_UNIONFS) + .ok_or_else(|| errno!(Errno::ENOENT, "the root UnionFS is not valid"))?; + + if upper_layer.is_some() { + let layer_mount_configs = root_mount_config.options.layers.as_mut().unwrap(); + // image SEFS in layers + let root_image_sefs_mount_config = layer_mount_configs + .iter_mut() + .find(|m| { + m.target == Path::new("/") + && m.type_ == ConfigMountFsType::TYPE_SEFS + && (m.options.mac.is_some() || m.options.index == 1) + }) + .ok_or_else(|| errno!(Errno::ENOENT, "the image SEFS in layers is not valid"))?; + + root_image_sefs_mount_config.source = upper_layer; + root_image_sefs_mount_config.options.mac = None; + root_image_sefs_mount_config.options.index = 1; + } + + if lower_layer.is_some() { + let layer_mount_configs = root_mount_config.options.layers.as_mut().unwrap(); + // container SEFS in layers + let root_container_sefs_mount_config = layer_mount_configs + .iter_mut() + .find(|m| { + m.target == Path::new("/") + && m.type_ == ConfigMountFsType::TYPE_SEFS + && m.options.mac.is_none() + && m.options.index == 0 + }) + .ok_or_else(|| errno!(Errno::ENOENT, "the container SEFS in layers is not valid"))?; + + root_container_sefs_mount_config.source = lower_layer; + } + + if entry_point.is_some() { + config_app.entry_points.clear(); + config_app.entry_points.push(entry_point.unwrap()) + } + + if hostfs_source.is_some() { + let hostfs_mount_config = config_app + .mount + .iter_mut() + .find(|m| m.type_ == ConfigMountFsType::TYPE_HOSTFS) + .ok_or_else(|| errno!(Errno::ENOENT, "the HostFS is not valid"))?; + hostfs_mount_config.source = hostfs_source; + hostfs_mount_config.target = hostfs_target; + } + + Ok(config_app) +} diff --git a/src/libos/src/fs/syscalls.rs b/src/libos/src/fs/syscalls.rs index 04d2f658..51f9e10f 100644 --- a/src/libos/src/fs/syscalls.rs +++ b/src/libos/src/fs/syscalls.rs @@ -660,20 +660,26 @@ pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result { pub fn do_mount_rootfs( key_ptr: *const sgx_key_128bit_t, - occlum_json_mac_ptr: *const sgx_aes_gcm_128bit_tag_t, + rootfs_config: *const user_rootfs_config, ) -> Result { let key = if key_ptr.is_null() { None } else { Some(unsafe { key_ptr.read() }) }; - if occlum_json_mac_ptr.is_null() { - return_errno!(EINVAL, "occlum_json_mac_ptr cannot be null"); + + // If user provided valid parameters, do runtime mount and boot + // Otherwise, do general mount and boot + if !rootfs_config.is_null() { + from_user::check_ptr(rootfs_config)?; + let rootfs_config = user_rootfs_config::from_raw_ptr(rootfs_config)?; + let app_config = gen_config_app(&rootfs_config)?; + debug!("user provided app config: {:?}", app_config); + fs_ops::do_mount_rootfs(&app_config, &key)?; + } else { + fs_ops::do_mount_rootfs(&config::LIBOS_CONFIG.get_app_config("app").unwrap(), &key)?; } - let expected_occlum_json_mac = unsafe { occlum_json_mac_ptr.read() }; - let user_config_path = unsafe { format!("{}{}", INSTANCE_DIR, "/build/Occlum.json.protected") }; - let user_config = config::load_config(&user_config_path, &expected_occlum_json_mac)?; - fs_ops::do_mount_rootfs(&user_config, &key)?; + Ok(0) } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 2bea12a2..e857739e 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -31,8 +31,8 @@ use crate::fs::{ do_pwritev, do_read, do_readlink, do_readlinkat, do_readv, do_rename, do_renameat, do_rmdir, do_sendfile, do_stat, do_statfs, do_symlink, do_symlinkat, do_sync, do_timerfd_create, do_timerfd_gettime, do_timerfd_settime, do_truncate, do_umask, do_umount, do_unlink, - do_unlinkat, do_utime, do_utimensat, do_utimes, do_write, do_writev, iovec_t, utimbuf_t, - AsTimer, File, FileDesc, FileRef, HostStdioFds, Stat, Statfs, + do_unlinkat, do_utime, do_utimensat, do_utimes, do_write, do_writev, iovec_t, + user_rootfs_config, utimbuf_t, AsTimer, File, FileDesc, FileRef, HostStdioFds, Stat, Statfs, }; use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; use crate::ipc::{do_shmat, do_shmctl, do_shmdt, do_shmget, key_t, shmids_t}; @@ -425,7 +425,7 @@ macro_rules! process_syscall_table_with_callback { (SpawnMusl = 360) => do_spawn_for_musl(child_pid_ptr: *mut u32, path: *const i8, argv: *const *const i8, envp: *const *const i8, fdop_list: *const FdOp, attribute_list: *const posix_spawnattr_t), (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), - (MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, occlum_json_mac_ptr: *const sgx_aes_gcm_128bit_tag_t), + (MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, rootfs_config: *const user_rootfs_config), } }; } diff --git a/tools/gen_internal_conf/src/main.rs b/tools/gen_internal_conf/src/main.rs index 045b7518..9e4dc1e6 100644 --- a/tools/gen_internal_conf/src/main.rs +++ b/tools/gen_internal_conf/src/main.rs @@ -67,8 +67,8 @@ fn main() { .takes_value(true), ) .subcommand( - SubCommand::with_name("gen_user_conf") - .about("Generate user image config") + SubCommand::with_name("gen_conf") + .about("Generate image config") // Input: User's Secure Occlum FS image MAC .arg( Arg::with_name("user_fs_mac") @@ -77,11 +77,19 @@ fn main() { .required(true) .takes_value(true), ) + // Input: InitFS image MAC + .arg( + Arg::with_name("init_fs_mac") + .long("init_fs_mac") + .value_name("input MAC of init image fs") + .required(true) + .takes_value(true), + ) // Output: JSON file used by libOS and users shouldn't touch .arg( - Arg::with_name("output_user_json") - .long("output_user_json") - .value_name("output user json") + Arg::with_name("output_json") + .long("output_json") + .value_name("output json") .required(true) .validator(|f| match File::create(f) { Ok(_) => Ok(()), @@ -102,30 +110,6 @@ fn main() { .takes_value(true), ), ) - .subcommand( - SubCommand::with_name("gen_sys_conf") - .about("Generate initfs image config") - // Input: InitFS image MAC - .arg( - Arg::with_name("init_fs_mac") - .long("init_fs_mac") - .value_name("input MAC of init image fs") - .required(true) - .takes_value(true), - ) - // Output: JSON file for initfs and users shouldn't touch - .arg( - Arg::with_name("sys_json") - .long("sys_json") - .value_name("output sys json") - .required(true) - .validator(|f| match File::create(f) { - Ok(_) => Ok(()), - Err(e) => Err(e.to_string()), - }) - .takes_value(true), - ), - ) .get_matches(); let occlum_config_file_path = matches.value_of("user_json").unwrap(); @@ -141,14 +125,17 @@ fn main() { debug!("The occlum config is:{:?}", occlum_config); // Match subcommand - if let Some(sub_matches) = matches.subcommand_matches("gen_user_conf") { + if let Some(sub_matches) = matches.subcommand_matches("gen_conf") { let occlum_conf_user_fs_mac = sub_matches.value_of("user_fs_mac").unwrap(); debug!("Occlum config user FS MAC {:?}", occlum_conf_user_fs_mac); - let occlum_user_json_file_path = sub_matches.value_of("output_user_json").unwrap(); + let occlum_conf_init_fs_mac = sub_matches.value_of("init_fs_mac").unwrap(); + debug!("Occlum config init FS MAC {:?}", occlum_conf_init_fs_mac); + + let occlum_json_file_path = sub_matches.value_of("output_json").unwrap(); debug!( - "Generated Occlum user config (json) file name {:?}", - occlum_user_json_file_path + "Genereated Occlum user config (json) file name {:?}", + occlum_json_file_path ); let enclave_config_file_path = sub_matches.value_of("sdk_xml").unwrap(); @@ -273,17 +260,23 @@ fn main() { let enclave_config = serde_xml_rs::to_string(&sgx_enclave_configuration).unwrap(); debug!("The enclave config:{:?}", enclave_config); - // Generate user Occlum.json - "output_user_json" - let user_mount_config = { - let user_mount_config = - gen_user_mount_config(occlum_config.mount, occlum_conf_user_fs_mac.to_string()); - if user_mount_config.is_err() { - println!("Mount configuration invalid: {:?}", user_mount_config); + // Generate app config, including "init" and user app + let app_config = { + let app_config = + gen_app_config( + occlum_config.entry_points, + occlum_config.mount, + occlum_conf_user_fs_mac.to_string(), + occlum_conf_init_fs_mac.to_string(), + ); + if app_config.is_err() { + println!("Mount configuration invalid: {:?}", app_config); return; } - user_mount_config.unwrap() + app_config.unwrap() }; - let user_occlum_json_config = InternalOcclumJson { + + let occlum_json_config = InternalOcclumJson { resource_limits: InternalResourceLimits { user_space_size: occlum_config.resource_limits.user_space_size.to_string(), }, @@ -292,12 +285,12 @@ fn main() { default_heap_size: occlum_config.process.default_heap_size, default_mmap_size: occlum_config.process.default_mmap_size, }, - entry_points: occlum_config.entry_points, env: occlum_config.env, - mount: serde_json::to_value(user_mount_config).unwrap(), + app: app_config, }; - let user_occlum_json_str = serde_json::to_string_pretty(&user_occlum_json_config).unwrap(); - debug!("The user Occlum.json config:\n{:?}", user_occlum_json_str); + + let occlum_json_str = serde_json::to_string_pretty(&occlum_json_config).unwrap(); + debug!("The Occlum.json config:\n{:?}", occlum_json_str); // Update the output file let mut enclave_config_file = File::create(enclave_config_file_path) @@ -306,44 +299,11 @@ fn main() { .write_all(enclave_config.as_bytes()) .expect("Failed to update the Enclave configuration file."); - let mut user_occlum_json = File::create(occlum_user_json_file_path) - .expect("Could not open the output user Occlum.json file."); - user_occlum_json - .write_all(user_occlum_json_str.as_bytes()) - .expect("Failed to update the output user Occlum.json file."); - } else if let Some(sub_matches) = matches.subcommand_matches("gen_sys_conf") { - let occlum_conf_init_fs_mac = sub_matches.value_of("init_fs_mac").unwrap(); - debug!("Occlum config init FS MAC {:?}", occlum_conf_init_fs_mac); - - let occlum_sys_json_file_path = sub_matches.value_of("sys_json").unwrap(); - debug!( - "Generated Occlum sys config (json) file name {:?}", - occlum_sys_json_file_path - ); - - // Generate sys Occlum.json - "sys_json" - let sys_occlum_json_config = InternalOcclumJson { - resource_limits: InternalResourceLimits { - user_space_size: occlum_config.resource_limits.user_space_size.to_string(), - }, - process: OcclumProcess { - default_stack_size: occlum_config.process.default_stack_size, - default_heap_size: occlum_config.process.default_heap_size, - default_mmap_size: occlum_config.process.default_mmap_size, - }, - entry_points: json!(["/bin"]), - env: occlum_config.env, - mount: gen_sys_mount_config(occlum_conf_init_fs_mac.to_string()), - }; - - // Update the output file - let sys_occlum_json_str = serde_json::to_string_pretty(&sys_occlum_json_config).unwrap(); - debug!("The sys Occlum.json config:\n{:?}", sys_occlum_json_str); - let mut sys_occlum_json = File::create(occlum_sys_json_file_path) - .expect("Could not open the output sys Occlum.json file."); - sys_occlum_json - .write_all(sys_occlum_json_str.as_bytes()) - .expect("Failed to update the output sys Occlum.json file."); + let mut occlum_json = File::create(occlum_json_file_path) + .expect("Could not open the output Occlum.json file."); + occlum_json + .write_all(occlum_json_str.as_bytes()) + .expect("Failed to update the output Occlum.json file."); } else { unreachable!(); } @@ -402,78 +362,151 @@ fn parse_kss_conf(occlum_config: &OcclumConfiguration) -> (u32, u64, u64, u64, u } } -fn gen_user_mount_config( +fn gen_app_config( + entry_points: serde_json::Value, mount_conf: Vec, occlum_conf_user_fs_mac: String, -) -> Result, &'static str> { - let mut user_mount_config = mount_conf; - let root_mc = user_mount_config - .iter_mut() - .find(|m| m.target == String::from("/") && m.type_ == String::from("unionfs")) - .ok_or("the root UnionFS is not valid")?; - if root_mc.options.layers.is_none() { - return Err("the root UnionFS must be given layers"); - } - let mut root_image_sefs_mc = root_mc - .options - .layers - .as_mut() - .unwrap() + occlum_conf_init_fs_mac: String, +) -> Result { + let mut app_config: serde_json::Value = json!({ + "app": [ + { + "stage": "init", + "entry_points": [ + "/bin" + ], + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/initfs/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/initfs/__ROOT" + } + ] + } + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] + }, + { + "stage": "app", + "entry_points": [], + "mount": [ + { + "target": "/", + "type": "unionfs", + "options": { + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./build/mount/__ROOT", + "options": { + "MAC": "" + } + }, + { + "target": "/", + "type": "sefs", + "source": "./run/mount/__ROOT" + } + ] + } + }, + { + "target": "/host", + "type": "hostfs", + "source": "." + }, + { + "target": "/proc", + "type": "procfs" + }, + { + "target": "/dev", + "type": "devfs" + } + ] + }] + }); + + // Update init root mount fs MAC + *app_config + .pointer_mut("/app/0/mount/0/options/layers/0/options/MAC") + .unwrap() = serde_json::Value::String(occlum_conf_init_fs_mac); + + // Update app entry points + *app_config + .pointer_mut("/app/1/entry_points") + .unwrap() = entry_points; + + let mut mount_config = mount_conf; + if let Some(root_mc) = mount_config .iter_mut() .find(|m| { m.target == String::from("/") - && m.type_ == String::from("sefs") - && m.options.mac.is_some() - }) - .ok_or("the image SEFS in layers is not valid")?; - root_image_sefs_mc.options.mac = Some(occlum_conf_user_fs_mac); + && m.type_ == String::from("unionfs") + }) { + debug!("User provides Root mount config:\n{:?}", root_mc); + root_mc + .options + .layers + .as_mut() + .unwrap() + .iter_mut() + .find(|m| { + m.target == String::from("/") + && m.type_ == String::from("sefs") + && m.options.mac.is_some() + }) + .ok_or("the image SEFS in layers is not valid")?; - debug!("user Occlum.json mount config:\n{:?}", user_mount_config); - Ok(user_mount_config) -} + // Update app root mount + *app_config + .pointer_mut("/app/1/mount/0") + .unwrap() = serde_json::to_value(root_mc).unwrap(); + } -fn gen_sys_mount_config(occlum_conf_init_fs_mac: String) -> serde_json::Value { - let mut init_fs_mount_config: serde_json::Value = json!({ - "mount": [ - { - "target": "/", - "type": "unionfs", - "options": { - "layers": [ - { - "target": "/", - "type": "sefs", - "source": "./build/initfs/__ROOT", - "options": { - "MAC": "" - } - }, - { - "target": "/", - "type": "sefs", - "source": "./run/initfs/__ROOT" - } - ] - } - }, - { - "target": "/proc", - "type": "procfs" - }, - { - "target": "/dev", - "type": "devfs" - } - ] - }); + // Update app root mount fs MAC + *app_config + .pointer_mut("/app/1/mount/0/options/layers/0/options/MAC") + .unwrap() = serde_json::Value::String(occlum_conf_user_fs_mac); - *init_fs_mount_config - .pointer_mut("/mount/0/options/layers/0/options/MAC") - .unwrap() = serde_json::Value::String(occlum_conf_init_fs_mac); + // Update host mount + if let Some(host_mc) = mount_config + .iter_mut() + .find(|m| { + m.type_ == String::from("hostfs") + }) { + debug!("User provides host mount config:\n{:?}", host_mc); + // Update app root mount + *app_config + .pointer_mut("/app/1/mount/1") + .unwrap() = serde_json::to_value(host_mc).unwrap(); + } - debug!("initfs mount config:\n{:?}", init_fs_mount_config); + debug!("Occlum.json mount config:\n{:?}", app_config); - init_fs_mount_config["mount"].to_owned() + Ok(app_config["app"].to_owned()) } #[derive(Debug, PartialEq, Deserialize)] @@ -598,7 +631,6 @@ struct InternalResourceLimits { struct InternalOcclumJson { resource_limits: InternalResourceLimits, process: OcclumProcess, - entry_points: serde_json::Value, env: serde_json::Value, - mount: serde_json::Value, + app: serde_json::Value, } diff --git a/tools/init/src/main.rs b/tools/init/src/main.rs index 5c5902e6..9e289255 100644 --- a/tools/init/src/main.rs +++ b/tools/init/src/main.rs @@ -14,14 +14,6 @@ fn main() -> Result<(), Box> { const IMAGE_CONFIG_FILE: &str = "/etc/image_config.json"; let image_config = load_config(IMAGE_CONFIG_FILE)?; - // Get the MAC of Occlum.json.protected file - let occlum_json_mac = { - let mut mac: sgx_aes_gcm_128bit_tag_t = Default::default(); - parse_str_to_bytes(&image_config.occlum_json_mac, &mut mac)?; - mac - }; - let occlum_json_mac_ptr = &occlum_json_mac as *const sgx_aes_gcm_128bit_tag_t; - // Get the key of FS image if needed let key = match &image_config.image_type[..] { "encrypted" => { @@ -42,7 +34,11 @@ fn main() -> Result<(), Box> { // Mount the image const SYS_MOUNT_FS: i64 = 363; - let ret = unsafe { syscall(SYS_MOUNT_FS, key_ptr, occlum_json_mac_ptr) }; + // User can provide valid path for runtime mount and boot + // Otherwise, just pass null pointer to do general mount and boot + let root_config_path: *const i8 = std::ptr::null(); + let ret = unsafe { syscall( + SYS_MOUNT_FS, key_ptr, root_config_path) }; if ret < 0 { return Err(Box::new(std::io::Error::last_os_error())); } @@ -52,13 +48,10 @@ fn main() -> Result<(), Box> { #[allow(non_camel_case_types)] type sgx_key_128bit_t = [u8; 16]; -#[allow(non_camel_case_types)] -type sgx_aes_gcm_128bit_tag_t = [u8; 16]; #[derive(Deserialize, Debug)] #[serde(deny_unknown_fields)] struct ImageConfig { - occlum_json_mac: String, image_type: String, } diff --git a/tools/occlum b/tools/occlum index ca26b118..c9ae94eb 100755 --- a/tools/occlum +++ b/tools/occlum @@ -510,8 +510,8 @@ cmd_package() { $instance_base_name/build/bin \ $instance_base_name/build/lib/libocclum-libos.signed.so \ $instance_base_name/build/lib/libocclum-pal.so* \ - $instance_base_name/build/mount $instance_base_name/build/Occlum.json.protected \ - $instance_base_name/build/initfs $instance_base_name/build/.Occlum_sys.json.protected \ + $instance_base_name/build/initfs $instance_base_name/build/mount \ + $instance_base_name/build/.Occlum_sys.json.protected \ $instance_base_name/initfs $instance_base_name/run \ $instance_base_name/.__occlum_status $instance_base_name/.sgx_mode \ " diff --git a/tools/occlum_build.mk b/tools/occlum_build.mk index 62b257ba..6747e761 100644 --- a/tools/occlum_build.mk +++ b/tools/occlum_build.mk @@ -68,9 +68,11 @@ $(instance_dir)/build/.Occlum_sys.json.protected: $(instance_dir)/build/.Occlum_ @cd "$(instance_dir)/build" ; \ LD_LIBRARY_PATH="$(SGX_SDK)/sdk_libs" "$(occlum_dir)/build/bin/occlum-protect-integrity" protect .Occlum_sys.json ; -$(instance_dir)/build/.Occlum_sys.json: $(INITFS_IMAGE) $(INITFS_IMAGE_MAC) $(JSON_CONF) - @$(occlum_dir)/build/bin/gen_internal_conf --user_json "$(JSON_CONF)" gen_sys_conf \ - --init_fs_mac "`cat $(INITFS_IMAGE_MAC)`" --sys_json $(instance_dir)/build/.Occlum_sys.json +$(instance_dir)/build/Enclave.xml: +$(instance_dir)/build/.Occlum_sys.json: $(INITFS_IMAGE) $(INITFS_IMAGE_MAC) $(JSON_CONF) $(SECURE_IMAGE) $(SECURE_IMAGE_MAC) + @$(occlum_dir)/build/bin/gen_internal_conf --user_json "$(JSON_CONF)" gen_conf \ + --user_fs_mac "`cat $(SECURE_IMAGE_MAC)`" --sdk_xml "$(instance_dir)/build/Enclave.xml" \ + --init_fs_mac "`cat $(INITFS_IMAGE_MAC)`" --output_json $(instance_dir)/build/.Occlum_sys.json $(BIN_LINKS): $(instance_dir)/build/bin/%: $(occlum_dir)/build/bin/% | $(instance_dir)/build/bin @ln -sf $< $@ @@ -103,24 +105,11 @@ $(INITFS_IMAGE): $(INITFS) $(INITFS_DIRS) $(INITFS_FILES) $(IMAGE_CONFIG_JSON) $ "$(instance_dir)/build/initfs/__ROOT" \ "$(INITFS_IMAGE_MAC)" -$(IMAGE_CONFIG_JSON): $(instance_dir)/build/Occlum.json.protected - @$(call get_occlum_file_mac, "$(instance_dir)/build/Occlum.json.protected", "$(CONF_TMP_MAC)") && \ - [ -n "$(SECURE_IMAGE_KEY)" ] && \ - jq -n --arg mac_val "`cat $(CONF_TMP_MAC)`" \ - '{image_type: "encrypted", occlum_json_mac: $$mac_val}' > $(IMAGE_CONFIG_JSON) || \ - jq -n --arg mac_val "`cat $(CONF_TMP_MAC)`" \ - '{image_type: "integrity-only", occlum_json_mac: $$mac_val}' > $(IMAGE_CONFIG_JSON) - @rm -f "$(CONF_TMP_MAC)" - -$(instance_dir)/build/Occlum.json.protected: $(instance_dir)/build/Occlum.json - @cd "$(instance_dir)/build" ; \ - LD_LIBRARY_PATH="$(SGX_SDK)/sdk_libs" "$(occlum_dir)/build/bin/occlum-protect-integrity" protect Occlum.json ; - -$(instance_dir)/build/Enclave.xml: -$(instance_dir)/build/Occlum.json: $(SECURE_IMAGE) $(SECURE_IMAGE_MAC) $(JSON_CONF) | $(instance_dir)/build/lib - @$(occlum_dir)/build/bin/gen_internal_conf --user_json "$(JSON_CONF)" gen_user_conf \ - --user_fs_mac "`cat $(SECURE_IMAGE_MAC)`" --sdk_xml "$(instance_dir)/build/Enclave.xml" \ - --output_user_json $(instance_dir)/build/Occlum.json +$(IMAGE_CONFIG_JSON): + @mkdir -p "$(instance_dir)/build/lib" + @[ -n "$(SECURE_IMAGE_KEY)" ] && \ + jq -n '{image_type: "encrypted"}' > $(IMAGE_CONFIG_JSON) || \ + jq -n '{image_type: "integrity-only"}' > $(IMAGE_CONFIG_JSON) # If image dir not exist, just use the secure Occlum FS image ifneq ($(wildcard $(IMAGE)/. ),)