diff --git a/.github/workflows/composite_action/prebuild/action.yml b/.github/workflows/composite_action/prebuild/action.yml index 0c525352..20c5fc24 100644 --- a/.github/workflows/composite_action/prebuild/action.yml +++ b/.github/workflows/composite_action/prebuild/action.yml @@ -12,7 +12,9 @@ runs: run: | docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum"; docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/grpc-rust"; + docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/ext2-rs"; docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/itoa-sgx"; + docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/mlsdisk"; docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/resolv-conf"; docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/ringbuf"; docker exec ${{ inputs.container-name }} bash -c "git config --global --add safe.directory /root/occlum/deps/rust-sgx-sdk"; diff --git a/.gitmodules b/.gitmodules index 647774e5..309d0a20 100644 --- a/.gitmodules +++ b/.gitmodules @@ -27,3 +27,9 @@ [submodule "deps/io-uring"] path = deps/io-uring url = https://github.com/occlum/io-uring.git +[submodule "deps/mlsdisk"] + path = deps/mlsdisk + url = https://github.com/asterinas/mlsdisk +[submodule "deps/ext2-rs"] + path = deps/ext2-rs + url = https://github.com/liqinggd/ext2-rs diff --git a/Makefile b/Makefile index 2ea5c417..840cf6fa 100644 --- a/Makefile +++ b/Makefile @@ -71,6 +71,7 @@ init-submodule: cd deps/serde-json-sgx && git apply ../serde-json-sgx.patch >/dev/null 2>&1 || git apply ../serde-json-sgx.patch -R --check cd deps/ringbuf && git apply ../ringbuf.patch >/dev/null 2>&1 || git apply ../ringbuf.patch -R --check cd deps/resolv-conf && git apply ../resolv-conf.patch >/dev/null 2>&1 || git apply ../resolv-conf.patch -R --check + cd deps/mlsdisk && git apply ../mlsdisk.patch >/dev/null 2>&1 || git apply ../mlsdisk.patch -R --check src: @$(MAKE) --no-print-directory -C src diff --git a/deps/ext2-rs b/deps/ext2-rs new file mode 160000 index 00000000..e78615a8 --- /dev/null +++ b/deps/ext2-rs @@ -0,0 +1 @@ +Subproject commit e78615a899adeb7b6bef5811eb9244cc73680407 diff --git a/deps/mlsdisk b/deps/mlsdisk new file mode 160000 index 00000000..864a0084 --- /dev/null +++ b/deps/mlsdisk @@ -0,0 +1 @@ +Subproject commit 864a00840110237d60d51e04d0e63394c812549a diff --git a/deps/mlsdisk.patch b/deps/mlsdisk.patch new file mode 100644 index 00000000..7f1bf49f --- /dev/null +++ b/deps/mlsdisk.patch @@ -0,0 +1,28 @@ +diff --git a/core/Cargo.toml b/core/Cargo.toml +index c1e1746..20b896f 100644 +--- a/core/Cargo.toml ++++ b/core/Cargo.toml +@@ -22,16 +22,18 @@ serde = { version = "=1.0.188", default-features = false, features = ["alloc", " + spin = { version = "0.9.8", optional = true } + static_assertions = "1.1.0" + +-sgx_tstd = { git = "https://github.com/apache/teaclave-sgx-sdk.git", features = ["backtrace", "thread"], optional = true } +-sgx_rand = { git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true } +-sgx_tcrypto = { git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true } +-sgx_types = { git = "https://github.com/apache/teaclave-sgx-sdk.git", optional = true } ++sgx_tstd = { path = "../../../deps/rust-sgx-sdk/sgx_tstd", features = ["backtrace", "thread"], optional = true } ++sgx_rand = { path = "../../../deps/rust-sgx-sdk/sgx_rand", optional = true } ++sgx_tcrypto = { path = "../../../deps/rust-sgx-sdk/sgx_tcrypto", optional = true } ++sgx_types = { path = "../../../deps/rust-sgx-sdk/sgx_types", optional = true } ++ext2-rs = { path = "../../../deps/ext2-rs", default-features = false, optional = true } ++ahash = { version="=0.8.6", default-features = false } + + [features] + default = ["std"] + std = ["spin", "openssl", "log"] + linux = ["bindings"] +-occlum = ["sgx_tstd", "sgx_rand", "sgx_tcrypto", "sgx_types", "spin", "log"] ++occlum = ["sgx_tstd", "sgx_rand", "sgx_tcrypto", "sgx_types", "spin", "log", "ext2-rs/sgx"] + jinux = [] + + diff --git a/docs/readthedocs/docs/source/filesystem/fs_overview.md b/docs/readthedocs/docs/source/filesystem/fs_overview.md index dc1cb915..33a22460 100644 --- a/docs/readthedocs/docs/source/filesystem/fs_overview.md +++ b/docs/readthedocs/docs/source/filesystem/fs_overview.md @@ -1,6 +1,6 @@ # Occlum File System Overview -Occlum supports various file systems: e.g., read-only integrity-protected SEFS, writable encrypted SEFS, UnionFS, Async-SFS, untrusted HostFS, RamFS, and other pseudo filesystems. +Occlum supports various file systems: e.g., read-only integrity-protected SEFS, writable encrypted SEFS, UnionFS, Ext2, untrusted HostFS, RamFS, and other pseudo filesystems. Here is the default FS layout: @@ -16,12 +16,12 @@ Here is the default FS layout: │ │ └──────┬──────┘ │ - ┌────────┬────┴─────┬────────┐ - │ │ │ │ - │"/sfs" │"/dev/shm"│"/proc" │"/dev" -┌───┴─┐ ┌──┴──┐ ┌───┴──┐ ┌──┴──┐ -│A-SFS│ │RamFS│ │ProcFS│ │DevFS│ -└─────┘ └─────┘ └──────┘ └─────┘ + ┌──────────┬───┴─────┬───────┐ + │ │ │ │ + │"/dev/shm"│"/proc" │"/dev" │"/ext2"(optional) +┌──┴──┐ ┌───┴──┐ ┌──┴──┐ ┌─┴──┐ +│RamFS│ │ProcFS│ │DevFS│ │Ext2│ +└─────┘ └──────┘ └─────┘ └────┘ ``` ## SEFS @@ -103,33 +103,19 @@ Here is the configuration of rootfs, the first item is the lower layer RO-SEFS a source: ./run/mount/__ROOT ``` -## Async-SFS -The Async-SFS is an asynchronous filesystem, which uses Rust asynchronous programming skills, making it fast and concurrent. It is mounted at `/sfs` by default. To achieve the high-performanced security, it uses the JinDisk as the underlying data storage and sends async I/O requests to it. +## Ext2 +The [Ext2](https://github.com/liqinggd/ext2-rs) is an independent filesystem Rust crate that resembles Linux's Ext2. For the sake of performance and security, it utilizes [SwornDisk](https://github.com/asterinas/mlsdisk) as its underlying block device. Compared with SEFS, the file I/O performance of "Ext2+SwornDisk" is superior. If your App's performance is highly dependent on file I/O, it is recommended to enable Ext2 in Occlum.json. -To accelerate block I/O, the page cache is introduced. It caches all the block I/O in the middle of Async-SFS and JinDisk. Thanks to the page cache and JinDisk, the result of the benchmark (e.g., FIO and Filebench) is significantly better than SEFS. If your App's performance is highly dependent on disk I/O, it is recommended to use Async-SFS. ``` -┌───────────┐ -│ │ -│ Async-SFS │ -│ │ -└─────┬─────┘ - │ -┌─────┴─────┐ -│ │ -│ Page Cache│ -│ │ -└─────┬─────┘ - │ -┌─────┴─────┐ -│ │ -│ JinDisk │ -│ │ -└───────────┘ + "mount": [{ + "target": "/ext2", + "type": "ext2", + "options": { + "disk_size": "10GB" + } + }] ``` - -Currently, there are some limitations of Async-SFS: -1. The maximum size of the file is 4GB. -2. The maximum size of FS is 16TB. +The configuration of enabling Ext2 is showed above, you can specify your mount point at `target`, the disk size that Ext2 manages should be specified at `options.disk_size`. ## HostFS The HostFS is used for convenient data exchange between the LibOS and the host OS. It simply wraps the untrusted host OS file to implement the functionalities of FS. So the data is straightforwardly transferred between LibOS and host OS without any protection or validation. diff --git a/docs/readthedocs/docs/source/occlum_configuration.md b/docs/readthedocs/docs/source/occlum_configuration.md index 08df4c3f..46a6fa82 100644 --- a/docs/readthedocs/docs/source/occlum_configuration.md +++ b/docs/readthedocs/docs/source/occlum_configuration.md @@ -147,6 +147,13 @@ The template of `Occlum.json` is shown below. { "target": "/dev", "type": "devfs" + }, + { + "target": "/ext2", + "type": "ext2", + "options": { + "disk_size": "10GB" + } } ] } diff --git a/docs/readthedocs/docs/source/tutorials/gen_occlum_instance.md b/docs/readthedocs/docs/source/tutorials/gen_occlum_instance.md index 02c22523..30b86f11 100644 --- a/docs/readthedocs/docs/source/tutorials/gen_occlum_instance.md +++ b/docs/readthedocs/docs/source/tutorials/gen_occlum_instance.md @@ -15,7 +15,7 @@ For every application to be running in Occlum (TEE env), all the running require | |-- opt | |-- proc | |-- root -| |-- sfs +| |-- sbin | |-- sys | `-- tmp |-- initfs // Occlum init file system diff --git a/etc/template/base.yaml b/etc/template/base.yaml index 7406d84b..ae915bd4 100644 --- a/etc/template/base.yaml +++ b/etc/template/base.yaml @@ -13,3 +13,5 @@ targets: - root - sys - tmp + - sbin + - ext2 diff --git a/src/Enclave.edl b/src/Enclave.edl index f8c77bf4..0e6b5fe8 100644 --- a/src/Enclave.edl +++ b/src/Enclave.edl @@ -4,6 +4,7 @@ enclave { from "sgx_tstdc.edl" import *; from "sgx_tstd.edl" import *; from "sgx_tprotected_fs.edl" import *; + from "sgx_thread.edl" import *; from "sgx_net.edl" import *; from "sgx_occlum_utils.edl" import *; from "sgx_vdso_time_ocalls.edl" import *; diff --git a/src/libos/Cargo.lock b/src/libos/Cargo.lock index 8533a22e..8305bd4a 100644 --- a/src/libos/Cargo.lock +++ b/src/libos/Cargo.lock @@ -15,6 +15,7 @@ dependencies = [ "derive_builder", "downcast-rs", "errno", + "ext2-rs", "goblin", "intrusive-collections", "io-uring-callback", @@ -35,7 +36,7 @@ dependencies = [ "resolv-conf", "ringbuf", "scroll", - "serde", + "serde 1.0.104", "serde_json", "sgx-untrusted-alloc", "sgx_cov", @@ -45,9 +46,22 @@ dependencies = [ "sgx_tstd", "sgx_types", "spin 0.7.1", + "sworndisk-v2", "vdso-time", ] +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aligned" version = "0.4.1" @@ -57,6 +71,26 @@ dependencies = [ "as-slice", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "anymap" +version = "1.0.0-beta.2" +source = "git+https://github.com/lucassong-mh/anymap?branch=1.0.0-beta.2-patched#18f6555cf93ee5609b883feb6d1ec46ca14f2a78" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + [[package]] name = "as-slice" version = "0.2.1" @@ -75,6 +109,15 @@ dependencies = [ "autocfg 1.1.0", ] +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + [[package]] name = "autocfg" version = "0.1.8" @@ -96,6 +139,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bittle" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14173f083171cee3f00fbbfa3d3d2492401c25c015874aad543bbf829d6389f8" + [[package]] name = "bitvec" version = "0.17.4" @@ -145,6 +194,33 @@ dependencies = [ "bitflags", ] +[[package]] +name = "cobs" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + [[package]] name = "ctor" version = "0.1.23" @@ -152,7 +228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdffe87e1d521a10f9696f833fe502293ea446d7f256c06128293a4119bdf4cb" dependencies = [ "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -161,8 +237,18 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.10.2", + "darling_macro 0.10.2", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", ] [[package]] @@ -175,8 +261,22 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", - "syn", + "strsim 0.9.3", + "syn 1.0.99", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.99", ] [[package]] @@ -185,9 +285,20 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ - "darling_core", + "darling_core 0.10.2", "quote", - "syn", + "syn 1.0.99", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.99", ] [[package]] @@ -196,11 +307,11 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0" dependencies = [ - "darling", + "darling 0.10.2", "derive_builder_core", "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -209,10 +320,10 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" dependencies = [ - "darling", + "darling 0.10.2", "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] [[package]] @@ -237,6 +348,55 @@ dependencies = [ "sgx_tstd", ] +[[package]] +name = "ext-trait" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5" +dependencies = [ + "ext-trait-proc_macros", +] + +[[package]] +name = "ext-trait-proc_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.99", +] + +[[package]] +name = "ext2-rs" +version = "0.1.0" +dependencies = [ + "bitflags", + "bitvec 1.0.1", + "cfg-if", + "inherit-methods-macro", + "log", + "lru", + "pod", + "rcore-fs", + "sgx_libc", + "sgx_trts", + "sgx_tstd", + "sgx_types", + "spin 0.9.8", + "static_assertions 1.1.0", +] + +[[package]] +name = "extension-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537" +dependencies = [ + "ext-trait", +] + [[package]] name = "fnv" version = "1.0.7" @@ -327,16 +487,61 @@ dependencies = [ "scroll", ] +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +dependencies = [ + "ahash", + "allocator-api2", + "serde 1.0.188", +] + [[package]] name = "hashbrown_tstd" version = "0.12.0" +[[package]] +name = "heapless" +version = "0.7.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" +dependencies = [ + "atomic-polyfill", + "hash32", + "rustc_version", + "serde 1.0.188", + "spin 0.9.8", + "stable_deref_trait", +] + [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "inherit-methods-macro" +version = "0.1.0" +source = "git+https://github.com/asterinas/inherit-methods-macro?rev=98f7e3e#98f7e3eb9efdac98faf5a7076f154f30894b9b02" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.99", +] + [[package]] name = "intrusive-collections" version = "0.9.4" @@ -406,10 +611,35 @@ dependencies = [ ] [[package]] -name = "libc" -version = "0.2.132" +name = "lending-iterator" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +checksum = "bc07588c853b50689205fb5c00498aa681d89828e0ce8cbd965ebc7a5d8ae260" +dependencies = [ + "extension-traits", + "lending-iterator-proc_macros", + "macro_rules_attribute", + "never-say-never", + "nougat", + "polonius-the-crab", +] + +[[package]] +name = "lending-iterator-proc_macros" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5445dd1c0deb1e97b8a16561d17fc686ca83e8411128fb036e9668a72d51b1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.99", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "lock_api" @@ -429,6 +659,31 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "macro_rules_attribute" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d" + [[package]] name = "memoffset" version = "0.5.6" @@ -465,7 +720,34 @@ checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", +] + +[[package]] +name = "never-say-never" +version = "6.6.666" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6" + +[[package]] +name = "nougat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b57b9ced431322f054fc673f1d3c7fa52d80efd9df74ad2fc759f044742510" +dependencies = [ + "macro_rules_attribute", + "nougat-proc_macros", +] + +[[package]] +name = "nougat-proc_macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c84f77a45e99a2f9b492695d99e1c23844619caa5f3e57647cffacad773ca257" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.99", ] [[package]] @@ -485,9 +767,21 @@ checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -507,10 +801,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] -name = "proc-macro2" -version = "1.0.43" +name = "pod" +version = "0.1.0" +source = "git+https://github.com/asterinas/pod?rev=d7dba56#d7dba56cc202a10d483b60aba4f734b1f49cb37b" +dependencies = [ + "pod-derive", +] + +[[package]] +name = "pod-derive" +version = "0.1.0" +source = "git+https://github.com/asterinas/pod?rev=d7dba56#d7dba56cc202a10d483b60aba4f734b1f49cb37b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.99", +] + +[[package]] +name = "polonius-the-crab" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" +checksum = "c2a69ee997a6282f8462abf1e0d8c38c965e968799e912b3bed8c9e8a28c2f9f" + +[[package]] +name = "postcard" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ee729232311d3cd113749948b689627618133b1c5012b77342c1950b25eaeb" +dependencies = [ + "cobs", + "heapless", + "serde 1.0.188", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -527,9 +856,9 @@ source = "git+https://github.com/mesalock-linux/quick-error-sgx.git#468bf2cce746 [[package]] name = "quote" -version = "1.0.21" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -749,6 +1078,15 @@ dependencies = [ "sgx_tstd", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.11" @@ -778,24 +1116,50 @@ checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.104" dependencies = [ - "serde_derive", + "serde_derive 1.0.104", "sgx_tstd", ] +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive 1.0.188", +] + [[package]] name = "serde_derive" version = "1.0.104" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.99", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -804,7 +1168,7 @@ version = "1.0.40" dependencies = [ "itoa", "ryu", - "serde", + "serde 1.0.104", "sgx_tstd", ] @@ -951,6 +1315,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13287b4da9d1207a4f4929ac390916d64eacfe236a487e9a9f5b3be392be5162" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -975,6 +1348,38 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "sworndisk-v2" +version = "0.1.0" +dependencies = [ + "ahash", + "anymap", + "array-init", + "bittle", + "crossbeam-queue", + "ext2-rs", + "hashbrown", + "inherit-methods-macro", + "lending-iterator", + "log", + "lru", + "pod", + "postcard", + "serde 1.0.188", + "sgx_rand", + "sgx_tcrypto", + "sgx_tstd", + "sgx_types", + "spin 0.9.8", + "static_assertions 1.1.0", +] + [[package]] name = "syn" version = "1.0.99" @@ -986,6 +1391,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -1021,6 +1437,12 @@ dependencies = [ "sgx_types", ] +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "winapi" version = "0.3.9" @@ -1051,3 +1473,23 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] diff --git a/src/libos/Cargo.toml b/src/libos/Cargo.toml index 4f964eeb..89d6d8e6 100644 --- a/src/libos/Cargo.toml +++ b/src/libos/Cargo.toml @@ -35,6 +35,8 @@ regex = { git = "https://github.com/mesalock-linux/regex-sgx", default-features goblin = { version = "0.5.4", default-features = false, features = ["elf64", "elf32", "endian_fd"] } intrusive-collections = "0.9" modular-bitfield = "0.11.2" +sworndisk-v2 = { path = "../../deps/mlsdisk/core", default-features = false, features = ["occlum"] } +ext2-rs = { path = "../../deps/ext2-rs", default-features = false, features = ["sgx"] } sgx-untrusted-alloc = { path = "./crates/sgx-untrusted-alloc", features = ["sgx"]} io-uring-callback = { path = "./crates/io-uring-callback", features = ["sgx"]} diff --git a/src/libos/src/blk/dev_disk.rs b/src/libos/src/blk/dev_disk.rs new file mode 100644 index 00000000..cd642e5d --- /dev/null +++ b/src/libos/src/blk/dev_disk.rs @@ -0,0 +1,182 @@ +//! Block device wrapper, currently used for the DevFS. +use super::{BlockDevice, BlockDeviceExt, RawDisk, GB}; +use crate::fs::*; +use crate::prelude::*; +use crate::util::sgx::get_autokey; + +use core::any::Any; +use rcore_fs::vfs::{self, FileType, INode, Metadata, Timespec}; +use std::path::PathBuf; +use sworndisk_v2::{AeadKey, SwornDisk, BLOCK_SIZE}; + +lazy_static! { + pub static ref SWORNDISK: RwLock>>> = { RwLock::new(None) }; + pub static ref SWORNDISK_METADATA: RwLock = + { RwLock::new(SwornDiskMeta::default()) }; +} + +pub const DEV_SWORNDISK: &str = "sworndisk"; + +/// Block device wrapper. +pub struct DevDisk { + disk: Arc, +} + +impl DevDisk { + pub fn open_or_create(name: &str) -> Result { + let disk: Arc = match name { + // Currently only support SwornDisk + DEV_SWORNDISK => { + let mut sworndisk_opt = SWORNDISK.write().unwrap(); + if let Some(sworndisk) = sworndisk_opt.as_ref() { + sworndisk.clone() + } else { + let metadata = SWORNDISK_METADATA.read().unwrap(); + if !metadata.is_setup { + return_errno!(EINVAL, "SwornDisk not set up"); + } + let total_blocks = metadata.size / BLOCK_SIZE; + let image_path = { + let mut path = metadata.image_dir.clone(); + path.push("sworndisk.image"); + path + }; + let raw_disk = + RawDisk::open_or_create(total_blocks, image_path.to_str().unwrap())?; + let root_key = metadata.root_key; + + let sworndisk = Arc::new( + SwornDisk::open(raw_disk.clone(), root_key, None).unwrap_or_else(|_e| { + SwornDisk::create(raw_disk, root_key, None).unwrap() + }), + ); + sworndisk_opt.insert(sworndisk.clone()); + sworndisk + } + } + _ => return_errno!(EINVAL, "Unrecognized block device"), + }; + Ok(Self { disk }) + } + + pub fn disk(&self) -> Arc { + self.disk.clone() + } +} + +// Used for registering the disk to the DevFS +impl INode for DevDisk { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result { + if rw_args_block_aligned(offset, buf.len()) { + self.disk + .read_blocks((offset / BLOCK_SIZE) as _, &mut [buf])?; + } else { + self.disk.read_bytes(offset, buf)?; + } + + Ok(buf.len()) + } + + fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result { + if rw_args_block_aligned(offset, buf.len()) { + self.disk.write_blocks((offset / BLOCK_SIZE) as _, &[buf])?; + } else { + self.disk.write_bytes(offset, buf)?; + } + + Ok(buf.len()) + } + + fn metadata(&self) -> vfs::Result { + Ok(Metadata { + dev: 0, + inode: 0xfe23_1d08, + size: self.disk.total_bytes(), + blk_size: BLOCK_SIZE, + blocks: self.disk.total_blocks(), + atime: Timespec { sec: 0, nsec: 0 }, + mtime: Timespec { sec: 0, nsec: 0 }, + ctime: Timespec { sec: 0, nsec: 0 }, + type_: FileType::File, + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + rdev: 0, + }) + } + + fn sync_all(&self) -> vfs::Result<()> { + self.disk.sync()?; + Ok(()) + } + + fn sync_data(&self) -> vfs::Result<()> { + self.disk.sync()?; + Ok(()) + } + + fn as_any_ref(&self) -> &dyn Any { + self + } +} + +fn rw_args_block_aligned(offset: usize, buf_len: usize) -> bool { + if offset % BLOCK_SIZE == 0 && buf_len > 0 && buf_len % BLOCK_SIZE == 0 { + true + } else { + false + } +} + +/// Metadata for SwornDisk. +#[derive(Debug)] +pub struct SwornDiskMeta { + size: usize, + root_key: AeadKey, + image_dir: PathBuf, + is_setup: bool, +} + +impl Default for SwornDiskMeta { + fn default() -> Self { + Self { + size: 0, + root_key: AeadKey::default(), + image_dir: PathBuf::from("run"), + is_setup: false, + } + } +} + +impl SwornDiskMeta { + pub fn setup( + disk_size: u64, + user_key: &Option, + source_path: Option<&PathBuf>, + ) -> Result<()> { + let mut metadata = SWORNDISK_METADATA.write().unwrap(); + if metadata.is_setup { + return_errno!(EEXIST, "SwornDisk already set up"); + }; + if disk_size < (5 * GB) as _ { + return_errno!(EINVAL, "Disk size too small for SwornDisk"); + }; + metadata.size = disk_size as _; + if let Some(source_path) = source_path { + metadata.image_dir = source_path.clone(); + } + let root_key = if let Some(user_key) = user_key { + *user_key + } else { + get_autokey(&metadata.image_dir)? + }; + metadata.root_key = AeadKey::from(root_key); + metadata.is_setup = true; + Ok(()) + } + + pub fn is_setup() -> bool { + SWORNDISK_METADATA.read().unwrap().is_setup + } +} diff --git a/src/libos/src/blk/mod.rs b/src/libos/src/blk/mod.rs new file mode 100644 index 00000000..15610be5 --- /dev/null +++ b/src/libos/src/blk/mod.rs @@ -0,0 +1,13 @@ +//! Block layer. +mod dev_disk; +mod raw_disk; + +pub use self::dev_disk::{DevDisk, SwornDiskMeta, DEV_SWORNDISK}; +pub use self::raw_disk::RawDisk; + +pub use ext2_rs::{Bid, BlockDevice, BlockDeviceExt}; + +pub const BLOCK_SIZE: usize = 0x1000; + +pub const MB: usize = 1024 * 1024; +pub const GB: usize = 1024 * MB; diff --git a/src/libos/src/blk/raw_disk.rs b/src/libos/src/blk/raw_disk.rs new file mode 100644 index 00000000..4266da87 --- /dev/null +++ b/src/libos/src/blk/raw_disk.rs @@ -0,0 +1,137 @@ +//! Raw disk. +use super::{Bid, BlockDevice}; +use crate::blk::BLOCK_SIZE; +use crate::prelude::*; + +use alloc::ffi::CString; +use alloc::string::{String, ToString}; +use core::ops::Range; +use sgx_trts::libc::ocall::{fdatasync, ftruncate, open64, pread64, pwrite64, unlink}; +use sgx_trts::libc::{O_CREAT, O_DIRECT, O_RDWR, O_TRUNC}; +use std::os::unix::io::{AsRawFd, RawFd}; + +use ext2_rs::FsError as Ext2Error; +use sworndisk_v2::{BlockId, BlockSet, BufMut, BufRef, Errno as SwornErrno, Error as SwornError}; + +/// A raw disk as a block device, backed by a host file. +#[derive(Clone, Debug)] +pub struct RawDisk { + fd: RawFd, + path: String, + range: Range, +} + +impl RawDisk { + pub fn open_or_create(nblocks: usize, path: &str) -> Result { + unsafe { + let flags = O_RDWR | O_CREAT; // w/o O_DIRECT + // let flags = O_RDWR | O_CREAT | O_DIRECT; // w/o O_TRUNC + let cpath = CString::new(path).unwrap(); + let fd = open64(cpath.as_ptr() as _, flags, 0o666); + if fd == -1 { + return_errno!(EIO, "raw disk open failed"); + } + + let res = ftruncate(fd, (nblocks * BLOCK_SIZE) as _); + if res == -1 { + return_errno!(EIO, "raw disk truncate failed"); + } + + Ok(Self { + fd, + path: path.to_string(), + range: 0..nblocks, + }) + } + } +} + +// Used by `SwornDisk` as its underlying disk. +impl BlockSet for RawDisk { + fn read(&self, mut pos: BlockId, mut buf: BufMut) -> core::result::Result<(), SwornError> { + pos += self.range.start; + debug_assert!(pos + buf.nblocks() <= self.range.end); + + let buf_mut_slice = buf.as_mut_slice(); + unsafe { + let res = pread64( + self.fd, + buf_mut_slice.as_ptr() as _, + buf_mut_slice.len(), + (pos * BLOCK_SIZE) as _, + ); + if res == -1 { + return Err(SwornError::with_msg( + SwornErrno::IoFailed, + "raw disk read failed", + )); + } + } + + Ok(()) + } + + fn write(&self, mut pos: BlockId, buf: BufRef) -> core::result::Result<(), SwornError> { + pos += self.range.start; + debug_assert!(pos + buf.nblocks() <= self.range.end); + + let buf_slice = buf.as_slice(); + unsafe { + let res = pwrite64( + self.fd, + buf_slice.as_ptr() as _, + buf_slice.len(), + (pos * BLOCK_SIZE) as _, + ); + if res == -1 { + return Err(SwornError::with_msg( + SwornErrno::IoFailed, + "raw disk write failed", + )); + } + } + + Ok(()) + } + + fn subset(&self, range: Range) -> core::result::Result + where + Self: Sized, + { + debug_assert!(self.range.start + range.end <= self.range.end); + Ok(Self { + fd: self.fd, + path: self.path.clone(), + range: Range { + start: self.range.start + range.start, + end: self.range.start + range.end, + }, + }) + } + + fn flush(&self) -> core::result::Result<(), SwornError> { + unsafe { + let res = fdatasync(self.fd); + if res == -1 { + return Err(SwornError::with_msg( + SwornErrno::IoFailed, + "raw disk sync failed", + )); + } + } + Ok(()) + } + + fn nblocks(&self) -> usize { + self.range.len() + } +} + +impl Drop for RawDisk { + fn drop(&mut self) { + unsafe { + // XXX: When should we delete the host file? + // unlink(self.path.as_ptr() as _); + } + } +} diff --git a/src/libos/src/config.rs b/src/libos/src/config.rs index 38b32ff5..2d34d121 100644 --- a/src/libos/src/config.rs +++ b/src/libos/src/config.rs @@ -162,6 +162,7 @@ pub enum ConfigMountFsType { TYPE_UNIONFS, TYPE_DEVFS, TYPE_PROCFS, + TYPE_EXT2, } impl ConfigMountFsType { @@ -175,6 +176,7 @@ impl ConfigMountFsType { "unionfs" => ConfigMountFsType::TYPE_UNIONFS, "devfs" => ConfigMountFsType::TYPE_DEVFS, "procfs" => ConfigMountFsType::TYPE_PROCFS, + "ext2" => ConfigMountFsType::TYPE_EXT2, _ => { return_errno!(EINVAL, "Unsupported file system type"); } @@ -189,6 +191,7 @@ pub struct ConfigMountOptions { pub layers: Option>, pub temporary: bool, pub cache_size: Option, + pub disk_size: Option, pub index: u32, } @@ -363,11 +366,17 @@ impl ConfigMountOptions { } else { None }; + let disk_size = if input.disk_size.is_some() { + Some(parse_memory_size(input.disk_size.as_ref().unwrap())? as _) + } else { + None + }; Ok(ConfigMountOptions { mac, layers, temporary: input.temporary, cache_size, + disk_size, index: input.index, }) } @@ -518,6 +527,8 @@ struct InputConfigMountOptions { #[serde(default)] pub cache_size: Option, #[serde(default)] + pub disk_size: Option, + #[serde(default)] pub index: u32, } diff --git a/src/libos/src/fs/dev_fs/mod.rs b/src/libos/src/fs/dev_fs/mod.rs index 4cddd081..44e2f2f6 100644 --- a/src/libos/src/fs/dev_fs/mod.rs +++ b/src/libos/src/fs/dev_fs/mod.rs @@ -12,6 +12,7 @@ use self::dev_random::DevRandom; use self::dev_sgx::DevSgx; use self::dev_shm::DevShm; use self::dev_zero::DevZero; +use blk::DevDisk; mod dev_fd; mod dev_null; @@ -21,7 +22,7 @@ mod dev_shm; mod dev_zero; /// API to initialize the DevFS -pub fn init_devfs() -> Result> { +pub fn init_devfs(disk_options: &[DevDiskOption]) -> Result> { let devfs = DevFS::new(); let dev_null = Arc::new(DevNull) as _; devfs.add("null", dev_null)?; @@ -37,6 +38,11 @@ pub fn init_devfs() -> Result> { devfs.add("shm", dev_shm)?; let dev_fd = Arc::new(DevFd) as _; devfs.add("fd", dev_fd); + for disk_option in disk_options { + let disk_name = &disk_option.name; + let dev_disk = Arc::new(DevDisk::open_or_create(disk_name)?); + devfs.add(disk_name, dev_disk)?; + } let mountable_devfs = MountFS::new(devfs); // Mount the ramfs at '/shm' let ramfs = RamFS::new(); @@ -49,3 +55,14 @@ pub fn init_devfs() -> Result> { // TODO: Add stdio(stdin, stdout, stderr) into DevFS Ok(mountable_devfs) } + +/// Options of block device under the DevFS. +pub struct DevDiskOption { + name: &'static str, +} + +impl DevDiskOption { + pub fn new(name: &'static str) -> Self { + Self { name } + } +} diff --git a/src/libos/src/fs/fs_ops/mount.rs b/src/libos/src/fs/fs_ops/mount.rs index 6525f057..7130832e 100644 --- a/src/libos/src/fs/fs_ops/mount.rs +++ b/src/libos/src/fs/fs_ops/mount.rs @@ -24,13 +24,14 @@ pub fn do_mount_rootfs( 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)?; + let root_inode = new_rootfs.root_inode(); 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_app_config.entry_points.to_owned(); }); + mount_nonroot_fs_according_to(&root_inode, mount_config, user_key, true)?; // Write resolv.conf file into mounted file system write_host_file(HostFile::ResolvConf)?; @@ -137,18 +138,25 @@ pub fn do_mount( }; (vec![mc], None) } + MountOptions::Ext2 => { + let mc = ConfigMount { + type_: ConfigMountFsType::TYPE_EXT2, + target, + source: None, + options: Default::default(), + }; + (vec![mc], None) + } }; let mut rootfs = ROOT_FS.write().unwrap(); // Should we sync the fs before mount? rootfs.sync()?; + let root_inode = rootfs.root_inode(); + drop(rootfs); + let follow_symlink = !flags.contains(MountFlags::MS_NOSYMFOLLOW); - mount_nonroot_fs_according_to( - &rootfs.root_inode(), - &mount_configs, - &user_key, - follow_symlink, - )?; + mount_nonroot_fs_according_to(&root_inode, &mount_configs, &user_key, follow_symlink)?; Ok(()) } @@ -215,6 +223,7 @@ pub enum MountOptions { SEFS(SEFSMountOptions), HostFS(PathBuf), RamFS, + Ext2, } impl MountOptions { @@ -253,6 +262,7 @@ impl MountOptions { Self::HostFS(dir) } ConfigMountFsType::TYPE_RAMFS => Self::RamFS, + ConfigMountFsType::TYPE_EXT2 => Self::Ext2, _ => { return_errno!(EINVAL, "unsupported fs type"); } diff --git a/src/libos/src/fs/rootfs.rs b/src/libos/src/fs/rootfs.rs index 35799ae2..97e63da4 100644 --- a/src/libos/src/fs/rootfs.rs +++ b/src/libos/src/fs/rootfs.rs @@ -3,18 +3,20 @@ use super::hostfs::HostFS; use super::procfs::ProcFS; use super::sefs::{SgxStorage, SgxUuidProvider}; use super::*; -use config::{ConfigApp, ConfigMountFsType}; -use std::mem::size_of; -use std::path::{Path, PathBuf}; -use std::untrusted::path::PathEx; +use crate::blk::{DevDisk, SwornDiskMeta, DEV_SWORNDISK}; +use crate::config::{ConfigApp, ConfigMountFsType}; +use crate::fs::dev_fs::DevDiskOption; +use crate::time::OcclumTimeProvider; +use alloc::ffi::CString; +use ext2_rs::{BlockDevice, Ext2}; 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; - -use util::mem_util::from_user; +use std::path::{Path, PathBuf}; +use std::untrusted::path::PathEx; lazy_static! { /// The root of file system @@ -102,6 +104,14 @@ pub fn mount_nonroot_fs_according_to( user_key: &Option, follow_symlink: bool, ) -> Result<()> { + let mc_ext2_opt = mount_configs + .iter() + .find(|mc| mc.type_ == ConfigMountFsType::TYPE_EXT2); + if let Some(mc) = mc_ext2_opt { + // Setup disk metadata first if enabled Ext2 + setup_disk_meta_for_ext2(mc, user_key)?; + } + for mc in mount_configs { if mc.target == Path::new("/") { continue; @@ -140,7 +150,12 @@ pub fn mount_nonroot_fs_according_to( mount_fs_at(ramfs, root, &mc.target, follow_symlink)?; } TYPE_DEVFS => { - let devfs = dev_fs::init_devfs()?; + let disk_options = if mc_ext2_opt.is_some() { + vec![DevDiskOption::new(DEV_SWORNDISK)] + } else { + vec![] + }; + let devfs = dev_fs::init_devfs(&disk_options)?; mount_fs_at(devfs, root, &mc.target, follow_symlink)?; } TYPE_PROCFS => { @@ -172,8 +187,17 @@ pub fn mount_nonroot_fs_according_to( }; mount_fs_at(unionfs, root, &mc.target, follow_symlink)?; } + TYPE_EXT2 => { + // Leave mounting the Ext2 to the final step + // before the disk under the DevFS is ready + } } } + + if let Some(mc) = mc_ext2_opt { + let ext2 = open_ext2()?; + mount_fs_at(ext2, root, &mc.target, follow_symlink)?; + } Ok(()) } @@ -266,3 +290,44 @@ fn open_or_create_sefs_according_to( }; Ok(sefs) } + +fn open_ext2() -> Result> { + debug_assert!(SwornDiskMeta::is_setup()); + + let sworndisk = DevDisk::open_or_create(DEV_SWORNDISK)?.disk(); + let ext2 = match Ext2::open(sworndisk, Arc::new(OcclumTimeProvider)) { + Err(e) if e == ext2_rs::FsError::WrongFs => { + let sworndisk = format_disk_for_ext2()?; + Ext2::open(sworndisk, Arc::new(OcclumTimeProvider))? + } + res => res?, + }; + Ok(ext2) +} + +fn format_disk_for_ext2() -> Result> { + // Format the SwornDisk using 'mke2fs' tool for Ext2 + let path = PathBuf::from("/sbin/mke2fs"); + let argv = vec![ + CString::new("mke2fs").unwrap(), + CString::new("-q").unwrap(), + CString::new("-t").unwrap(), + CString::new("ext2").unwrap(), + CString::new("/dev/".to_owned() + DEV_SWORNDISK).unwrap(), + ]; + let pid = process::do_spawn(&path.to_str().unwrap(), &argv, &[], &[], None, ¤t!())?; + let _ = process::do_wait4(pid as _, core::ptr::null_mut(), 0)?; + + let sworndisk = DevDisk::open_or_create(DEV_SWORNDISK)?.disk(); + Ok(sworndisk) +} + +fn setup_disk_meta_for_ext2(mc: &ConfigMount, user_key: &Option) -> Result<()> { + debug_assert_eq!(mc.type_, ConfigMountFsType::TYPE_EXT2); + let disk_size = mc.options.disk_size; + if disk_size.is_none() { + return_errno!(EINVAL, "Disk size is expected for Ext2"); + } + let source_path = mc.source.as_ref(); + SwornDiskMeta::setup(disk_size.unwrap(), user_key, source_path) +} diff --git a/src/libos/src/fs/stdio.rs b/src/libos/src/fs/stdio.rs index 5d27a24b..0b5a61ec 100644 --- a/src/libos/src/fs/stdio.rs +++ b/src/libos/src/fs/stdio.rs @@ -21,6 +21,7 @@ macro_rules! try_libc_stdio { // Struct for the occlum_stdio_fds #[repr(C)] +#[derive(Debug)] pub struct HostStdioFds { pub stdin_fd: i32, pub stdout_fd: i32, @@ -30,11 +31,7 @@ pub struct HostStdioFds { impl HostStdioFds { pub fn from_user(ptr: *const HostStdioFds) -> Result { if ptr.is_null() { - return Ok(Self { - stdin_fd: libc::STDIN_FILENO, - stdout_fd: libc::STDOUT_FILENO, - stderr_fd: libc::STDERR_FILENO, - }); + return Ok(Self::default()); } let host_stdio_fds_c = unsafe { &*ptr }; if host_stdio_fds_c.stdin_fd < 0 @@ -51,6 +48,16 @@ impl HostStdioFds { } } +impl Default for HostStdioFds { + fn default() -> Self { + Self { + stdin_fd: libc::STDIN_FILENO, + stdout_fd: libc::STDOUT_FILENO, + stderr_fd: libc::STDERR_FILENO, + } + } +} + struct StdoutRaw { host_fd: i32, } diff --git a/src/libos/src/lib.rs b/src/libos/src/lib.rs index 83e2240f..b9a73fb6 100644 --- a/src/libos/src/lib.rs +++ b/src/libos/src/lib.rs @@ -30,6 +30,7 @@ #![feature(linkage)] #![feature(new_uninit)] #![feature(raw_ref_op)] +#![feature(let_chains)] #[macro_use] extern crate alloc; @@ -86,6 +87,7 @@ mod error; #[macro_use] mod net; +mod blk; mod config; mod entry; mod events; diff --git a/src/libos/src/process/mod.rs b/src/libos/src/process/mod.rs index ec6f5aed..e7a506af 100644 --- a/src/libos/src/process/mod.rs +++ b/src/libos/src/process/mod.rs @@ -24,7 +24,7 @@ use self::wait::{WaitQueue, Waiter}; pub use self::do_exit::handle_force_exit; pub use self::do_futex::{futex_wait, futex_wake}; pub use self::do_robust_list::RobustListHead; -pub use self::do_spawn::do_spawn_without_exec; +pub use self::do_spawn::{do_spawn, do_spawn_without_exec}; pub use self::do_vfork::{do_vfork, handle_force_stop}; pub use self::do_wait4::idle_reap_zombie_children; pub use self::process::{Process, ProcessFilter, ProcessStatus, IDLE}; diff --git a/src/libos/src/time/mod.rs b/src/libos/src/time/mod.rs index 9f5044e6..20d6e505 100644 --- a/src/libos/src/time/mod.rs +++ b/src/libos/src/time/mod.rs @@ -309,6 +309,13 @@ impl TimeProvider for OcclumTimeProvider { } } +impl ext2_rs::TimeProvider for OcclumTimeProvider { + fn now(&self) -> ext2_rs::UnixTime { + let time = do_gettimeofday(); + ext2_rs::UnixTime { sec: time.sec as _ } + } +} + // For Timerfd #[repr(C)] #[derive(Debug, Default, Copy, Clone)] diff --git a/src/libos/src/util/sgx/mod.rs b/src/libos/src/util/sgx/mod.rs index 934343af..6d5edb22 100644 --- a/src/libos/src/util/sgx/mod.rs +++ b/src/libos/src/util/sgx/mod.rs @@ -21,7 +21,7 @@ pub use self::dcap::{ QuoteGenerator as SgxDCAPQuoteGenerator, QuoteVerifier as SgxDCAPQuoteVerifier, }; pub use self::epid::AttestationAgent as SgxEPIDAttestationAgent; -pub use self::sgx_key::get_key; +pub use self::sgx_key::{get_autokey, get_key}; pub use self::sgx_report::{create_report, get_self_target, verify_report}; pub fn allow_debug() -> bool { diff --git a/src/libos/src/util/sgx/sgx_key.rs b/src/libos/src/util/sgx/sgx_key.rs index 8c9bb74a..81d10b23 100644 --- a/src/libos/src/util/sgx/sgx_key.rs +++ b/src/libos/src/util/sgx/sgx_key.rs @@ -1,6 +1,11 @@ use super::*; +use crate::misc::get_random; +use std::io::{Read, Write}; +use std::mem::{size_of, transmute}; +use std::path::PathBuf; use std::ptr; +use std::untrusted::{fs::File, path::PathEx}; pub fn get_key(key_request: &sgx_key_request_t) -> Result { let mut key = sgx_key_128bit_t::default(); @@ -14,3 +19,91 @@ pub fn get_key(key_request: &sgx_key_request_t) -> Result { } } } + +pub fn get_autokey(path: &PathBuf) -> Result { + let mut key_request = sgx_key_request_t::default(); + + key_request.key_name = SGX_KEYSELECT_SEAL; + key_request.key_policy = SGX_KEYPOLICY_MRSIGNER; + + let key_metadata = { + let metadata_path = { + let mut metadata_path = path.clone(); + if !metadata_path.is_dir() { + metadata_path = metadata_path.parent().unwrap().to_path_buf(); + } + metadata_path.push(KEY_METADATA_FILE_NAME); + metadata_path + }; + let load_res = if metadata_path.exists() { + KeyMetadata::load_from(&metadata_path) + } else { + Err(errno!(ENOENT)) + }; + load_res.unwrap_or_else(|_| { + let key_metadata = KeyMetadata::default(); + let _ = key_metadata.persist_to(&metadata_path); + key_metadata + }) + }; + key_request.key_id = key_metadata.key_id; + key_request.cpu_svn = key_metadata.cpu_svn; + key_request.isv_svn = key_metadata.isv_svn; + + key_request.attribute_mask.flags = TSEAL_DEFAULT_FLAGSMASK; + key_request.attribute_mask.xfrm = 0x0; + key_request.misc_mask = TSEAL_DEFAULT_MISCMASK; + + get_key(&key_request) +} + +const KEY_METADATA_FILE_NAME: &str = "metadata"; +const KEY_METADATA_SIZE: usize = size_of::(); + +#[repr(C)] +struct KeyMetadata { + pub key_id: sgx_key_id_t, + pub cpu_svn: sgx_cpu_svn_t, + pub isv_svn: sgx_isv_svn_t, +} + +impl Default for KeyMetadata { + fn default() -> Self { + let key_id = { + let mut key_id = sgx_key_id_t::default(); + let _ = get_random(&mut key_id.id); + key_id + }; + let report = sgx_tse::rsgx_self_report(); + Self { + key_id, + cpu_svn: report.body.cpu_svn, + isv_svn: report.body.isv_svn, + } + } +} + +impl KeyMetadata { + pub fn load_from(metadata_path: &PathBuf) -> Result { + debug_assert!(metadata_path.ends_with(KEY_METADATA_FILE_NAME)); + let mut metadata_file = File::open(metadata_path)?; + let mut metadata_buf = [0u8; KEY_METADATA_SIZE]; + metadata_file.read(&mut metadata_buf)?; + Ok(Self::from_bytes(metadata_buf)) + } + + pub fn persist_to(&self, metadata_path: &PathBuf) -> Result<()> { + debug_assert!(metadata_path.ends_with(KEY_METADATA_FILE_NAME)); + let mut metadata_file = File::create(metadata_path)?; + metadata_file.write(self.as_bytes())?; + Ok(()) + } + + fn as_bytes(&self) -> &[u8; KEY_METADATA_SIZE] { + unsafe { transmute::<&Self, &[u8; KEY_METADATA_SIZE]>(self) } + } + + fn from_bytes(bytes: [u8; KEY_METADATA_SIZE]) -> Self { + unsafe { transmute::<[u8; KEY_METADATA_SIZE], Self>(bytes) } + } +} diff --git a/tools/gen_internal_conf/src/main.rs b/tools/gen_internal_conf/src/main.rs index 92b82ca2..507d1946 100644 --- a/tools/gen_internal_conf/src/main.rs +++ b/tools/gen_internal_conf/src/main.rs @@ -793,6 +793,8 @@ struct OcclumMountOptions { pub temporary: bool, #[serde(default, skip_serializing_if = "Option::is_none")] pub cache_size: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub disk_size: Option, } #[inline] diff --git a/tools/occlum b/tools/occlum index 7097d86d..98f2436b 100755 --- a/tools/occlum +++ b/tools/occlum @@ -318,6 +318,8 @@ cmd_init() { mkdir -p image/dev mkdir -p image/proc mkdir -p image/etc + mkdir -p image/sbin + mkdir -p image/ext2 local occlum_glibc_lib=/opt/occlum/glibc/lib local occlum_glibc_etc=/opt/occlum/glibc/etc if [ -d "$occlum_glibc_lib" ]; then @@ -429,6 +431,8 @@ cmd_build() { cp "$instance_dir/init_ra_conf.json" "$instance_dir/initfs/etc/" fi + prepare_ext2_if_enabled + # If sgx mode is changed, build thoroughly again if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then if [ "$(cat $instance_dir/.sgx_mode 2>/dev/null)" != "$SGX_MODE" ]; then @@ -468,6 +472,39 @@ cmd_build() { echo "Built the Occlum image and enclave successfully" } +prepare_ext2_if_enabled() { + if ! jq -e '.mount[] | select(.type == "ext2")' "$instance_dir/Occlum.json" > /dev/null 2>&1; then + return + fi + + local mke2fs_path="/usr/sbin/mke2fs" + local occlum_glibc_lib="/opt/occlum/glibc/lib" + local os_lib_path="/usr/lib/x86_64-linux-gnu" # for ubuntu + local os_release=`awk -F= '/^NAME/{print $2}' /etc/os-release` + if [ "$os_release" != "\"Ubuntu\"" ]; then + os_lib_path="/usr/lib64" # for openanolis, alios + fi + if [ -f "$mke2fs_path" ] && [ -d "$os_lib_path" ] && [ -d "$occlum_glibc_lib" ]; then + cp -t "$instance_dir/image/sbin/" "$mke2fs_path" + mkdir -p "$instance_dir/image/$occlum_glibc_lib" + cp -t "$instance_dir/image/$occlum_glibc_lib" \ + "$os_lib_path/libext2fs.so.2" \ + "$os_lib_path/libcom_err.so.2" \ + "$os_lib_path/libblkid.so.1" \ + "$os_lib_path/libuuid.so.1" \ + "$os_lib_path/libe2p.so.2" + + cp -t "$instance_dir/image/lib64/" \ + "$occlum_glibc_lib/ld-linux-x86-64.so.2" + ln -sf /lib64/ld-linux-x86-64.so.2 "$instance_dir/image/$occlum_glibc_lib/ld-linux-x86-64.so.2" + cp -t "$instance_dir/image/$occlum_glibc_lib" \ + "$occlum_glibc_lib/libc.so.6" \ + "$occlum_glibc_lib/libpthread.so.0" \ + "$occlum_glibc_lib/libm.so.6" + else + exit_error "Ext2 enabled but mke2fs tool or its libs not found" + fi +} cmd_run() { check_has_built