[libos] Move runtime boot config to config.rs
This commit is contained in:
		
							parent
							
								
									ac5d385747
								
							
						
					
					
						commit
						d4b762ebe5
					
				| @ -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<InputConfigMount>, | ||||
| } | ||||
| 
 | ||||
| #[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<user_rootfs_config> { | ||||
|         let config = unsafe { *ptr }; | ||||
|         Ok(config) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn to_option_pathbuf(path: *const i8) -> Result<Option<PathBuf>> { | ||||
|     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<ConfigApp> { | ||||
|         // Check config struct length for future possible extension
 | ||||
|         if config.len != size_of::<user_rootfs_config>() { | ||||
|             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) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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}; | ||||
|  | ||||
| @ -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<user_rootfs_config> { | ||||
|         let config = unsafe { *ptr }; | ||||
|         Ok(config) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn to_option_pathbuf(path: *const i8) -> Result<Option<PathBuf>> { | ||||
|     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<ConfigApp> { | ||||
|     // Check config struct length for future possible extension
 | ||||
|     if config.len != size_of::<user_rootfs_config>() { | ||||
|         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) | ||||
| } | ||||
|  | ||||
| @ -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<isize> { | ||||
| 
 | ||||
| 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<isize> { | ||||
|     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<isize> { | ||||
|  | ||||
| @ -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), | ||||
|         } | ||||
|     }; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user