[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