diff --git a/src/libos/src/config.rs b/src/libos/src/config.rs index 139a3715..d1752348 100644 --- a/src/libos/src/config.rs +++ b/src/libos/src/config.rs @@ -4,9 +4,12 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::ffi::CString; use std::io::Read; +use std::mem::size_of; use std::path::{Path, PathBuf}; use std::sgxfs::SgxFile; +use crate::util::mem_util::from_user; + lazy_static! { pub static ref LIBOS_CONFIG: Config = { let config_path = @@ -471,3 +474,160 @@ struct InputConfigApp { #[serde(default)] pub mount: Vec, } + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub struct user_rootfs_config { + // length of the struct + len: usize, + // UnionFS type rootfs upper layer, read-write layer + upper_layer_path: *const i8, + // UnionFS type rootfs lower layer, read-only layer + lower_layer_path: *const i8, + entry_point: *const i8, + // HostFS source path + hostfs_source: *const i8, + // HostFS target path, default value is "/host" + hostfs_target: *const i8, + // An array of pointers to null-terminated strings + // and must be terminated by a null pointer + envp: *const *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) +} + +fn combine_trusted_envs(envp: *const *const i8) -> Result<()> { + let mut user_envs = from_user::clone_cstrings_safely(envp)?; + trace!("User envs: {:?}", user_envs); + let env_key: Vec<&str> = user_envs + .iter() + .map(|x| { + let kv: Vec<&str> = x.to_str().unwrap().splitn(2, '=').collect(); + kv[0] + }) + .collect(); + + let mut merged = config::TRUSTED_ENVS.write().unwrap(); + // First clear the default envs then do the merge again + merged.clear(); + merged.extend_from_slice(&user_envs); + + for (_idx, val) in config::LIBOS_CONFIG.env.default.iter().enumerate() { + let kv: Vec<&str> = val.to_str().unwrap().splitn(2, '=').collect(); // only split the first "=" + info!("kv: {:?}", kv); + if !env_key.contains(&kv[0]) { + unsafe { merged.push(val.clone()) }; + } + } + + // trace!("Combined trusted envs: {:?}", merged); + Ok(()) +} + +impl ConfigApp { + pub fn from_user(config: &user_rootfs_config) -> Result { + // Check config struct length for future possible extension + if config.len != size_of::() { + return_errno!(EINVAL, "User Config Struct length not match"); + } + + // Combine the default envs and user envs if necessary + if !config.envp.is_null() { + combine_trusted_envs(config.envp)?; + } + + 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 = 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/mod.rs b/src/libos/src/fs/mod.rs index bc378edf..8d752b8f 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::{gen_config_app, user_rootfs_config, ROOT_FS}; +pub use self::rootfs::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 b3a5c42c..35799ae2 100644 --- a/src/libos/src/fs/rootfs.rs +++ b/src/libos/src/fs/rootfs.rs @@ -266,156 +266,3 @@ 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 { - // length of the struct - len: usize, - // UnionFS type rootfs upper layer, read-write layer - upper_layer_path: *const i8, - // UnionFS type rootfs lower layer, read-only layer - lower_layer_path: *const i8, - entry_point: *const i8, - // HostFS source path - hostfs_source: *const i8, - // HostFS target path, default value is "/host" - hostfs_target: *const i8, - // An array of pointers to null-terminated strings - // and must be terminated by a null pointer - envp: *const *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) -} - -fn combine_trusted_envs(envp: *const *const i8) -> Result<()> { - let mut user_envs = from_user::clone_cstrings_safely(envp)?; - trace!("User envs: {:?}", user_envs); - let env_key: Vec<&str> = user_envs - .iter() - .map(|x| { - let kv: Vec<&str> = x.to_str().unwrap().splitn(2, '=').collect(); - kv[0] - }) - .collect(); - - let mut merged = config::TRUSTED_ENVS.write().unwrap(); - // First clear the default envs then do the merge again - merged.clear(); - merged.extend_from_slice(&user_envs); - - for (_idx, val) in config::LIBOS_CONFIG.env.default.iter().enumerate() { - let kv: Vec<&str> = val.to_str().unwrap().splitn(2, '=').collect(); // only split the first "=" - info!("kv: {:?}", kv); - if !env_key.contains(&kv[0]) { - unsafe { merged.push(val.clone()) }; - } - } - - // trace!("Combined trusted envs: {:?}", merged); - Ok(()) -} - -pub fn gen_config_app(config: &user_rootfs_config) -> Result { - // Check config struct length for future possible extension - if config.len != size_of::() { - return_errno!(EINVAL, "User Config Struct length not match"); - } - - // Combine the default envs and user envs if necessary - if !config.envp.is_null() { - combine_trusted_envs(config.envp)?; - } - - 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 51f9e10f..2d3b0b6e 100644 --- a/src/libos/src/fs/syscalls.rs +++ b/src/libos/src/fs/syscalls.rs @@ -9,7 +9,7 @@ use super::fs_ops::{MountFlags, MountOptions, UmountFlags}; use super::time::{clockid_t, itimerspec_t, timespec_t, timeval_t, ClockID}; use super::timer_file::{TimerCreationFlags, TimerSetFlags}; use super::*; -use config::ConfigMountFsType; +use crate::config::{user_rootfs_config, ConfigApp, ConfigMountFsType}; use util::mem_util::from_user; #[allow(non_camel_case_types)] @@ -660,27 +660,25 @@ pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result { pub fn do_mount_rootfs( key_ptr: *const sgx_key_128bit_t, - rootfs_config: *const user_rootfs_config, + rootfs_config_ptr: *const user_rootfs_config, ) -> Result { let key = if key_ptr.is_null() { None } else { Some(unsafe { key_ptr.read() }) }; - // 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)?; + if !rootfs_config_ptr.is_null() { + from_user::check_ptr(rootfs_config_ptr)?; + let rootfs_config = unsafe { *rootfs_config_ptr }; + let app_config = ConfigApp::from_user(&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)?; } - - Ok(0) + Ok((0)) } pub fn do_fallocate(fd: FileDesc, mode: u32, offset: off_t, len: off_t) -> Result { diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index e857739e..69e17df0 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -20,6 +20,7 @@ use time::{clockid_t, itimerspec_t, timespec_t, timeval_t}; use util::log::{self, LevelFilter}; use util::mem_util::from_user::*; +use crate::config::user_rootfs_config; use crate::exception::do_handle_exception; use crate::fs::{ do_access, do_chdir, do_chmod, do_chown, do_close, do_creat, do_dup, do_dup2, do_dup3, @@ -31,8 +32,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, - user_rootfs_config, utimbuf_t, AsTimer, File, FileDesc, FileRef, HostStdioFds, Stat, Statfs, + do_unlinkat, do_utime, do_utimensat, do_utimes, do_write, do_writev, iovec_t, 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 +426,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, rootfs_config: *const user_rootfs_config), + (MountRootFS = 363) => do_mount_rootfs(key_ptr: *const sgx_key_128bit_t, rootfs_config_ptr: *const user_rootfs_config), } }; }