[libos] Move runtime boot config to config.rs

This commit is contained in:
Zheng, Qi 2023-05-04 16:12:39 +08:00 committed by volcano
parent ac5d385747
commit d4b762ebe5
5 changed files with 172 additions and 166 deletions

@ -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),
}
};
}