diff --git a/Cargo.lock b/Cargo.lock index ede831e..d2283a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -145,6 +145,26 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + [[package]] name = "bitflags" version = "2.6.0" @@ -163,6 +183,17 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +[[package]] +name = "cc" +version = "1.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -173,13 +204,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "detee-shared" version = "0.1.0" dependencies = [ - "base64", + "bincode", "prost", "serde", "serde_yaml", + "tar", + "tempfile", "thiserror", "tonic", "tonic-build", + "zstd", ] [[package]] @@ -210,6 +244,18 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -269,7 +315,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -449,6 +507,15 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "libc" version = "0.2.169" @@ -456,10 +523,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "log" @@ -501,7 +579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -574,6 +652,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "ppv-lite86" version = "0.2.20" @@ -663,6 +747,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "rand" version = "0.8.5" @@ -690,7 +780,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags", ] [[package]] @@ -730,9 +829,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.38.42" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", @@ -786,6 +885,12 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -829,13 +934,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" [[package]] -name = "tempfile" -version = "3.14.0" +name = "tar" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.3.2", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1051,6 +1167,18 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "want" version = "0.3.1" @@ -1066,6 +1194,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1148,6 +1285,25 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + +[[package]] +name = "xattr" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -1168,3 +1324,31 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.15+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index f282463..f0e9d0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,17 @@ version = "0.1.0" edition = "2021" [dependencies] -base64 = "0.22.1" prost = "0.13.4" serde = { version = "1.0.216", features = ["derive"] } serde_yaml = "0.9.34" thiserror = "2.0.11" tonic = "0.12.3" +tar = "0.4.44" +zstd = "0.13.3" +bincode = "2.0.1" [build-dependencies] tonic-build = "0.12.3" + +[dev-dependencies] +tempfile = "3.19.1" diff --git a/build.rs b/build.rs index 16bb3cd..d9e8a0c 100644 --- a/build.rs +++ b/build.rs @@ -34,6 +34,10 @@ fn main() -> Result<(), Box> { ".vm_proto.VmNodeListResp", "#[derive(serde::Serialize, serde::Deserialize)]", ) + .type_attribute( + ".dtpm_proto.FileEntry", + "#[derive(serde::Serialize, serde::Deserialize, bincode::Encode, bincode::Decode)]", + ) .compile_protos( &[ "proto/sgx/app.proto", diff --git a/proto/sgx/dtpm.proto b/proto/sgx/dtpm.proto index 5622bb3..45af42d 100644 --- a/proto/sgx/dtpm.proto +++ b/proto/sgx/dtpm.proto @@ -5,16 +5,19 @@ package dtpm_proto; import "shared/common.proto"; message DtpmConfigData { - repeated FileEntry filesystems = 1; - repeated EnvironmentEntry environments = 2; - repeated ChildProcess child_processes = 3; + repeated EnvironmentEntry environments = 1; + repeated ChildProcess child_processes = 2; } message FileEntry { string path = 1; - string content = 2; + oneof content { + bytes data = 2; + bytes archive = 3; + } } + message EnvironmentEntry { string name = 1; string value = 2; @@ -35,7 +38,6 @@ message RestartPolicy { } } - message DtpmSetConfigReq { DtpmConfigData config_data = 1; string metadata = 2; @@ -51,6 +53,7 @@ message DtpmGetConfigRes { } service DtpmConfigManager { + rpc UploadFiles(stream FileEntry) returns (common_proto.Empty) {} rpc SetConfig(DtpmSetConfigReq) returns (DtpmSetConfigRes) {} rpc GetConfig(common_proto.Empty) returns (DtpmGetConfigRes) {} } \ No newline at end of file diff --git a/src/sgx/types/dtpm.rs b/src/sgx/types/dtpm.rs index 7b33293..e272805 100644 --- a/src/sgx/types/dtpm.rs +++ b/src/sgx/types/dtpm.rs @@ -1,6 +1,9 @@ use crate::sgx::pb::dtpm_proto; -use base64::{engine::general_purpose::STANDARD as BASE64, Engine}; +use bincode::{Decode, Encode}; use serde::{Deserialize, Serialize}; +use std::path::Path; +use tar::{Archive, Builder}; +use zstd::{Decoder, Encoder}; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct DtpmConfig { @@ -12,11 +15,7 @@ pub struct DtpmConfig { impl From for DtpmConfig { fn from(pb_val: dtpm_proto::DtpmConfigData) -> Self { DtpmConfig { - filesystems: pb_val - .filesystems - .into_iter() - .map(FileEntry::from) - .collect(), + filesystems: vec![], environments: pb_val .environments .into_iter() @@ -34,14 +33,13 @@ impl From for DtpmConfig { impl From for dtpm_proto::DtpmConfigData { fn from(val: DtpmConfig) -> dtpm_proto::DtpmConfigData { dtpm_proto::DtpmConfigData { - filesystems: val.filesystems.into_iter().map(Into::into).collect(), environments: val.environments.into_iter().map(Into::into).collect(), child_processes: val.child_processes.into_iter().map(Into::into).collect(), } } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct FileEntry { pub path: String, pub content: FileContent, @@ -51,7 +49,13 @@ impl From for FileEntry { fn from(pb_val: dtpm_proto::FileEntry) -> Self { FileEntry { path: pb_val.path, - content: FileContent::Data(pb_val.content), + content: match pb_val.content { + Some(dtpm_proto::file_entry::Content::Data(data)) => FileContent::Data(data), + Some(dtpm_proto::file_entry::Content::Archive(archive_data)) => { + FileContent::Archive(archive_data) + } + _ => FileContent::Data(vec![]), + }, } } } @@ -60,19 +64,24 @@ impl From for dtpm_proto::FileEntry { dtpm_proto::FileEntry { path: val.path, content: match val.content { - FileContent::Data(data) => data, - FileContent::Path(path) => path, + FileContent::Path(_) => unimplemented!(), + FileContent::Data(data) => Some(dtpm_proto::file_entry::Content::Data(data)), + FileContent::Archive(file_entry) => { + Some(dtpm_proto::file_entry::Content::Archive(file_entry)) + } }, } } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub enum FileContent { #[serde(rename = "path")] Path(String), #[serde(rename = "data")] - Data(String), + Data(Vec), + #[serde(rename = "directory")] + Archive(Vec), } #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -197,15 +206,61 @@ impl DtpmConfig { } pub fn load_data(mut self) -> Result { - self.filesystems.iter_mut().for_each(|x| { - if let FileContent::Path(path) = &x.content { - let content = - std::fs::read(path).unwrap_or_else(|_| panic!("Unable to read file {path}")); - let encoded = BASE64.encode(content); - x.content = FileContent::Data(encoded); + for file_entry in self.filesystems.iter_mut() { + if let FileContent::Path(content_path) = &file_entry.content { + if Path::new(content_path).is_dir() { + let compressed_data = compress_directory(content_path)?; + file_entry.content = FileContent::Archive(compressed_data); + } else { + let content = std::fs::read(content_path) + .unwrap_or_else(|_| panic!("Unable to read file {content_path}")); + file_entry.content = FileContent::Data(content); + } } - }); + } Ok(self) } } + +pub fn compress_directory(input_dir: &str) -> Result> { + let path = format!("{}/", input_dir.split('/').next_back().unwrap_or("files")); + let mut tar_builder = Builder::new(Encoder::new(Vec::new(), 3)?); + + tar_builder.append_dir_all(path, input_dir)?; + + tar_builder.finish()?; + + let zstd_encoder = tar_builder.into_inner()?; + let compressed_data = zstd_encoder.finish()?; + + Ok(compressed_data) +} + +pub fn decompress_directory(dst: &str, archive_buff: Vec) -> Result<()> { + /* + for entry in Archive::new(Decoder::new(archive_buff.as_slice())?).entries()? { + let entry = entry?; + let path = entry.path(); + println!( + "Entry: {:?}; type {:?}; size: {}", + path?, + entry.header().entry_type(), + entry.size() + ); + } + */ + let mut archive = Archive::new(Decoder::new(archive_buff.as_slice())?); + + for entry in archive.entries()? { + let mut file = entry?; + let file_path = format!("{dst}/{}", &file.path()?.to_string_lossy()); + if file.header().entry_type() == tar::EntryType::Directory { + std::fs::create_dir_all(file_path)?; + } else { + file.unpack(file_path)?; + } + } + + Ok(()) +} diff --git a/tests/dtpm-config_test.rs b/tests/dtpm-config_test.rs new file mode 100644 index 0000000..ec6baa7 --- /dev/null +++ b/tests/dtpm-config_test.rs @@ -0,0 +1,46 @@ +use detee_shared::sgx::types::dtpm::{compress_directory, decompress_directory, DtpmConfig}; + +use std::sync::LazyLock; + +static TEMP_DIR: LazyLock = LazyLock::new(|| { + tempfile::tempdir() + .unwrap() + .into_path() + .to_string_lossy() + .to_string() +}); + +#[test] +fn dtpm_config_dir_support_test() { + let file_path = "tests/fixtures/dtpm_config.yaml"; + let unloaded_config = DtpmConfig::from_path(file_path).unwrap(); + + let loaded_config = unloaded_config.load_data().unwrap(); + + dbg!(&loaded_config); +} + +#[test] +fn test_compression() { + let file_path = "./tests"; + let compressed_buff = compress_directory(file_path).unwrap(); + + dbg!(&TEMP_DIR); + + std::fs::write( + format!("{}/{}", *TEMP_DIR, "archive.tar.zst"), + &compressed_buff, + ) + .unwrap(); +} + +#[test] +fn test_decompression_02() { + let file_path = "./tests"; + let archive_buff = compress_directory(file_path).unwrap(); + + decompress_directory(&TEMP_DIR, archive_buff).unwrap(); + + let path = format!("{}/{}", *TEMP_DIR, "tests/fixtures/dtpm_config.yaml"); + assert!(std::path::Path::new(&path).exists()); +} diff --git a/tests/fixtures/dtpm_config.yaml b/tests/fixtures/dtpm_config.yaml new file mode 100644 index 0000000..39b0607 --- /dev/null +++ b/tests/fixtures/dtpm_config.yaml @@ -0,0 +1,15 @@ +environments: + - name: APP_NAME + value: actix-injectio-from-base-package + - name: PORT + value: 8080 +child_processes: + - path: /bin/actix-app-info + arguments: [] + restart: + max_retries: 2 + delay_seconds: 2 + policy: !OnNonZeroExit true +filesystems: + - path: /bin/actix-app-info + content: !path "./tests"