Combine two config json files as one

This commit is contained in:
Zheng, Qi 2022-05-17 09:32:09 +08:00 committed by volcano
parent 0fef286df2
commit 2347951743
14 changed files with 421 additions and 260 deletions

@ -39,14 +39,6 @@ fn main() -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
// 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<dyn Error>> {
#[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,
}

@ -62,14 +62,6 @@
"target": "/host",
"type": "hostfs",
"source": "."
},
{
"target": "/proc",
"type": "procfs"
},
{
"target": "/dev",
"type": "devfs"
}
]
}

@ -29,14 +29,6 @@ fn main() -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
// 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<dyn Error>> {
#[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,
}

@ -94,8 +94,7 @@ pub struct Config {
pub resource_limits: ConfigResourceLimits,
pub process: ConfigProcess,
pub env: ConfigEnv,
pub entry_points: Vec<PathBuf>,
pub mount: Vec<ConfigMount>,
pub app: Vec<ConfigApp>,
}
#[derive(Debug)]
@ -116,7 +115,7 @@ pub struct ConfigEnv {
pub untrusted: HashSet<String>,
}
#[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<PathBuf>,
pub stage: String,
pub mount: Vec<ConfigMount>,
}
#[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<sgx_aes_gcm_128bit_tag_t>,
pub layers: Option<Vec<ConfigMount>>,
pub temporary: bool,
pub cache_size: Option<u64>,
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")
let app = {
let mut app = Vec::new();
for input_app in &input.app {
app.push(ConfigApp::from_input(&input_app)?);
}
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
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<ConfigApp> {
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<ConfigMount> {
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<String>,
#[serde(default)]
pub mount: Vec<InputConfigMount>,
pub app: Vec<InputConfigApp>,
}
#[derive(Deserialize, Debug)]
@ -415,4 +451,17 @@ struct InputConfigMountOptions {
pub temporary: bool,
#[serde(default)]
pub cache_size: Option<String>,
#[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<String>,
#[serde(default)]
pub mount: Vec<InputConfigMount>,
}

@ -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<Vec<PathBuf>> =
RwLock::new(config::LIBOS_CONFIG.entry_points.clone());
pub static ref ENTRY_POINTS: RwLock<Vec<PathBuf>> = RwLock::new(
config::LIBOS_CONFIG
.get_app_config("init")
.unwrap()
.entry_points
.clone()
);
pub static ref RESOLV_CONF_STR: RwLock<Option<String>> = RwLock::new(None);
pub static ref HOSTNAME_STR: RwLock<Option<String>> = RwLock::new(None);
pub static ref HOSTS_STR: RwLock<Option<String>> = RwLock::new(None);

@ -13,7 +13,7 @@ lazy_static! {
}
pub fn do_mount_rootfs(
user_config: &config::Config,
user_app_config: &config::ConfigApp,
user_key: &Option<sgx_key_128bit_t>,
) -> 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

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

@ -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<Arc<dyn FileSystem>> = {
fn init_root_fs() -> Result<Arc<dyn FileSystem>> {
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<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)
}
pub fn gen_config_app(config: &user_rootfs_config) -> Result<ConfigApp> {
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)
}

@ -660,20 +660,26 @@ 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,
occlum_json_mac_ptr: *const sgx_aes_gcm_128bit_tag_t,
rootfs_config: *const user_rootfs_config,
) -> Result<isize> {
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)
}

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

@ -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,38 +362,19 @@ 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<OcclumMount>,
occlum_conf_user_fs_mac: String,
) -> Result<Vec<OcclumMount>, &'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()
.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);
debug!("user Occlum.json mount config:\n{:?}", user_mount_config);
Ok(user_mount_config)
}
fn gen_sys_mount_config(occlum_conf_init_fs_mac: String) -> serde_json::Value {
let mut init_fs_mount_config: serde_json::Value = json!({
occlum_conf_init_fs_mac: String,
) -> Result<serde_json::Value, &'static str> {
let mut app_config: serde_json::Value = json!({
"app": [
{
"stage": "init",
"entry_points": [
"/bin"
],
"mount": [
{
"target": "/",
@ -465,15 +406,107 @@ fn gen_sys_mount_config(occlum_conf_init_fs_mac: String) -> serde_json::Value {
"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"
}
]
}]
});
*init_fs_mount_config
.pointer_mut("/mount/0/options/layers/0/options/MAC")
// 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);
debug!("initfs mount config:\n{:?}", init_fs_mount_config);
// Update app entry points
*app_config
.pointer_mut("/app/1/entry_points")
.unwrap() = entry_points;
init_fs_mount_config["mount"].to_owned()
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("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")?;
// Update app root mount
*app_config
.pointer_mut("/app/1/mount/0")
.unwrap() = serde_json::to_value(root_mc).unwrap();
}
// 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);
// 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!("Occlum.json mount config:\n{:?}", app_config);
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,
}

@ -14,14 +14,6 @@ fn main() -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
// 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<dyn Error>> {
#[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,
}

@ -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 \
"

@ -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)/. ),)