From 572873d9a4d20ba5d9afec49d451c32a64c5ea0a Mon Sep 17 00:00:00 2001 From: LI Qing Date: Thu, 7 May 2020 07:07:42 +0000 Subject: [PATCH] Enable UnionFS --- .gitmodules | 1 + Makefile | 8 +-- README.md | 22 +++++--- deps/sefs | 2 +- etc/template/Occlum.json | 22 +++++--- src/libos/Cargo.lock | 67 +++++++++++++----------- src/libos/Cargo.toml | 1 + src/libos/src/config.rs | 17 +++++- src/libos/src/fs/rootfs.rs | 77 +++++++++++++++++++--------- src/libos/src/lib.rs | 1 + test/Occlum.json | 22 +++++--- test/fs_perms/main.c | 11 ++-- tools/occlum | 8 ++- tools/occlum-gen-default-occlum-json | 26 ++++++---- 14 files changed, 186 insertions(+), 99 deletions(-) diff --git a/.gitmodules b/.gitmodules index 6cc60b7a..fef8932c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,6 +9,7 @@ [submodule "deps/sefs"] path = deps/sefs url = https://github.com/occlum/sefs.git + branch = unionfs [submodule "deps/serde-sgx"] path = deps/serde-sgx url = https://github.com/occlum/serde-sgx diff --git a/Makefile b/Makefile index ad4c9344..ecdbd82a 100644 --- a/Makefile +++ b/Makefile @@ -35,10 +35,10 @@ submodule: githooks @# Enclaves used by tools are running in simulation mode by default to run faster. @rm -rf build build_sim @$(MAKE) SGX_MODE=SIM --no-print-directory -C tools - @$(MAKE) --no-print-directory -C deps/sefs/sefs-fuse clean - @$(MAKE) SGX_MODE=SIM --no-print-directory -C deps/sefs/sefs-fuse - @cp deps/sefs/sefs-fuse/bin/sefs-fuse build/bin - @cp deps/sefs/sefs-fuse/lib/libsefs-fuse.signed.so build/lib + @$(MAKE) --no-print-directory -C deps/sefs/sefs-cli clean + @$(MAKE) SGX_MODE=SIM --no-print-directory -C deps/sefs/sefs-cli + @cp deps/sefs/sefs-cli/bin/sefs-cli build/bin + @cp deps/sefs/sefs-cli/lib/libsefs-cli.signed.so build/lib src: @$(MAKE) --no-print-directory -C src diff --git a/README.md b/README.md index 121c90c5..8e465eb6 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,24 @@ Occlum can be configured easily via a config file named `Occlum.json`, which is "mount": [ { "target": "/", - "type": "sefs", - "source": "./image", + "type": "unionfs", "options": { - "integrity_only": true + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./image", + "options": { + "integrity_only": true + } + }, + { + "target": "/", + "type": "sefs" + } + ] } }, - { - "target": "/root", - "type": "sefs" - }, { "target": "/host", "type": "hostfs", diff --git a/deps/sefs b/deps/sefs index 2420622f..fcb81443 160000 --- a/deps/sefs +++ b/deps/sefs @@ -1 +1 @@ -Subproject commit 2420622f050efda627ccebcff6e86a71dcf405f5 +Subproject commit fcb81443be49344e26fc1017534f1a6eec397d49 diff --git a/etc/template/Occlum.json b/etc/template/Occlum.json index d62a8d39..c22a2a66 100644 --- a/etc/template/Occlum.json +++ b/etc/template/Occlum.json @@ -29,16 +29,24 @@ "mount": [ { "target": "/", - "type": "sefs", - "source": "./image", + "type": "unionfs", "options": { - "integrity_only": true + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./image", + "options": { + "integrity_only": true + } + }, + { + "target": "/", + "type": "sefs" + } + ] } }, - { - "target": "/root", - "type": "sefs" - }, { "target": "/host", "type": "hostfs", diff --git a/src/libos/Cargo.lock b/src/libos/Cargo.lock index 804c8fde..4c83c311 100644 --- a/src/libos/Cargo.lock +++ b/src/libos/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "rcore-fs-mountfs", "rcore-fs-ramfs", "rcore-fs-sefs", + "rcore-fs-unionfs", "ringbuf", "serde", "serde_json", @@ -54,9 +55,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.52" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" +checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" [[package]] name = "cfg-if" @@ -141,9 +142,9 @@ checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" [[package]] name = "fnv" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fuchsia-cprng" @@ -182,15 +183,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" +checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -206,11 +207,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.12" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ - "unicode-xid 0.2.0", + "unicode-xid 0.2.1", ] [[package]] @@ -224,11 +225,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.4" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.12", + "proc-macro2 1.0.19", ] [[package]] @@ -354,7 +355,6 @@ dependencies = [ name = "rcore-fs-mountfs" version = "0.1.0" dependencies = [ - "lazy_static", "log", "rcore-fs", "spin", @@ -381,6 +381,15 @@ dependencies = [ "uuid", ] +[[package]] +name = "rcore-fs-unionfs" +version = "0.1.0" +dependencies = [ + "log", + "rcore-fs", + "spin", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -399,9 +408,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" @@ -415,9 +424,9 @@ dependencies = [ name = "serde_derive" version = "1.0.104" dependencies = [ - "proc-macro2 1.0.12", - "quote 1.0.4", - "syn 1.0.19", + "proc-macro2 1.0.19", + "quote 1.0.7", + "syn 1.0.34", ] [[package]] @@ -545,13 +554,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.19" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7" +checksum = "936cae2873c940d92e697597c5eee105fb570cd5689c695806f672883653349b" dependencies = [ - "proc-macro2 1.0.12", - "quote 1.0.4", - "unicode-xid 0.2.0", + "proc-macro2 1.0.19", + "quote 1.0.7", + "unicode-xid 0.2.1", ] [[package]] @@ -562,9 +571,9 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "uuid" @@ -577,9 +586,9 @@ dependencies = [ [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index e67702fc..516aa6a4 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -18,6 +18,7 @@ rcore-fs = { path = "../../deps/sefs/rcore-fs" } rcore-fs-sefs = { path = "../../deps/sefs/rcore-fs-sefs" } rcore-fs-ramfs = { path = "../../deps/sefs/rcore-fs-ramfs" } rcore-fs-mountfs = { path = "../../deps/sefs/rcore-fs-mountfs" } +rcore-fs-unionfs = { path = "../../deps/sefs/rcore-fs-unionfs" } serde = { path = "../../deps/serde-sgx/serde", features = ["derive"] } serde_json = { path = "../../deps/serde-json-sgx" } diff --git a/src/libos/src/config.rs b/src/libos/src/config.rs index 6940e770..83ecd9b4 100644 --- a/src/libos/src/config.rs +++ b/src/libos/src/config.rs @@ -123,12 +123,14 @@ pub enum ConfigMountFsType { TYPE_SEFS, TYPE_HOSTFS, TYPE_RAMFS, + TYPE_UNIONFS, } #[derive(Debug)] pub struct ConfigMountOptions { pub integrity_only: bool, pub mac: Option, + pub layers: Option>, } impl Config { @@ -195,12 +197,13 @@ impl ConfigEnv { impl ConfigMount { fn from_input(input: &InputConfigMount) -> Result { - const ALL_FS_TYPES: [&str; 3] = ["sefs", "hostfs", "ramfs"]; + const ALL_FS_TYPES: [&str; 4] = ["sefs", "hostfs", "ramfs", "unionfs"]; let type_ = match input.type_.as_str() { "sefs" => ConfigMountFsType::TYPE_SEFS, "hostfs" => ConfigMountFsType::TYPE_HOSTFS, "ramfs" => ConfigMountFsType::TYPE_RAMFS, + "unionfs" => ConfigMountFsType::TYPE_UNIONFS, _ => { return_errno!(EINVAL, "Unsupported file system type"); } @@ -233,9 +236,19 @@ impl ConfigMountOptions { } (true, Some(parse_mac(&input.mac.as_ref().unwrap())?)) }; + let layers = if let Some(layers) = &input.layers { + let layers = layers + .iter() + .map(|config| ConfigMount::from_input(config).expect("invalid mount config")) + .collect(); + Some(layers) + } else { + None + }; Ok(ConfigMountOptions { integrity_only, mac, + layers, }) } } @@ -370,4 +383,6 @@ struct InputConfigMountOptions { #[serde(rename = "MAC")] #[serde(default)] pub mac: Option, + #[serde(default)] + pub layers: Option>, } diff --git a/src/libos/src/fs/rootfs.rs b/src/libos/src/fs/rootfs.rs index 1cc6bcdc..0da56a99 100644 --- a/src/libos/src/fs/rootfs.rs +++ b/src/libos/src/fs/rootfs.rs @@ -8,6 +8,7 @@ use rcore_fs_mountfs::{MNode, MountFS}; use rcore_fs_ramfs::RamFS; use rcore_fs_sefs::dev::*; use rcore_fs_sefs::SEFS; +use rcore_fs_unionfs::UnionFS; lazy_static! { /// The root of file system @@ -29,38 +30,61 @@ lazy_static! { }; } -fn open_root_fs_according_to(mount_config: &Vec) -> Result> { - let (root_sefs_mac, root_sefs_source) = { - let root_mount_config = mount_config +fn open_root_fs_according_to(mount_configs: &Vec) -> Result> { + let mount_config = mount_configs + .iter() + .find(|m| m.target == Path::new("/") && m.type_ == ConfigMountFsType::TYPE_UNIONFS) + .ok_or_else(|| errno!(Errno::ENOENT, "the root UnionFS is not valid"))?; + if mount_config.options.layers.is_none() { + return_errno!(EINVAL, "The root UnionFS must be given the layers"); + } + let layer_mount_configs = mount_config.options.layers.as_ref().unwrap(); + // image SEFS in layers + let (root_image_sefs_mac, root_image_sefs_source) = { + let mount_config = layer_mount_configs .iter() - .find(|m| m.target == Path::new("/")) - .ok_or_else(|| errno!(Errno::ENOENT, "the mount point at / is not specified"))?; - - if root_mount_config.type_ != ConfigMountFsType::TYPE_SEFS { - return_errno!(EINVAL, "The mount point at / must be SEFS"); - } - if !root_mount_config.options.integrity_only { - return_errno!(EINVAL, "The root SEFS at / must be integrity-only"); - } - if root_mount_config.source.is_none() { - return_errno!( - EINVAL, - "The root SEFS must be given a source path (on host)" - ); - } + .find(|m| m.type_ == ConfigMountFsType::TYPE_SEFS && m.options.integrity_only) + .ok_or_else(|| errno!(Errno::ENOENT, "the image SEFS in layers is not valid"))?; ( - root_mount_config.options.mac, - root_mount_config.source.as_ref().unwrap(), + mount_config.options.mac, + mount_config.source.as_ref().unwrap(), ) }; - - let root_sefs = SEFS::open( - Box::new(SgxStorage::new(root_sefs_source, true, root_sefs_mac)), + let root_image_sefs = SEFS::open( + Box::new(SgxStorage::new( + root_image_sefs_source, + true, + root_image_sefs_mac, + )), &time::OcclumTimeProvider, &SgxUuidProvider, )?; - let root_mountable_sefs = MountFS::new(root_sefs); - Ok(root_mountable_sefs) + // container SEFS in layers + let root_container_sefs_source = { + let mount_config = layer_mount_configs + .iter() + .find(|m| m.type_ == ConfigMountFsType::TYPE_SEFS && !m.options.integrity_only) + .ok_or_else(|| errno!(Errno::ENOENT, "the container SEFS in layers is not valid"))?; + mount_config.source.as_ref().unwrap() + }; + let root_container_sefs = { + SEFS::open( + Box::new(SgxStorage::new(root_container_sefs_source, false, None)), + &time::OcclumTimeProvider, + &SgxUuidProvider, + ) + } + .or_else(|_| { + SEFS::create( + Box::new(SgxStorage::new(root_container_sefs_source, false, None)), + &time::OcclumTimeProvider, + &SgxUuidProvider, + ) + })?; + + let root_unionfs = UnionFS::new(vec![root_container_sefs, root_image_sefs])?; + let root_mountable_unionfs = MountFS::new(root_unionfs); + Ok(root_mountable_unionfs) } fn mount_nonroot_fs_according_to(mount_config: &Vec, root: &MNode) -> Result<()> { @@ -116,6 +140,9 @@ fn mount_nonroot_fs_according_to(mount_config: &Vec, root: &MNode) let ramfs = RamFS::new(); mount_fs_at(ramfs, &root, target_dirname)?; } + TYPE_UNIONFS => { + return_errno!(EINVAL, "Cannot mount UnionFS at non-root path"); + } } } Ok(()) diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index 3a1f3eab..c058524a 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -39,6 +39,7 @@ extern crate rcore_fs; extern crate rcore_fs_mountfs; extern crate rcore_fs_ramfs; extern crate rcore_fs_sefs; +extern crate rcore_fs_unionfs; #[macro_use] extern crate derive_builder; extern crate ringbuf; diff --git a/test/Occlum.json b/test/Occlum.json index f6b9a77b..46f24d65 100644 --- a/test/Occlum.json +++ b/test/Occlum.json @@ -32,16 +32,24 @@ "mount": [ { "target": "/", - "type": "sefs", - "source": "./image", + "type": "unionfs", "options": { - "integrity_only": true + "layers": [ + { + "target": "/", + "type": "sefs", + "source": "./image", + "options": { + "integrity_only": true + } + }, + { + "target": "/", + "type": "sefs" + } + ] } }, - { - "target": "/root", - "type": "sefs" - }, { "target": "/host", "type": "hostfs", diff --git a/test/fs_perms/main.c b/test/fs_perms/main.c index ca83af30..16504fd4 100644 --- a/test/fs_perms/main.c +++ b/test/fs_perms/main.c @@ -75,6 +75,9 @@ static int do_perm_tests( int expected_result = expected_results[i]; int fd = open_file(filename, flags, 0666); + if (fd < 0 && fd != expected_result) { + return -1; + } int result = do_write ? write_file(fd) : read_file(fd); if (result != expected_result) { return -1; @@ -101,15 +104,15 @@ static int test_expected_results[NUM_TEST_CASES][NUM_TEST_FILES] = { // test_open_ro_then_write() {NG, NG, NG, NG, NG}, // test_open_wo_then_write() - {NG, NG, NG, OK, OK}, + {OK, OK, OK, OK, OK}, // test_open_rw_then_write() - {NG, NG, NG, OK, OK}, + {OK, OK, OK, OK, OK}, // test_open_ro_then_read() - {NG, NG, NG, OK, OK}, + {OK, OK, OK, OK, OK}, // test_open_wo_then_read() {NG, NG, NG, NG, NG}, // test_open_rw_then_read() - {NG, NG, NG, OK, OK}, + {OK, OK, OK, OK, OK}, }; int test_open_ro_then_write() { diff --git a/tools/occlum b/tools/occlum index 89e329fb..303799fc 100755 --- a/tools/occlum +++ b/tools/occlum @@ -106,7 +106,7 @@ check_has_init() { check_has_built() { check_has_init - if [ ! -d "$context_dir/run/mount/root" ]; then + if [ ! -d "$context_dir/run/mount/__ROOT" ]; then echo "Error: the Occlum image and enclave are not built yet. Need to run \"occlum build\" first." exit 1 fi @@ -187,11 +187,9 @@ cmd_build() { cd build/lib && ln -sf "$pal_lib.$occlum_version" "libocclum-pal.so.$major_ver" && \ ln -sf "libocclum-pal.so.$major_ver" libocclum-pal.so && cd - - chmod 531 -R $working_dir/image/bin - chmod 531 -R $working_dir/image/lib mkdir -p build/mount/ cd "$occlum_dir/$build_dir/bin/" && \ - LD_LIBRARY_PATH="$SGX_SDK/sdk_libs" ./sefs-fuse \ + LD_LIBRARY_PATH="$SGX_SDK/sdk_libs" ./sefs-cli \ --integrity-only \ "$context_dir/build/mount/__ROOT" \ "$working_dir/image" \ @@ -237,7 +235,7 @@ cmd_build() { echo "HW" > .sgx_mode fi - mkdir -p "$context_dir/run/mount/root" + mkdir -p "$context_dir/run/mount/__ROOT" ln -s $occlum_dir/$build_dir/bin/occlum_exec_client $context_dir/build/bin/occlum_exec_client ln -s $occlum_dir/$build_dir/bin/occlum_exec_server $context_dir/build/bin/occlum_exec_server diff --git a/tools/occlum-gen-default-occlum-json b/tools/occlum-gen-default-occlum-json index 0aa0497a..d5f172df 100755 --- a/tools/occlum-gen-default-occlum-json +++ b/tools/occlum-gen-default-occlum-json @@ -17,18 +17,26 @@ cat <