diff --git a/Cargo.lock b/Cargo.lock index 10181a35..190bcf03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,15 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" - -[[package]] -name = "array-init" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30bbe2f5e3d117f55bd8c7a1f9191e4a5deba9f15f595bbea4f670c59c765db" +checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf" [[package]] name = "atty" @@ -54,15 +48,15 @@ checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" [[package]] name = "bitflags" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da1976d75adbe5fbc88130ecd119529cf1cc6a93ae1546d8696ee66f0d21af1" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cc" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cfg-if" @@ -153,6 +147,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + [[package]] name = "enarx-keepldr" version = "0.1.0" @@ -161,8 +161,10 @@ dependencies = [ "cc", "ciborium", "colorful", + "flagset", "goblin 0.4.2", "iocuddle", + "itertools", "koine", "kvm-bindings", "kvm-ioctls", @@ -184,6 +186,12 @@ dependencies = [ "x86_64", ] +[[package]] +name = "flagset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1207393e01e20804589a3fc9781c9df2a70687cd81362ca58e33b2a726ec83cf" + [[package]] name = "foreign-types" version = "0.3.2" @@ -277,6 +285,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8972d5be69940353d5347a1344cb375d9b457d6809b428b05bb1ca2fb9ce007" +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + [[package]] name = "koine" version = "0.1.0" @@ -289,18 +306,18 @@ dependencies = [ [[package]] name = "kvm-bindings" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04936b66155d2b23a0df85c411c234b329206e548e1d7f94b8e47c66c87a8a4f" +checksum = "a78c049190826fff959994b7c1d8a2930d0a348f1b8f3aa4f9bb34cd5d7f2952" dependencies = [ "vmm-sys-util", ] [[package]] name = "kvm-ioctls" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2924454e22895c738e43331ae310459c74a11ded9c97dc250129ee10d2f9ca2" +checksum = "48dc14f9047df1873cf6942caccc7431d19c3d496ca7a0d162260c4cf0f64b76" dependencies = [ "kvm-bindings", "libc", @@ -321,9 +338,9 @@ checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -339,9 +356,9 @@ dependencies = [ [[package]] name = "lset" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b20ea162e8026b8fc058e49bbc77ad7dd48d1907b3de206ecbe549c7ce669a" +checksum = "efeae5282702b072b5e21cf8f430ccd3c5031c1e346321a28429523266c4a9b0" [[package]] name = "mmarinus" @@ -393,9 +410,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -404,9 +421,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if", "instant", @@ -430,9 +447,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "primordial" -version = "0.1.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "979d94833957a6485c5cac4b71d552a9cd0b9f3f6fd1c7c5dc8096b3ee2bcd13" +checksum = "55d6312462222758b3fb6c7e84d819ce87c315c446e0e2c11b0b9258dedd3f25" [[package]] name = "proc-macro-error" @@ -460,9 +477,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.28" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] @@ -579,7 +596,7 @@ dependencies = [ [[package]] name = "sallyport" version = "0.1.0" -source = "git+https://github.com/enarx/sallyport?rev=0d3f139366003b196f9c07c437f86d398c73a18c#0d3f139366003b196f9c07c437f86d398c73a18c" +source = "git+https://github.com/enarx/sallyport?rev=c8ed47f27a09a021048153042af9adcda3fc9deb#c8ed47f27a09a021048153042af9adcda3fc9deb" dependencies = [ "libc", "primordial", @@ -622,9 +639,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] @@ -640,9 +657,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.127" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -674,7 +691,7 @@ dependencies = [ [[package]] name = "sev" version = "0.1.0" -source = "git+https://github.com/enarx/sev#3a7775347fec52c335dbeb15cd3da3fc965e6949" +source = "git+https://github.com/enarx/sev#eb57cd413930b1c89f4574c74b16ad5631e2c13c" dependencies = [ "bitfield", "bitflags", @@ -688,10 +705,11 @@ dependencies = [ [[package]] name = "sgx" version = "0.1.0" -source = "git+https://github.com/enarx/sgx?rev=2f8837a3e27d787ad4d420c588bc54b3ff603402#2f8837a3e27d787ad4d420c588bc54b3ff603402" +source = "git+https://github.com/enarx/sgx?rev=a0b881cc798f3bafb8d603fa1bad6ca7b2a2c740#a0b881cc798f3bafb8d603fa1bad6ca7b2a2c740" dependencies = [ "bitflags", "cc", + "flagset", "iocuddle", "libc", "lset", @@ -699,6 +717,7 @@ dependencies = [ "openssl", "primordial", "vdso", + "x86_64", "xsave", ] @@ -716,9 +735,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" dependencies = [ "clap", "lazy_static", @@ -727,9 +746,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" dependencies = [ "heck", "proc-macro-error", @@ -740,9 +759,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.74" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ "proc-macro2", "quote", @@ -834,6 +853,12 @@ dependencies = [ "libc", ] +[[package]] +name = "volatile" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0" + [[package]] name = "walkdir" version = "2.3.2" @@ -884,14 +909,12 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x86_64" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa1f02f6b33489502afe477f7d428cfa1eee22d4a10966e95dfeed96c523d46" +version = "0.14.4" +source = "git+https://github.com/npmccallum/x86_64?branch=errors#502ba0c17b1feeb152390a91664d9ee939943071" dependencies = [ - "array-init", "bit_field", "bitflags", - "cc", + "volatile", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index efdda32c..f4ed9d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,31 +29,33 @@ backend-kvm = ["x86_64", "kvm-bindings", "kvm-ioctls"] backend-sgx = ["sgx"] [dependencies] -sallyport = { git = "https://github.com/enarx/sallyport", features=[ "asm" ], rev="0d3f139366003b196f9c07c437f86d398c73a18c" } -sgx = { git = "https://github.com/enarx/sgx", rev = "2f8837a3e27d787ad4d420c588bc54b3ff603402", features = ["asm", "crypto"], optional = true } +sgx = { git = "https://github.com/enarx/sgx", rev = "a0b881cc798f3bafb8d603fa1bad6ca7b2a2c740", features = ["asm", "crypto"], optional = true } +sallyport = { git = "https://github.com/enarx/sallyport", rev = "c8ed47f27a09a021048153042af9adcda3fc9deb", features = [ "asm" ] } +x86_64 = { git = "https://github.com/npmccallum/x86_64", branch = "errors", default-features = false, optional = true } koine = { git = "https://github.com/enarx/koine", optional = true } -x86_64 = { version = "0.11", default-features = false, features = ["stable"], optional = true } -kvm-bindings = { version = "0.4", optional = true } -kvm-ioctls = { version = "0.9", optional = true } -primordial = "0.1" +primordial = { version = "0.3", features = ["alloc"] } +kvm-bindings = { version = "0.5", optional = true } +kvm-ioctls = { version = "0.10", optional = true } +itertools = "0.10" +protobuf = "2.22" structopt = "0.3" +openssl = "0.10" iocuddle = "0.1" ciborium = "0.1" colorful = "0.2" mmarinus = "0.2" +flagset = "0.4" nbytes = "0.1" anyhow = "1.0" goblin = "0.4" libc = "0.2" -lset = "0.1" -protobuf = "2.22" -openssl = "0.10" +lset = "0.2" [build-dependencies] cc = "1.0" walkdir = "2" protobuf-codegen-pure = "2.25" -sallyport = { git = "https://github.com/enarx/sallyport", features=[ "asm" ], rev="0d3f139366003b196f9c07c437f86d398c73a18c" } +sallyport = { git = "https://github.com/enarx/sallyport", rev = "c8ed47f27a09a021048153042af9adcda3fc9deb", features = [ "asm" ] } [dev-dependencies] process_control = "3.0" diff --git a/internal/shim-sev/Cargo.lock b/internal/shim-sev/Cargo.lock index d6ddae3a..7c3cd0dc 100644 --- a/internal/shim-sev/Cargo.lock +++ b/internal/shim-sev/Cargo.lock @@ -22,9 +22,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "compiler_builtins" -version = "0.1.49" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2" +checksum = "c4fd27448c11cdc03f9be9babc79e2aba19789a1db6fe0a1390d53f99f3f8fb1" [[package]] name = "crt0stack" @@ -56,9 +56,9 @@ checksum = "d0b725207570aa16096962d0b20c79f8a543df2280bd3c903022b9b0b4d7ea68" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] diff --git a/internal/shim-sgx/.cargo/config b/internal/shim-sgx/.cargo/config index 927b8ca1..120e38b0 100644 --- a/internal/shim-sgx/.cargo/config +++ b/internal/shim-sgx/.cargo/config @@ -2,6 +2,6 @@ target = "x86_64-unknown-linux-musl" rustflags = [ "-C", "relocation-model=pic", - "-C", "link-args=-Wl,--sort-section=alignment -nostartfiles", + "-C", "link-args=-Wl,--sort-section=alignment,-Tlayout.ld -nostartfiles", "-C", "link-self-contained=no", ] diff --git a/internal/shim-sgx/Cargo.lock b/internal/shim-sgx/Cargo.lock index b77930db..0340983f 100644 --- a/internal/shim-sgx/Cargo.lock +++ b/internal/shim-sgx/Cargo.lock @@ -3,22 +3,22 @@ version = 3 [[package]] -name = "bitflags" -version = "1.2.1" +name = "bit_field" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" [[package]] -name = "cc" -version = "1.0.68" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "compiler_builtins" -version = "0.1.49" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20b1438ef42c655665a8ab2c1c6d605a305f031d38d9be689ddfef41a20f3aa2" +checksum = "c4fd27448c11cdc03f9be9babc79e2aba19789a1db6fe0a1390d53f99f3f8fb1" [[package]] name = "const-default" @@ -49,13 +49,19 @@ checksum = "9274b445ee572d50bdeb17a1101be829becc565b5c12b21a697af4d360b48e8d" [[package]] name = "enarx-heap" version = "0.1.0" -source = "git+https://github.com/enarx/enarx-heap?rev=6ecf48aa3db78a0cc17f32870c52446dba30f376#6ecf48aa3db78a0cc17f32870c52446dba30f376" +source = "git+https://github.com/enarx/enarx-heap?rev=9cbfb3367edd4aa17f4a7409ea0c0f7d83fa8ce3#9cbfb3367edd4aa17f4a7409ea0c0f7d83fa8ce3" dependencies = [ "libc", "lset", - "primordial", + "primordial 0.1.0", ] +[[package]] +name = "flagset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1207393e01e20804589a3fc9781c9df2a70687cd81362ca58e33b2a726ec83cf" + [[package]] name = "goblin" version = "0.4.2" @@ -68,15 +74,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.100" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "lset" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b20ea162e8026b8fc058e49bbc77ad7dd48d1907b3de206ecbe549c7ce669a" +checksum = "efeae5282702b072b5e21cf8f430ccd3c5031c1e346321a28429523266c4a9b0" [[package]] name = "nbytes" @@ -84,6 +90,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c619aa76dbb3f67970c7cf10fc3efa81da412be26d4dda1726af76b25260dc66" +[[package]] +name = "noted" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1bc5b8b5b7171ba3ddd9c2a6027c345f8a787d8a696d3f95bc30f95edbe5516" + [[package]] name = "plain" version = "0.2.3" @@ -96,11 +108,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "979d94833957a6485c5cac4b71d552a9cd0b9f3f6fd1c7c5dc8096b3ee2bcd13" +[[package]] +name = "primordial" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d6312462222758b3fb6c7e84d819ce87c315c446e0e2c11b0b9258dedd3f25" + [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] @@ -126,10 +144,10 @@ dependencies = [ [[package]] name = "sallyport" version = "0.1.0" -source = "git+https://github.com/enarx/sallyport?rev=0d3f139366003b196f9c07c437f86d398c73a18c#0d3f139366003b196f9c07c437f86d398c73a18c" +source = "git+https://github.com/enarx/sallyport?rev=c8ed47f27a09a021048153042af9adcda3fc9deb#c8ed47f27a09a021048153042af9adcda3fc9deb" dependencies = [ "libc", - "primordial", + "primordial 0.3.0", ] [[package]] @@ -138,18 +156,6 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" -[[package]] -name = "sgx" -version = "0.1.0" -source = "git+https://github.com/enarx/sgx?rev=2f8837a3e27d787ad4d420c588bc54b3ff603402#2f8837a3e27d787ad4d420c588bc54b3ff603402" -dependencies = [ - "bitflags", - "cc", - "lset", - "primordial", - "xsave", -] - [[package]] name = "shim-sgx" version = "0.1.0" @@ -158,22 +164,24 @@ dependencies = [ "const-default", "crt0stack", "enarx-heap", + "flagset", "goblin", "libc", "lset", "nbytes", - "primordial", + "noted", + "primordial 0.3.0", "rcrt1", "sallyport", - "sgx", + "x86_64", "xsave", ] [[package]] name = "syn" -version = "1.0.73" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ "proc-macro2", "quote", @@ -186,6 +194,22 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "volatile" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0" + +[[package]] +name = "x86_64" +version = "0.14.4" +source = "git+https://github.com/npmccallum/x86_64?branch=errors#502ba0c17b1feeb152390a91664d9ee939943071" +dependencies = [ + "bit_field", + "bitflags", + "volatile", +] + [[package]] name = "xsave" version = "0.1.1" diff --git a/internal/shim-sgx/Cargo.toml b/internal/shim-sgx/Cargo.toml index ed957f4b..2151d0d3 100644 --- a/internal/shim-sgx/Cargo.toml +++ b/internal/shim-sgx/Cargo.toml @@ -10,19 +10,21 @@ name = "shim-sgx" test = false [dependencies] -enarx-heap = { git = "https://github.com/enarx/enarx-heap", rev = "6ecf48aa3db78a0cc17f32870c52446dba30f376" } -sallyport = { git = "https://github.com/enarx/sallyport", features=[ "asm" ], rev="0d3f139366003b196f9c07c437f86d398c73a18c" } +sallyport = { git = "https://github.com/enarx/sallyport", rev = "c8ed47f27a09a021048153042af9adcda3fc9deb", features=[ "asm" ] } +enarx-heap = { git = "https://github.com/enarx/enarx-heap", rev = "9cbfb3367edd4aa17f4a7409ea0c0f7d83fa8ce3" } rcrt1 = { git = "https://github.com/enarx/rcrt1", rev = "b28f711" } +x86_64 = { git = "https://github.com/npmccallum/x86_64", branch = "errors" } compiler_builtins = { version = "0.1", default-features = false, features = [ "mem" ] } -sgx = { git = "https://github.com/enarx/sgx", rev = "2f8837a3e27d787ad4d420c588bc54b3ff603402", features = [ "asm" ] } goblin = { version = "0.4", default-features = false, features = [ "elf64" ] } crt0stack = { version = "0.1", default-features = false } libc = { version = "0.2", default-features = false } -primordial = "0.1" -nbytes = "0.1" -lset = "0.1" +const-default = "0.1" +primordial = "0.3.0" +flagset = "0.4" xsave = "0.1.1" -const-default = { version = "0.1" } +nbytes = "0.1" +noted = "0.1" +lset = "0.2" [profile.dev.package.rcrt1] opt-level = 3 diff --git a/internal/shim-sgx/build.rs b/internal/shim-sgx/build.rs new file mode 100644 index 00000000..1fb1f422 --- /dev/null +++ b/internal/shim-sgx/build.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: Apache-2.0 + +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); +} diff --git a/internal/shim-sgx/layout.ld b/internal/shim-sgx/layout.ld new file mode 100644 index 00000000..7f3f37f4 --- /dev/null +++ b/internal/shim-sgx/layout.ld @@ -0,0 +1,77 @@ +ENTRY(_start) + +PHDRS { + rodata PT_LOAD FILEHDR PHDRS; + data PT_LOAD; + text PT_LOAD; + dynamic PT_DYNAMIC; + note PT_NOTE; + + stk0 PT_LOAD; + tcs0 PT_LOAD FLAGS(1 << 20); /* PF_ENARX_SGX_TCS */ + ssa0 PT_LOAD; + + exec 0x634A0003 FLAGS(0); /* PT_ENARX_EXEC */ + heap PT_LOAD FLAGS(7); +} + +SECTIONS { + . = SIZEOF_HEADERS; + + . = ALIGN(4K); + .rodata : { *(.rodata .rodata.*) } :rodata + .dynsym : { *(.dynsym) } :rodata + .dynstr : { *(.dynstr) } :rodata + .gnu.hash : { *(.gnu.hash) } :rodata + .note : { *(.note .note.*) } :rodata :note + + . = ALIGN(4K); + .data.rel.ro : { *(.data.rel.ro .data.rel.ro.*) } :data + .init : { KEEP(*(.init .init.*)) } :data + .dynamic : { *(.dynamic) } :data :dynamic + .data : { *(.data .data.*) } :data + .rela.dyn : { *(.rela.*) } :data + .got : { *(.got) } :data + .bss : { *(.bss .bss.*) } :data + + . = ALIGN(4K); + .text : { *(.text .text.*) } :text + + /DISCARD/ : { + *(.eh_frame*) + *(.note.GNU-stack) + *(.gnu_debuglink) + *(.interp) + *(.gnu.hash) + *(.hash) + *(.comment) + *(COMMON) + *(.note.gnu.build-id) + } + + /* THREAD */ + . = ALIGN(2M); + . += 4K; /* Guard Page */ + .enarx.stk0 (NOLOAD) : { . += 2M - 4K * 5; } :stk0 =0 + .enarx.tcs0 : { + . += 16; + QUAD(. + 4K - 16) /* OSSA */ + LONG(0) /* CSSA */ + LONG(3) /* NSSA */ + QUAD(_start) /* OENTRY */ + . = ALIGN(4K); + } :tcs0 =0 + .enarx.ssa0 (NOLOAD) : { . += 4K * 3; } :ssa0 =0 + + /* EXEC */ + . = ALIGN(1M); + HIDDEN(ENARX_EXEC_START = .); + .enarx.exec (NOLOAD) : { . = ALIGN(128M); } :exec =0 + HIDDEN(ENARX_EXEC_END = .); + + /* HEAP */ + . = ALIGN(128M); + HIDDEN(ENARX_HEAP_START = .); + .enarx.heap (NOLOAD) : { . += 128M; } :heap =0 + HIDDEN(ENARX_HEAP_END = .); +} diff --git a/internal/shim-sgx/src/enclave.rs b/internal/shim-sgx/src/enclave.rs deleted file mode 100644 index 69345a04..00000000 --- a/internal/shim-sgx/src/enclave.rs +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! The Enclave entry and exit -//! -//! Provides enclave EENTER entry point and a `syscall` interface. - -mod _internal { - use const_default::ConstDefault; - use rcrt1::dyn_reloc; - use xsave::XSave; - - const EEXIT: u64 = 4; - - const GPR: u64 = 4096 - 184; - const RSPO: u64 = GPR + 32; - - const STACK: u64 = 9 * 8; - const SHIM: u64 = 10 * 8; - - /// Clear CPU flags, extended state and temporary registers (`r10` and `r11`) - /// - /// This function clears CPU state during enclave transitions. - /// - /// # Safety - /// - /// This function should be safe as it only modifies non-preserved - /// registers. In fact, in addition to the declared calling convention, - /// we promise not to modify any of the parameter registers. - #[naked] - extern "sysv64" fn clearx() { - static XSAVE: XSave = XSave::DEFAULT; - - unsafe { - asm!( - // Clear all temporary registers - "xor r10, r10", - "xor r11, r11", - - // Clear CPU flags - "add r11, r11", - "cld", - - // Clear the extended CPU state - "push rax ", // Save rax - "push rdx ", // Save rdx - "mov rdx, ~0 ", // Set mask for xrstor in rdx - "mov rax, ~0 ", // Set mask for xrstor in rax - "xrstor [rip + {XSAVE}]", // Clear xCPU state with synthetic state - "pop rdx ", // Restore rdx - "pop rax ", // Restore rax - - "ret", - - XSAVE = sym XSAVE, - options(noreturn) - ) - } - } - - /// Clears parameter registers - /// - /// # Safety - /// - /// This function should be safe as it only modifies non-preserved - /// registers. It really doesn't even need to be a naked function - /// except that Rust tries really hard to put `rax` on the stack - /// and then pops it off into a random register (usually `rcx`). - #[naked] - extern "sysv64" fn clearp() { - unsafe { - asm!( - "xor rax, rax", - "xor rdi, rdi", - "xor rsi, rsi", - "xor rdx, rdx", - "xor rcx, rcx", - "xor r8, r8", - "xor r9, r9", - "ret", - options(noreturn) - ) - } - } - - /// Perform relocation - /// - /// # Safety - /// - /// This function does not follow any established calling convention. It - /// has the following requirements: - /// * `rsp` must point to a stack with the return address (i.e. `call`) - /// * `rcx` must contain the address of the `Layout` - /// - /// Upon return, all general-purpose registers will have been preserved. - #[naked] - unsafe extern "sysv64" fn relocate() { - asm!( - "push rax", - "push rdi", - "push rsi", - "push rdx", - "push rcx", - "push r8", - "push r9", - "push r10", - "push r11", - - "mov rsi, [rcx + {SHIM}] ", // rsi = shim load offset (Layout.shim.start) - ".hidden _DYNAMIC ", - "lea rdi, [rip + _DYNAMIC]", // rdi = address of _DYNAMIC section - ".hidden {DYN_RELOC} ", - "call {DYN_RELOC} ", // relocate the dynamic symbols - - "pop r11", - "pop r10", - "pop r9", - "pop r8", - "pop rcx", - "pop rdx", - "pop rsi", - "pop rdi", - "pop rax", - - "ret", - - SHIM = const SHIM, - DYN_RELOC = sym dyn_reloc, - options(noreturn) - ) - } - - /// Entry point - /// - /// This function is called during EENTER. Its inputs are as follows: - /// rax = The current SSA index. (i.e. rbx->cssa) - /// rbx = The address of the TCS. - /// rcx = The next address after the EENTER instruction. - /// - /// If rax == 0, we are doing normal execution. - /// Otherwise, we are handling an exception. - /// - /// # Safety - /// - /// Do not call this function from Rust. It is the entry point for SGX. - #[naked] - #[no_mangle] - pub unsafe extern "sysv64" fn _start() -> ! { - asm!( - "xchg rcx, rbx ", // Swap TCS and next instruction - "add rcx, 4096 ", // rcx = &Layout - - // Find stack pointer for CSSA == 0 - "cmp rax, 0 ", // If CSSA > 0 - "jne 2f ", // ... jump to the next section - "mov r10, [rcx + {STACK}] ", // r10 = stack pointer - "jmp 3f ", // Jump to stack setup - - // Find stack pointer for CSSA > 0 - "2: ", - "mov r10, rax ", // r10 = CSSA - "shl r10, 12 ", // r10 = CSSA * 4096 - "mov r10, [rcx + r10 + {RSPO}]", // r10 = SSA[CSSA - 1].gpr.rsp - "sub r10, 128 ", // Skip the red zone - "jmp 3f ", // Jump to stack setup - - // Setup the stack - "3: ", - "and r10, ~0xf ", // Align the stack - "xchg rsp, r10 ", // Swap r10 and rsp - "sub rsp, 8 ", // Align the stack - "push r10 ", // Store old stack - - // Do relocation if CSSA == 0 - "cmp rax, 0 ", // If CSSA > 0 - "jne 4f ", // ... jump to the next section - "call {RELOC} ", // Relocate symbols - - // Clear, call Rust, clear - "4: ", - "push rcx ", // Save &Layout - "push rax ", // Save CSSA - "mov rcx, rsp ", // Setup argument - "call {CLEARX} ", // Clear CPU state - "call {ENTRY} ", // Jump to Rust - "call {CLEARX} ", // Clear CPU state - "call {CLEARP} ", // Clear parameter registers - "add rsp, 16 ", // Remove arguments from stack - - // Exit - "pop rsp ", // Restore old stack - "mov rax, {EEXIT} ", // rax = EEXIT - "enclu ", // Exit enclave - - CLEARX = sym clearx, - CLEARP = sym clearp, - RELOC = sym relocate, - ENTRY = sym crate::main, - EEXIT = const EEXIT, - STACK = const STACK, - RSPO = const RSPO, - options(noreturn) - ) - } -} diff --git a/internal/shim-sgx/src/entry.rs b/internal/shim-sgx/src/entry.rs index 0f01b96a..44294645 100644 --- a/internal/shim-sgx/src/entry.rs +++ b/internal/shim-sgx/src/entry.rs @@ -3,16 +3,15 @@ use crt0stack::{Builder, Entry, Handle, OutOfSpace}; use goblin::elf::header::{header64::Header, ELFMAG}; -use crate::Layout; - fn exit(code: usize) -> ! { - unsafe { - asm!( - "syscall", - in("rax") libc::SYS_exit, - in("rdi") code, - options(noreturn) - ) + loop { + unsafe { + asm!( + "syscall", + in("rax") libc::SYS_exit, + in("rdi") code + ); + } } } @@ -29,12 +28,12 @@ fn random() -> u64 { } fn crt0setup<'a>( - layout: &Layout, hdr: &Header, crt0: &'a mut [u8], + off: *const (), ) -> Result, OutOfSpace> { let rand = unsafe { core::mem::transmute([random(), random()]) }; - let phdr = layout.code.start as u64 + hdr.e_phoff; + let phdr = off as u64 + hdr.e_phoff; // Set the arguments let mut builder = Builder::new(crt0); @@ -66,10 +65,9 @@ fn crt0setup<'a>( builder.done() } -pub fn entry(layout: &Layout) -> ! { +pub unsafe fn entry(offset: *const ()) -> ! { // Validate the ELF header. - let hdr = unsafe { &*(layout.code.start as *const Header) }; - + let hdr = &*(offset as *const Header); if !hdr.e_ident[..ELFMAG.len()].eq(ELFMAG) { exit(1); } @@ -77,18 +75,16 @@ pub fn entry(layout: &Layout) -> ! { // Prepare the crt0 stack. let mut crt0 = [0u8; 1024]; let space = random() as usize & 0xf0; - let handle = match crt0setup(layout, hdr, &mut crt0[space..]) { + let handle = match crt0setup(hdr, &mut crt0[space..], offset) { Err(OutOfSpace) => exit(1), Ok(handle) => handle, }; - unsafe { - asm!( - "mov rsp, {SP}", - "jmp {START}", - SP = in(reg) &*handle, - START = in(reg) layout.code.start as u64 + hdr.e_entry, - options(noreturn) - ) - } + asm!( + "mov rsp, {SP}", + "jmp {START}", + SP = in(reg) &*handle, + START = in(reg) offset as u64 + hdr.e_entry, + options(noreturn) + ) } diff --git a/internal/shim-sgx/src/event.rs b/internal/shim-sgx/src/event.rs deleted file mode 100644 index c60186e7..00000000 --- a/internal/shim-sgx/src/event.rs +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -use sallyport::Block; -use sgx::types::ssa::{Exception, StateSaveArea}; - -use crate::handler::Handler; -use crate::Layout; -use sallyport::syscall::{BaseSyscallHandler, ProcessSyscallHandler, SyscallHandler}; - -pub fn event(layout: &Layout, aex: &mut StateSaveArea, block: &mut Block) { - let mut h = Handler::new(layout, aex, block); - - // Exception Vector Table - match h.aex.gpr.exitinfo.exception() { - Some(Exception::InvalidOpcode) => { - match unsafe { h.aex.gpr.rip.into_slice(2usize) } { - super::OP_SYSCALL => { - let ret = h.syscall( - h.aex.gpr.rdi.into(), - h.aex.gpr.rsi.into(), - h.aex.gpr.rdx.into(), - h.aex.gpr.r10.into(), - h.aex.gpr.r8.into(), - h.aex.gpr.r9.into(), - h.aex.gpr.rax.into(), - ); - - aex.gpr.rip = (usize::from(aex.gpr.rip) + 2).into(); - match ret { - Err(e) => aex.gpr.rax = (-e).into(), - Ok([rax, rdx]) => { - aex.gpr.rax = rax.into(); - aex.gpr.rdx = rdx.into(); - } - } - } - - super::OP_CPUID => { - h.cpuid(); - aex.gpr.rip = (usize::from(aex.gpr.rip) + 2).into(); - } - - // unsupported opcode - r => { - debugln!(h, "unsupported opcode: {:?}", r); - h.exit(1) - } - } - } - - // Not InvalidOpcode - _ => { - h.attacked(); - } - } -} diff --git a/internal/shim-sgx/src/handler.rs b/internal/shim-sgx/src/handler.rs deleted file mode 100644 index 84cc3201..00000000 --- a/internal/shim-sgx/src/handler.rs +++ /dev/null @@ -1,473 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -use crate::Layout; - -use core::fmt::Write; -use primordial::Register; - -use sallyport::syscall::{ - BaseSyscallHandler, EnarxSyscallHandler, FileSyscallHandler, MemorySyscallHandler, - NetworkSyscallHandler, ProcessSyscallHandler, SyscallHandler, SystemSyscallHandler, - ARCH_GET_FS, ARCH_GET_GS, ARCH_SET_FS, ARCH_SET_GS, SYS_ENARX_CPUID, -}; -use sallyport::untrusted::{AddressValidator, UntrustedRef, UntrustedRefMut, ValidateSlice}; -use sallyport::{request, Block, Cursor, Request}; - -use enarx_heap::Heap; -use sgx::types::ssa::StateSaveArea; - -pub const TRACE: bool = false; - -pub struct Handler<'a> { - pub aex: &'a mut StateSaveArea, - layout: &'a Layout, - block: &'a mut Block, -} - -impl<'a> Write for Handler<'a> { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - if s.as_bytes().is_empty() { - return Ok(()); - } - - let c = self.new_cursor(); - let (_, untrusted) = c.copy_from_slice(s.as_bytes()).or(Err(core::fmt::Error))?; - - let req = request!(libc::SYS_write => libc::STDERR_FILENO, untrusted, untrusted.len()); - let res = unsafe { self.proxy(req) }; - - match res { - Ok(res) if usize::from(res[0]) > s.bytes().len() => self.attacked(), - Ok(res) if usize::from(res[0]) == s.bytes().len() => Ok(()), - _ => Err(core::fmt::Error), - } - } -} - -impl<'a> Handler<'a> { - /// Create a new handler - pub fn new(layout: &'a Layout, aex: &'a mut StateSaveArea, block: &'a mut Block) -> Self { - Self { aex, layout, block } - } - - pub fn cpuid(&mut self) { - if TRACE { - debug!( - self, - "cpuid({:08x}, {:08x})", - usize::from(self.aex.gpr.rax), - usize::from(self.aex.gpr.rcx) - ); - } - - self.block.msg.req = request!(SYS_ENARX_CPUID => self.aex.gpr.rax, self.aex.gpr.rcx); - - unsafe { - // prevent earlier writes from being moved beyond this point - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release); - - asm!("cpuid"); - - // prevent later reads from being moved before this point - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire); - - self.aex.gpr.rax = self.block.msg.req.arg[0].into(); - self.aex.gpr.rbx = self.block.msg.req.arg[1].into(); - self.aex.gpr.rcx = self.block.msg.req.arg[2].into(); - self.aex.gpr.rdx = self.block.msg.req.arg[3].into(); - } - - if TRACE { - debugln!( - self, - " = ({:08x}, {:08x}, {:08x}, {:08x})", - usize::from(self.aex.gpr.rax), - usize::from(self.aex.gpr.rbx), - usize::from(self.aex.gpr.rcx), - usize::from(self.aex.gpr.rdx) - ); - } - } -} - -impl<'a> AddressValidator for Handler<'a> { - fn validate_const_mem_fn(&self, _ptr: *const (), _size: usize) -> bool { - // FIXME: https://github.com/enarx/enarx/issues/630 - true - } - - fn validate_mut_mem_fn(&self, _ptr: *mut (), _size: usize) -> bool { - // FIXME: https://github.com/enarx/enarx/issues/630 - true - } -} - -impl<'a> SyscallHandler for Handler<'a> {} -impl<'a> SystemSyscallHandler for Handler<'a> {} -impl<'a> NetworkSyscallHandler for Handler<'a> {} - -impl<'a> BaseSyscallHandler for Handler<'a> { - fn translate_shim_to_host_addr(buf: *const T) -> usize { - buf as _ - } - - fn new_cursor(&mut self) -> Cursor { - self.block.cursor() - } - - unsafe fn proxy(&mut self, req: Request) -> sallyport::Result { - self.block.msg.req = req; - - // prevent earlier writes from being moved beyond this point - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release); - - asm!("syscall"); - - // prevent later reads from being moved before this point - core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire); - - self.block.msg.rep.into() - } - - /// When we are under attack, we trip this circuit breaker and - /// exit the enclave. Any attempt to re-enter the enclave after - /// tripping the circuit breaker causes the enclave to immediately - /// EEXIT. - fn attacked(&mut self) -> ! { - self.exit(1) - } - - #[inline] - fn unknown_syscall( - &mut self, - _a: Register, - _b: Register, - _c: Register, - _d: Register, - _e: Register, - _f: Register, - nr: usize, - ) { - if !TRACE { - return; - } - debugln!(self, "unsupported syscall: {}", nr); - } - - fn trace(&mut self, name: &str, argc: usize) { - if !TRACE { - return; - } - - let argv = [ - self.aex.gpr.rdi, - self.aex.gpr.rsi, - self.aex.gpr.rdx, - self.aex.gpr.r10, - self.aex.gpr.r8, - self.aex.gpr.r9, - ]; - - debug!(self, "{}(", name); - for (i, arg) in argv[..argc].iter().copied().enumerate() { - let prefix = if i > 0 { ", " } else { "" }; - debug!(self, "{}0x{:x}", prefix, u64::from(arg)); - } - - debugln!(self, ")"); - } -} - -impl<'a> ProcessSyscallHandler for Handler<'a> { - /// Do an arch_prctl() syscall - fn arch_prctl(&mut self, code: libc::c_int, addr: libc::c_ulong) -> sallyport::Result { - self.trace("arch_prctl", 2); - - // TODO: Check that addr in %rdx does not point to an unmapped address - // and is not outside of the process address space. - match code { - ARCH_SET_FS => self.aex.gpr.fsbase = addr.into(), - ARCH_SET_GS => self.aex.gpr.gsbase = addr.into(), - ARCH_GET_FS => return Err(libc::ENOSYS), - ARCH_GET_GS => return Err(libc::ENOSYS), - _ => return Err(libc::EINVAL), - } - - Ok(Default::default()) - } -} - -impl<'a> FileSyscallHandler for Handler<'a> { - /// Do a readv() syscall - fn readv( - &mut self, - fd: libc::c_int, - iovec: UntrustedRef, - iovcnt: libc::c_int, - ) -> sallyport::Result { - self.trace("readv", 3); - - let mut size = 0usize; - let trusted = iovec.validate_slice(iovcnt, self).ok_or(libc::EFAULT)?; - - let c = self.new_cursor(); - - let (c, untrusted) = c - .copy_from_slice::(trusted) - .or(Err(libc::EMSGSIZE))?; - - let mut c = c; - for (t, u) in trusted.iter().zip(untrusted.iter_mut()) { - let (nc, us) = c.alloc::(t.iov_len).or(Err(libc::EMSGSIZE))?; - c = nc; - u.iov_base = us.as_mut_ptr() as _; - size += u.iov_len; - } - - let req = request!(libc::SYS_readv => fd, untrusted, untrusted.len()); - let ret = unsafe { self.proxy(req)? }; - - let mut read = ret[0].into(); - if size < read { - self.attacked(); - } - - let c = self.new_cursor(); - let (c, _) = c - .alloc::(trusted.len()) - .or(Err(libc::EMSGSIZE))?; - - let mut c = c; - for t in trusted.iter() { - let ts = t.iov_base as *mut u8; - let ts_len: usize = t.iov_len; - - let sz = core::cmp::min(ts_len, read); - - let nc = unsafe { c.copy_into_raw_parts(ts_len, ts, sz) }.or(Err(libc::EMSGSIZE))?; - c = nc; - - read -= sz; - } - - Ok(ret) - } - - /// Do a writev() syscall - fn writev( - &mut self, - fd: libc::c_int, - iovec: UntrustedRef, - iovcnt: libc::c_int, - ) -> sallyport::Result { - self.trace("writev", 3); - - let mut size = 0usize; - let trusted = iovec.validate_slice(iovcnt, self).ok_or(libc::EFAULT)?; - let c = self.new_cursor(); - let (c, untrusted) = c - .copy_from_slice::(trusted) - .or(Err(libc::EMSGSIZE))?; - - let mut c = c; - for (t, mut u) in trusted.iter().zip(untrusted.iter_mut()) { - let (nc, us) = unsafe { c.copy_from_raw_parts(t.iov_base as *const u8, t.iov_len) } - .or(Err(libc::EMSGSIZE))?; - c = nc; - u.iov_base = us as _; - size += u.iov_len; - } - - let req = request!(libc::SYS_writev => fd, untrusted, untrusted.len()); - let ret = unsafe { self.proxy(req)? }; - - if size < ret[0].into() { - self.attacked(); - } - - Ok(ret) - } -} - -impl<'a> MemorySyscallHandler for Handler<'a> { - /// Do a brk() system call - fn brk(&mut self, addr: *const u8) -> sallyport::Result { - self.trace("brk", 1); - - let mut heap = unsafe { Heap::new(self.layout.heap.into()) }; - let ret = heap.brk(addr as _); - Ok([ret.into(), Default::default()]) - } - - /// Do a mprotect() system call - // Until EDMM, we can't change any page permissions. - // What you get is what you get. Fake success. - fn mprotect( - &mut self, - _addr: UntrustedRef, - _len: libc::size_t, - _prot: libc::c_int, - ) -> sallyport::Result { - self.trace("mprotect", 3); - - Ok(Default::default()) - } - - /// Do a mmap() system call - fn mmap( - &mut self, - addr: UntrustedRef, - length: libc::size_t, - prot: libc::c_int, - flags: libc::c_int, - fd: libc::c_int, - offset: libc::off_t, - ) -> sallyport::Result { - self.trace("mmap", 6); - - let mut heap = unsafe { Heap::new(self.layout.heap.into()) }; - let ret = heap.mmap::( - addr.as_ptr() as _, - length, - prot, - flags, - fd, // Allow truncation! - offset, - )?; - - Ok([ret.into(), Default::default()]) - } - - /// Do a munmap() system call - fn munmap(&mut self, addr: UntrustedRef, length: libc::size_t) -> sallyport::Result { - self.trace("munmap", 2); - - let mut heap = unsafe { Heap::new(self.layout.heap.into()) }; - heap.munmap::(addr.as_ptr() as _, length)?; - Ok(Default::default()) - } - - // Do madvise syscall - // We don't actually support this. So, fake success. - fn madvise( - &mut self, - _addr: *const libc::c_void, - _length: libc::size_t, - _advice: libc::c_int, - ) -> sallyport::Result { - self.trace("madvise", 3); - Ok(Default::default()) - } -} - -impl<'a> EnarxSyscallHandler for Handler<'a> { - // NOTE: The 'nonce' field is called 'hash' here, as it is used to pass in - // a hash of a public key from the client that is to be embedded in the Quote. - // For more on this syscall, see: https://github.com/enarx/enarx-keepldr/issues/31 - fn get_attestation( - &mut self, - _hash: UntrustedRef, - _hash_len: libc::size_t, - _buf: UntrustedRefMut, - _buf_len: libc::size_t, - ) -> sallyport::Result { - self.trace("get_att", 0); - - /* - // If hash is NULL ptr, it is a Quote size request; return expected Quote size - // without proxying to host. Otherwise get hash value. - let hash = match hash.validate_slice(hash_len, self) { - None => { - let rep: sallyport::Reply = Ok([SGX_QUOTE_SIZE.into(), SGX_TECH.into()]).into(); - return sallyport::Result::from(rep); - } - Some(h) => { - if h.len() != 64 { - return Err(libc::EINVAL); - } - let mut hash = [0u8; 64]; - hash.copy_from_slice(h); - hash - } - }; - - // Used internally for buffer size to host when getting TargetInfo - const REPORT_LEN: usize = 512; - - // Validate output buf memory - let buf = buf.validate_slice(buf_len, self).ok_or(libc::EFAULT)?; - - // Request TargetInfo from host by passing nonce as 0 - let c = self.new_cursor(); - let (_, shim_buf_ptr) = c.alloc::(buf_len).or(Err(libc::EMSGSIZE))?; - let req = request!(SYS_ENARX_GETATT => 0, 0, shim_buf_ptr.as_ptr(), REPORT_LEN); - unsafe { self.proxy(req)? }; - - // Retrieve TargetInfo from sallyport block and call EREPORT to - // create Report from TargetInfo. - let mut ti = [0u8; 512]; - let ti_len = ti.len(); - let c = self.new_cursor(); - - unsafe { - c.copy_into_slice(buf_len, &mut ti[..ti_len]) - .or(Err(libc::EFAULT))?; - } - - // Cannot generate a Report from dummy values - if ti.eq(&SGX_DUMMY_TI) { - buf.copy_from_slice(&SGX_DUMMY_QUOTE); - let rep: sallyport::Reply = Ok([SGX_QUOTE_SIZE.into(), SGX_TECH.into()]).into(); - return sallyport::Result::from(rep); - } - - // Generate Report - let mut target_info: TargetInfo = Default::default(); - let mut f = [0u8; 8]; - let mut x = [0u8; 8]; - f.copy_from_slice(&ti[32..40]); - x.copy_from_slice(&ti[40..48]); - let f = u64::from_le_bytes(f); - let x = u64::from_le_bytes(x); - let att = Attributes::new( - Flags::from_bits(f).ok_or(libc::EBADMSG)?, - Xfrm::from_bits(x).ok_or(libc::EBADMSG)?, - ); - target_info.mrenclave.copy_from_slice(&ti[0..32]); - target_info.attributes = att; - let report: Report = unsafe { target_info.get_report(&ReportData(hash)) }; - - // Request Quote from host - let report_slice = &[report]; - let report_bytes = unsafe { - core::slice::from_raw_parts( - report_slice.as_ptr() as *const _ as *const u8, - core::mem::size_of::(), - ) - }; - - let c = self.new_cursor(); - let (c, shim_nonce_ptr) = c.copy_from_slice(report_bytes).or(Err(libc::EMSGSIZE))?; - let (_, shim_buf_ptr) = c.alloc::(buf_len).or(Err(libc::EMSGSIZE))?; - let req = request!(SYS_ENARX_GETATT => shim_nonce_ptr.as_ptr(), report_bytes.len(), shim_buf_ptr.as_ptr(), buf_len); - let result = unsafe { self.proxy(req)? }; - - // Pass Quote back to code layer in buf - let c = self.new_cursor(); - let (c, _) = c.alloc::(report_bytes.len()).or(Err(libc::EMSGSIZE))?; - - let result_len: usize = result[0].into(); - if result_len > buf_len { - self.attacked() - } - - unsafe { - c.copy_into_slice(buf_len, &mut buf[..result_len]) - .or(Err(libc::EFAULT))?; - } - */ - - let rep: sallyport::Reply = Err(libc::ENOSYS).into(); - sallyport::Result::from(rep) - } -} diff --git a/internal/shim-sgx/src/handler/base.rs b/internal/shim-sgx/src/handler/base.rs new file mode 100644 index 00000000..d8351ae1 --- /dev/null +++ b/internal/shim-sgx/src/handler/base.rs @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: Apache-2.0 + +use primordial::Register; +use sallyport::syscall::{BaseSyscallHandler, ProcessSyscallHandler}; +use sallyport::{Cursor, Request}; + +impl<'a> BaseSyscallHandler for super::Handler<'a> { + fn translate_shim_to_host_addr(buf: *const T) -> usize { + buf as _ + } + + fn new_cursor(&mut self) -> Cursor { + self.block.cursor() + } + + unsafe fn proxy(&mut self, req: Request) -> sallyport::Result { + self.block.msg.req = req; + + // prevent earlier writes from being moved beyond this point + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release); + + asm!("syscall"); + + // prevent later reads from being moved before this point + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire); + + self.block.msg.rep.into() + } + + /// When we are under attack, we trip this circuit breaker and + /// exit the enclave. Any attempt to re-enter the enclave after + /// tripping the circuit breaker causes the enclave to immediately + /// EEXIT. + fn attacked(&mut self) -> ! { + self.exit(1) + } + + #[inline] + fn unknown_syscall( + &mut self, + _a: Register, + _b: Register, + _c: Register, + _d: Register, + _e: Register, + _f: Register, + nr: usize, + ) { + debugln!(self, "unsupported syscall: {}", nr); + } + + fn trace(&mut self, name: &str, argc: usize) { + let argv = [ + self.gpr.rdi, + self.gpr.rsi, + self.gpr.rdx, + self.gpr.r10, + self.gpr.r8, + self.gpr.r9, + ]; + + debug!(self, "{}(", name); + for (i, arg) in argv[..argc].iter().copied().enumerate() { + let prefix = if i > 0 { ", " } else { "" }; + debug!(self, "{}0x{:x}", prefix, u64::from(arg)); + } + + debugln!(self, ")"); + } +} diff --git a/internal/shim-sgx/src/handler/enarx.rs b/internal/shim-sgx/src/handler/enarx.rs new file mode 100644 index 00000000..1369c8d9 --- /dev/null +++ b/internal/shim-sgx/src/handler/enarx.rs @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: Apache-2.0 + +use sallyport::syscall::{BaseSyscallHandler, EnarxSyscallHandler}; +use sallyport::untrusted::{UntrustedRef, UntrustedRefMut}; + +impl<'a> EnarxSyscallHandler for super::Handler<'a> { + // NOTE: The 'nonce' field is called 'hash' here, as it is used to pass in + // a hash of a public key from the client that is to be embedded in the Quote. + // For more on this syscall, see: https://github.com/enarx/enarx-keepldr/issues/31 + fn get_attestation( + &mut self, + _hash: UntrustedRef, + _hash_len: libc::size_t, + _buf: UntrustedRefMut, + _buf_len: libc::size_t, + ) -> sallyport::Result { + self.trace("get_att", 0); + + /* + // If hash is NULL ptr, it is a Quote size request; return expected Quote size + // without proxying to host. Otherwise get hash value. + let hash = match hash.validate_slice(hash_len, self) { + None => { + let rep: sallyport::Reply = Ok([SGX_QUOTE_SIZE.into(), SGX_TECH.into()]).into(); + return sallyport::Result::from(rep); + } + Some(h) => { + if h.len() != 64 { + return Err(libc::EINVAL); + } + let mut hash = [0u8; 64]; + hash.copy_from_slice(h); + hash + } + }; + + // Used internally for buffer size to host when getting TargetInfo + const REPORT_LEN: usize = 512; + + // Validate output buf memory + let buf = buf.validate_slice(buf_len, self).ok_or(libc::EFAULT)?; + + // Request TargetInfo from host by passing nonce as 0 + let c = self.new_cursor(); + let (_, shim_buf_ptr) = c.alloc::(buf_len).or(Err(libc::EMSGSIZE))?; + let req = request!(SYS_ENARX_GETATT => 0, 0, shim_buf_ptr.as_ptr(), REPORT_LEN); + unsafe { self.proxy(req)? }; + + // Retrieve TargetInfo from sallyport block and call EREPORT to + // create Report from TargetInfo. + let mut ti = [0u8; 512]; + let ti_len = ti.len(); + let c = self.new_cursor(); + + unsafe { + c.copy_into_slice(buf_len, &mut ti[..ti_len]) + .or(Err(libc::EFAULT))?; + } + + // Cannot generate a Report from dummy values + if ti.eq(&SGX_DUMMY_TI) { + buf.copy_from_slice(&SGX_DUMMY_QUOTE); + let rep: sallyport::Reply = Ok([SGX_QUOTE_SIZE.into(), SGX_TECH.into()]).into(); + return sallyport::Result::from(rep); + } + + // Generate Report + let mut target_info: TargetInfo = Default::default(); + let mut f = [0u8; 8]; + let mut x = [0u8; 8]; + f.copy_from_slice(&ti[32..40]); + x.copy_from_slice(&ti[40..48]); + let f = u64::from_le_bytes(f); + let x = u64::from_le_bytes(x); + let att = Attributes::new( + Flags::from_bits(f).ok_or(libc::EBADMSG)?, + Xfrm::from_bits(x).ok_or(libc::EBADMSG)?, + ); + target_info.mrenclave.copy_from_slice(&ti[0..32]); + target_info.attributes = att; + let report: Report = unsafe { target_info.get_report(&ReportData(hash)) }; + + // Request Quote from host + let report_slice = &[report]; + let report_bytes = unsafe { + core::slice::from_raw_parts( + report_slice.as_ptr() as *const _ as *const u8, + core::mem::size_of::(), + ) + }; + + let c = self.new_cursor(); + let (c, shim_nonce_ptr) = c.copy_from_slice(report_bytes).or(Err(libc::EMSGSIZE))?; + let (_, shim_buf_ptr) = c.alloc::(buf_len).or(Err(libc::EMSGSIZE))?; + let req = request!(SYS_ENARX_GETATT => shim_nonce_ptr.as_ptr(), report_bytes.len(), shim_buf_ptr.as_ptr(), buf_len); + let result = unsafe { self.proxy(req)? }; + + // Pass Quote back to code layer in buf + let c = self.new_cursor(); + let (c, _) = c.alloc::(report_bytes.len()).or(Err(libc::EMSGSIZE))?; + + let result_len: usize = result[0].into(); + if result_len > buf_len { + self.attacked() + } + + unsafe { + c.copy_into_slice(buf_len, &mut buf[..result_len]) + .or(Err(libc::EFAULT))?; + } + */ + + let rep: sallyport::Reply = Err(libc::ENOSYS).into(); + sallyport::Result::from(rep) + } +} diff --git a/internal/shim-sgx/src/handler/file.rs b/internal/shim-sgx/src/handler/file.rs new file mode 100644 index 00000000..9f2bca5f --- /dev/null +++ b/internal/shim-sgx/src/handler/file.rs @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: Apache-2.0 + +use sallyport::request; +use sallyport::syscall::{BaseSyscallHandler, FileSyscallHandler}; +use sallyport::untrusted::{UntrustedRef, ValidateSlice}; + +impl<'a> FileSyscallHandler for super::Handler<'a> { + /// Do a readv() syscall + fn readv( + &mut self, + fd: libc::c_int, + iovec: UntrustedRef, + iovcnt: libc::c_int, + ) -> sallyport::Result { + self.trace("readv", 3); + + let mut size = 0usize; + let trusted = iovec.validate_slice(iovcnt, self).ok_or(libc::EFAULT)?; + + let c = self.new_cursor(); + + let (c, untrusted) = c + .copy_from_slice::(trusted) + .or(Err(libc::EMSGSIZE))?; + + let mut c = c; + for (t, u) in trusted.iter().zip(untrusted.iter_mut()) { + let (nc, us) = c.alloc::(t.iov_len).or(Err(libc::EMSGSIZE))?; + c = nc; + u.iov_base = us.as_mut_ptr() as _; + size += u.iov_len; + } + + let req = request!(libc::SYS_readv => fd, untrusted, untrusted.len()); + let ret = unsafe { self.proxy(req)? }; + + let mut read = ret[0].into(); + if size < read { + self.attacked(); + } + + let c = self.new_cursor(); + let (c, _) = c + .alloc::(trusted.len()) + .or(Err(libc::EMSGSIZE))?; + + let mut c = c; + for t in trusted.iter() { + let ts = t.iov_base as *mut u8; + let ts_len: usize = t.iov_len; + + let sz = core::cmp::min(ts_len, read); + + let nc = unsafe { c.copy_into_raw_parts(ts_len, ts, sz) }.or(Err(libc::EMSGSIZE))?; + c = nc; + + read -= sz; + } + + Ok(ret) + } + + /// Do a writev() syscall + fn writev( + &mut self, + fd: libc::c_int, + iovec: UntrustedRef, + iovcnt: libc::c_int, + ) -> sallyport::Result { + self.trace("writev", 3); + + let mut size = 0usize; + let trusted = iovec.validate_slice(iovcnt, self).ok_or(libc::EFAULT)?; + let c = self.new_cursor(); + let (c, untrusted) = c + .copy_from_slice::(trusted) + .or(Err(libc::EMSGSIZE))?; + + let mut c = c; + for (t, mut u) in trusted.iter().zip(untrusted.iter_mut()) { + let (nc, us) = unsafe { c.copy_from_raw_parts(t.iov_base as *const u8, t.iov_len) } + .or(Err(libc::EMSGSIZE))?; + c = nc; + u.iov_base = us as _; + size += u.iov_len; + } + + let req = request!(libc::SYS_writev => fd, untrusted, untrusted.len()); + let ret = unsafe { self.proxy(req)? }; + + if size < ret[0].into() { + self.attacked(); + } + + Ok(ret) + } +} diff --git a/internal/shim-sgx/src/handler/memory.rs b/internal/shim-sgx/src/handler/memory.rs new file mode 100644 index 00000000..f30acf1b --- /dev/null +++ b/internal/shim-sgx/src/handler/memory.rs @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: Apache-2.0 + +use sallyport::syscall::{BaseSyscallHandler, MemorySyscallHandler}; +use sallyport::untrusted::UntrustedRef; + +impl<'a> MemorySyscallHandler for super::Handler<'a> { + /// Do a brk() system call + fn brk(&mut self, addr: *const u8) -> sallyport::Result { + self.trace("brk", 1); + + let ret = self.heap.brk(addr as _); + Ok([ret.into(), Default::default()]) + } + + /// Do a mprotect() system call + // Until EDMM, we can't change any page permissions. + // What you get is what you get. Fake success. + fn mprotect( + &mut self, + _addr: UntrustedRef, + _len: libc::size_t, + _prot: libc::c_int, + ) -> sallyport::Result { + self.trace("mprotect", 3); + + Ok(Default::default()) + } + + /// Do a mmap() system call + fn mmap( + &mut self, + addr: UntrustedRef, + length: libc::size_t, + prot: libc::c_int, + flags: libc::c_int, + fd: libc::c_int, + offset: libc::off_t, + ) -> sallyport::Result { + self.trace("mmap", 6); + + let ret = self.heap.mmap::( + addr.as_ptr() as _, + length, + prot, + flags, + fd, // Allow truncation! + offset, + )?; + + Ok([ret.into(), Default::default()]) + } + + /// Do a munmap() system call + fn munmap(&mut self, addr: UntrustedRef, length: libc::size_t) -> sallyport::Result { + self.trace("munmap", 2); + + self.heap + .munmap::(addr.as_ptr() as _, length)?; + Ok(Default::default()) + } + + // Do madvise syscall + // We don't actually support this. So, fake success. + fn madvise( + &mut self, + _addr: *const libc::c_void, + _length: libc::size_t, + _advice: libc::c_int, + ) -> sallyport::Result { + self.trace("madvise", 3); + Ok(Default::default()) + } +} diff --git a/internal/shim-sgx/src/handler/mod.rs b/internal/shim-sgx/src/handler/mod.rs new file mode 100644 index 00000000..a0d96d80 --- /dev/null +++ b/internal/shim-sgx/src/handler/mod.rs @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: Apache-2.0 + +macro_rules! debug { + ($dst:expr, $($arg:tt)*) => { + #[allow(unused_must_use)] { + if $crate::DEBUG { + use core::fmt::Write; + write!($dst, $($arg)*); + } + } + }; +} + +macro_rules! debugln { + ($dst:expr) => { debugln!($dst,) }; + ($dst:expr, $($arg:tt)*) => { + #[allow(unused_must_use)] { + if $crate::DEBUG { + use core::fmt::Write; + writeln!($dst, $($arg)*); + } + } + }; +} + +mod base; +mod enarx; +mod file; +mod memory; +mod other; +mod process; + +use crate::ssa::{Gpr, Vector}; + +use core::fmt::Write; + +use enarx_heap::Heap; +use lset::Line; +use sallyport::syscall::*; +use sallyport::{request, Block}; + +// Opcode constants, details in Volume 2 of the Intel 64 and IA-32 Architectures Software +// Developer's Manual +const OP_SYSCALL: &[u8] = &[0x0f, 0x05]; +const OP_CPUID: &[u8] = &[0x0f, 0xa2]; + +pub struct Handler<'a> { + block: &'a mut Block, + gpr: &'a mut Gpr, + heap: Heap, +} + +impl<'a> Write for Handler<'a> { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + if s.as_bytes().is_empty() { + return Ok(()); + } + + let c = self.new_cursor(); + let (_, untrusted) = c.copy_from_slice(s.as_bytes()).or(Err(core::fmt::Error))?; + + let req = request!(libc::SYS_write => libc::STDERR_FILENO, untrusted, untrusted.len()); + let res = unsafe { self.proxy(req) }; + + match res { + Ok(res) if usize::from(res[0]) > s.bytes().len() => self.attacked(), + Ok(res) if usize::from(res[0]) == s.bytes().len() => Ok(()), + _ => Err(core::fmt::Error), + } + } +} + +impl<'a> Handler<'a> { + fn new(gpr: &'a mut Gpr, block: &'a mut Block, heap: Line) -> Self { + Self { + gpr, + block, + heap: unsafe { Heap::new(heap.into()) }, + } + } + + /// Finish handling an exception + pub fn finish(gpr: &'a mut Gpr) { + if let Some(Vector::InvalidOpcode) = gpr.exitinfo.exception() { + if let OP_SYSCALL | OP_CPUID = unsafe { gpr.rip.into_slice(2usize) } { + // Skip the instruction. + let rip = usize::from(gpr.rip); + gpr.rip = (rip + 2).into(); + return; + } + } + + unsafe { asm!("ud2", options(noreturn)) }; + } + + /// Handle an exception + pub fn handle(gpr: &'a mut Gpr, block: &'a mut Block, heap: Line) { + let mut h = Self::new(gpr, block, heap); + + match h.gpr.exitinfo.exception() { + Some(Vector::InvalidOpcode) => match unsafe { h.gpr.rip.into_slice(2usize) } { + OP_SYSCALL => h.handle_syscall(), + OP_CPUID => h.handle_cpuid(), + r => { + debugln!(h, "unsupported opcode: {:?}", r); + h.exit(1) + } + }, + + _ => h.attacked(), + } + } + + fn handle_syscall(&mut self) { + let ret = self.syscall( + self.gpr.rdi.into(), + self.gpr.rsi.into(), + self.gpr.rdx.into(), + self.gpr.r10.into(), + self.gpr.r8.into(), + self.gpr.r9.into(), + self.gpr.rax.into(), + ); + + self.gpr.rip = (usize::from(self.gpr.rip) + 2).into(); + + match ret { + Err(e) => self.gpr.rax = (-e).into(), + Ok([rax, rdx]) => { + self.gpr.rax = rax.into(); + self.gpr.rdx = rdx.into(); + } + } + } + + fn handle_cpuid(&mut self) { + debug!( + self, + "cpuid({:08x}, {:08x})", + usize::from(self.gpr.rax), + usize::from(self.gpr.rcx) + ); + + self.block.msg.req = request!(SYS_ENARX_CPUID => self.gpr.rax, self.gpr.rcx); + + unsafe { + // prevent earlier writes from being moved beyond this point + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Release); + + asm!("cpuid"); + + // prevent later reads from being moved before this point + core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::Acquire); + + self.gpr.rax = self.block.msg.req.arg[0].into(); + self.gpr.rbx = self.block.msg.req.arg[1].into(); + self.gpr.rcx = self.block.msg.req.arg[2].into(); + self.gpr.rdx = self.block.msg.req.arg[3].into(); + } + + debugln!( + self, + " = ({:08x}, {:08x}, {:08x}, {:08x})", + usize::from(self.gpr.rax), + usize::from(self.gpr.rbx), + usize::from(self.gpr.rcx), + usize::from(self.gpr.rdx) + ); + + self.gpr.rip = (usize::from(self.gpr.rip) + 2).into(); + } +} diff --git a/internal/shim-sgx/src/handler/other.rs b/internal/shim-sgx/src/handler/other.rs new file mode 100644 index 00000000..cbb64931 --- /dev/null +++ b/internal/shim-sgx/src/handler/other.rs @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: Apache-2.0 + +use super::Handler; + +use sallyport::syscall::{NetworkSyscallHandler, SyscallHandler, SystemSyscallHandler}; +use sallyport::untrusted::AddressValidator; + +impl<'a> NetworkSyscallHandler for Handler<'a> {} +impl<'a> SystemSyscallHandler for Handler<'a> {} +impl<'a> SyscallHandler for Handler<'a> {} + +impl<'a> AddressValidator for Handler<'a> { + fn validate_const_mem_fn(&self, _ptr: *const (), _size: usize) -> bool { + // FIXME: https://github.com/enarx/enarx/issues/630 + true + } + + fn validate_mut_mem_fn(&self, _ptr: *mut (), _size: usize) -> bool { + // FIXME: https://github.com/enarx/enarx/issues/630 + true + } +} diff --git a/internal/shim-sgx/src/handler/process.rs b/internal/shim-sgx/src/handler/process.rs new file mode 100644 index 00000000..52dc6e71 --- /dev/null +++ b/internal/shim-sgx/src/handler/process.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: Apache-2.0 + +use sallyport::syscall::{BaseSyscallHandler, ProcessSyscallHandler}; +use sallyport::syscall::{ARCH_GET_FS, ARCH_GET_GS, ARCH_SET_FS, ARCH_SET_GS}; + +impl<'a> ProcessSyscallHandler for super::Handler<'a> { + /// Do an arch_prctl() syscall + fn arch_prctl(&mut self, code: libc::c_int, addr: libc::c_ulong) -> sallyport::Result { + self.trace("arch_prctl", 2); + + // TODO: Check that addr in %rdx does not point to an unmapped address + // and is not outside of the process address space. + match code { + ARCH_SET_FS => self.gpr.fsbase = addr.into(), + ARCH_SET_GS => self.gpr.gsbase = addr.into(), + ARCH_GET_FS => return Err(libc::ENOSYS), + ARCH_GET_GS => return Err(libc::ENOSYS), + _ => return Err(libc::EINVAL), + } + + Ok(Default::default()) + } +} diff --git a/internal/shim-sgx/src/hostlib.rs b/internal/shim-sgx/src/hostlib.rs deleted file mode 100644 index 25ee195b..00000000 --- a/internal/shim-sgx/src/hostlib.rs +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -// The common Layout for `enarx-keep-sgx` and `enarx-keep-sgx-shim` - -use lset::Line; - -/// The enclave layout -#[repr(C, align(4096))] -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] -pub struct Layout { - /// The boundaries of the enclave. - pub enclave: Line, - - /// The boundaries of the prefix. - pub prefix: Line, - - /// The boundaries of the code. - pub code: Line, - - /// The boundaries of the heap. - pub heap: Line, - - /// The boundaries of the stack. - pub stack: Line, - - /// The boundaries of the shim. - pub shim: Line, -} diff --git a/internal/shim-sgx/src/main.rs b/internal/shim-sgx/src/main.rs index 6f755cfe..1af2165a 100644 --- a/internal/shim-sgx/src/main.rs +++ b/internal/shim-sgx/src/main.rs @@ -48,80 +48,235 @@ pub extern "C" fn rust_eh_personality() { // ============== REAL CODE HERE =============== -macro_rules! debug { - ($dst:expr, $($arg:tt)*) => { - #[allow(unused_must_use)] { - use core::fmt::Write; - write!($dst, $($arg)*); - } - }; +mod entry; +mod handler; +mod ssa; + +use noted::noted; + +const DEBUG: bool = false; + +sallyport::declare_abi_version!(); + +const SSA_FRAME_SIZE: u32 = 1; +const ENCL_SIZE_BITS: u32 = 31; +const ENCL_SIZE: usize = 1 << ENCL_SIZE_BITS; + +noted! { + static NOTE_ENARX_SGX_SIZE<"enarx", 0x73677800>: u32 = ENCL_SIZE_BITS; + static NOTE_ENARX_SGX_SSAP<"enarx", 0x73677801>: u32 = SSA_FRAME_SIZE; } -macro_rules! debugln { - ($dst:expr) => { debugln!($dst,) }; - ($dst:expr, $($arg:tt)*) => { - #[allow(unused_must_use)] { - use core::fmt::Write; - writeln!($dst, $($arg)*); - } - }; +// NOTE: You MUST take the address of these symbols for them to work! +extern "C" { + static ENARX_EXEC_START: u8; + //static ENARX_EXEC_END: u8; + static ENARX_HEAP_START: u8; + static ENARX_HEAP_END: u8; } -mod enclave; -mod entry; -mod event; -mod handler; -mod hostlib; +/// Clear CPU flags, extended state and temporary registers (`r10` and `r11`) +/// +/// This function clears CPU state during enclave transitions. +/// +/// # Safety +/// +/// This function should be safe as it only modifies non-preserved +/// registers. In fact, in addition to the declared calling convention, +/// we promise not to modify any of the parameter registers. +#[naked] +extern "sysv64" fn clearx() { + use const_default::ConstDefault; + static XSAVE: xsave::XSave = xsave::XSave::DEFAULT; -use hostlib::Layout; + unsafe { + asm!( + // Clear all temporary registers + "xor r10, r10", + "xor r11, r11", -sallyport::declare_abi_version!(); + // Clear CPU flags + "add r11, r11", + "cld", -use sallyport::Block; -use sgx::types::ssa::{Exception, StateSaveArea}; + // Clear the extended CPU state + "push rax ", // Save rax + "push rdx ", // Save rdx + "mov rdx, ~0 ", // Set mask for xrstor in rdx + "mov rax, ~0 ", // Set mask for xrstor in rax + "xrstor [rip + {XSAVE}]", // Clear xCPU state with synthetic state + "pop rdx ", // Restore rdx + "pop rax ", // Restore rax -// Opcode constants, details in Volume 2 of the Intel 64 and IA-32 Architectures Software -// Developer's Manual -const OP_SYSCALL: &[u8] = &[0x0f, 0x05]; -const OP_CPUID: &[u8] = &[0x0f, 0xa2]; + "ret", -#[repr(C)] -struct Context { - layout: hostlib::Layout, - ssa: [StateSaveArea], + XSAVE = sym XSAVE, + options(noreturn) + ) + } } -#[repr(C)] -struct Input { - cssa: usize, - ctx: &'static mut Context, +/// Clears parameter registers +/// +/// # Safety +/// +/// This function should be safe as it only modifies non-preserved +/// registers. It really doesn't even need to be a naked function +/// except that Rust tries really hard to put `rax` on the stack +/// and then pops it off into a random register (usually `rcx`). +#[naked] +extern "sysv64" fn clearp() { + unsafe { + asm!( + "xor rax, rax", + "xor rdi, rdi", + "xor rsi, rsi", + "xor rdx, rdx", + "xor rcx, rcx", + "xor r8, r8", + "xor r9, r9", + "ret", + options(noreturn) + ) + } +} + +/// Perform relocation +/// +/// # Safety +/// +/// This function does not follow any established calling convention. It +/// has the following requirements: +/// * `rsp` must point to a stack with the return address (i.e. `call`) +/// +/// Upon return, all general-purpose registers will have been preserved. +#[naked] +unsafe extern "sysv64" fn relocate() { + asm!( + "push rax", + "push rdi", + "push rsi", + "push rdx", + "push rcx", + "push r8", + "push r9", + "push r10", + "push r11", + + "lea rdi, [rip + _DYNAMIC]", // rdi = address of _DYNAMIC section + "mov rsi, -{SIZE} ", // rsi = enclave start address mask + "and rsi, rdi ", // rsi = relocation address + "call {DYN_RELOC} ", // relocate the dynamic symbols + + "pop r11", + "pop r10", + "pop r9", + "pop r8", + "pop rcx", + "pop rdx", + "pop rsi", + "pop rdi", + "pop rax", + + "ret", + + SIZE = const ENCL_SIZE, + DYN_RELOC = sym rcrt1::dyn_reloc, + options(noreturn) + ) +} + +/// Entry point +/// +/// This function is called during EENTER. Its inputs are as follows: +/// +/// rax = The current SSA index. (i.e. rbx->cssa) +/// rbx = The address of the TCS. +/// rcx = The next address after the EENTER instruction. +/// +/// If rax == 0, we are doing normal execution. +/// Otherwise, we are handling an exception. +/// +/// # Safety +/// +/// Do not call this function from Rust. It is the entry point for SGX. +#[naked] +#[no_mangle] +pub unsafe extern "sysv64" fn _start() -> ! { + // The constant for ENCLU[EEXIT] + const EEXIT: u64 = 4; + + // GPRO = offset_of!(StateSaveArea, gpr); + const GPRO: u64 = 4096 - 184; + + // RSPO = offset_of!(StateSaveArea, gpr.rsp); + const RSPO: u64 = GPRO + 32; + + asm!( + "xchg rbx, rcx ", // rbx = exit address, rcx = TCS page + + // Find stack pointer for CSSA == 0 + "cmp rax, 0 ", // If CSSA > 0 + "jne 2f ", // ... jump to the next section + "mov r10, rcx ", // r10 = stack pointer + "jmp 3f ", // Jump to stack setup + + // Find stack pointer for CSSA > 0 + "2: ", + "mov r10, rax ", // r10 = CSSA + "shl r10, 12 ", // r10 = CSSA * 4096 + "mov r10, [rcx + r10 + {RSPO}]", // r10 = SSA[CSSA - 1].gpr.rsp + "sub r10, 128 ", // Skip the red zone + + // Setup the stack + "3: ", + "and r10, ~0xf ", // Align the stack + "xchg rsp, r10 ", // Swap r10 and rsp + "sub rsp, 8 ", // Align the stack + "push r10 ", // Store old stack + + // Do relocation if CSSA == 0 + "cmp rax, 0 ", // If CSSA > 0 + "jne 4f ", // ... jump to the next section + "call {RELOC} ", // Relocate symbols + + // Clear, call Rust, clear + "4: ", // rdi = &mut sallyport::Block (passthrough) + "lea rsi, [rcx + 4096] ", // rsi = &mut [StateSaveArea; N] + "mov rdx, rax ", // rdx = CSSA + "call {CLEARX} ", // Clear CPU state + "call {ENTRY} ", // Jump to Rust + "call {CLEARX} ", // Clear CPU state + "call {CLEARP} ", // Clear parameter registers + + // Exit + "pop rsp ", // Restore old stack + "mov rax, {EEXIT} ", // rax = EEXIT + "enclu ", // Exit enclave + + CLEARX = sym clearx, + CLEARP = sym clearp, + RELOC = sym relocate, + ENTRY = sym main, + EEXIT = const EEXIT, + RSPO = const RSPO, + options(noreturn) + ) } -#[allow(unreachable_code)] -extern "C" fn main( - _rdi: usize, - _rsi: usize, - rdx: &mut Block, - rcx: &mut Input, - _r8: usize, - _r9: usize, +unsafe extern "C" fn main( + port: &mut sallyport::Block, + ssas: &mut [ssa::StateSaveArea; 3], + cssa: usize, ) { - match rcx.cssa { - 0 => entry::entry(&rcx.ctx.layout), - 1 => event::event(&rcx.ctx.layout, &mut rcx.ctx.ssa[0], rdx), - n => { - let gpr = &mut rcx.ctx.ssa[n - 1].gpr; - - if let Some(Exception::InvalidOpcode) = gpr.exitinfo.exception() { - if let OP_SYSCALL | OP_CPUID = unsafe { gpr.rip.into_slice(2usize) } { - // Skip the instruction. - let rip = usize::from(gpr.rip); - gpr.rip = (rip + 2).into(); - return; - } - } - - unreachable!() - } + let heap = lset::Line::new( + &ENARX_HEAP_START as *const _ as usize, + &ENARX_HEAP_END as *const _ as usize, + ); + + match cssa { + 0 => entry::entry(&ENARX_EXEC_START as *const u8 as _), + 1 => handler::Handler::handle(&mut ssas[0].gpr, port, heap), + n => handler::Handler::finish(&mut ssas[n - 1].gpr), } } diff --git a/internal/shim-sgx/src/ssa.rs b/internal/shim-sgx/src/ssa.rs new file mode 100644 index 00000000..271e1156 --- /dev/null +++ b/internal/shim-sgx/src/ssa.rs @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: Apache-2.0 + +use core::mem::size_of; + +use primordial::{Page, Register}; +use xsave::XSave; + +pub use x86_64::InterruptVector as Vector; + +/// Section 38.9.1.1, Table 38-9 +#[repr(C, align(4))] +#[derive(Copy, Clone)] +pub struct ExitInfo { + vector: Vector, + exit_type: u8, + reserved: u8, + valid: u8, +} + +impl ExitInfo { + const VALID: u8 = 1 << 7; + + /// Returns the exception type, if any. + pub fn exception(self) -> Option { + if self.valid != Self::VALID { + return None; + } + + Some(self.vector) + } +} + +/// Section 38.9.1, Table 38-8 +#[repr(C)] +pub struct Gpr { + /// Register rax + pub rax: Register, + + /// Register rcx + pub rcx: Register, + + /// Register rdx + pub rdx: Register, + + /// Register rbx + pub rbx: Register, + + /// Register rsp + pub rsp: Register, + + /// Register rbp + pub rbp: Register, + + /// Register rsi + pub rsi: Register, + + /// Register rdi + pub rdi: Register, + + /// Register r8 + pub r8: Register, + + /// Register r9 + pub r9: Register, + + /// Register r10 + pub r10: Register, + + /// Register r11 + pub r11: Register, + + /// Register r12 + pub r12: Register, + + /// Register r13 + pub r13: Register, + + /// Register r14 + pub r14: Register, + + /// Register r15 + pub r15: Register, + + /// Register flags + pub rflags: Register, + + /// Register rip + pub rip: Register, + + /// Register ursp + pub ursp: Register, + + /// Register urbp + pub urbp: Register, + + /// ExitInfo struct + pub exitinfo: ExitInfo, + + /// Reserved + pub reserved: u32, + + /// FS base + pub fsbase: Register, + + /// GS base + pub gsbase: Register, +} + +/// Section 38.9.2.1, Table 38-12 +#[derive(Debug)] +#[repr(C)] +struct ExceptionInfo { + /// In case of a page fault, contains the linear address that caused the fault. + maddr: u64, + + /// Exception error code for GP fault or page fault. + errcd: u32, + + reserved: u32, +} + +/// Section 38.9.2, Table 38-11 +#[derive(Debug)] +#[repr(C)] +pub struct Miscellaneous { + /// Exception info for GP or page fault occurring inside an enclave can be written to + /// this struct under some conditions (see Table 38.11). + exinfo: ExceptionInfo, +} + +/// When an AEX occurs while running in an enclave, the architectural state is saved +/// in the thread’s current StateSaveArea (SSA Frame), which is pointed to by TCS.CSSA. +/// +/// Section 38.9, Table 38-7 +#[repr(C, align(4096))] +pub struct StateSaveArea { + /// Area for saving and restoring the XSAVE-managed state components + pub xsave: XSave, + + /// Padding + pub reserved: [u8; Self::padding()], + + /// Contains Exception Info (error condition, memory address) + pub misc: Miscellaneous, + + /// Contains Exit Info (exit and exception type) + pub gpr: Gpr, +} + +impl StateSaveArea { + const fn padding() -> usize { + Page::SIZE - size_of::() - size_of::() - size_of::() + } +} diff --git a/src/backend/kvm/vm/mod.rs b/src/backend/kvm/vm/mod.rs index 94021c1c..fb0b1dbf 100644 --- a/src/backend/kvm/vm/mod.rs +++ b/src/backend/kvm/vm/mod.rs @@ -42,7 +42,7 @@ pub struct Vm { impl Vm

{ pub fn add_memory(&mut self, pages: usize) -> Result { - let mem_size = pages * Page::size(); + let mem_size = pages * Page::SIZE; let last_region = self.regions.last().unwrap().as_guest(); let map = Map::map(mem_size as usize) diff --git a/src/backend/sgx/mod.rs b/src/backend/sgx/mod.rs index 6531c58f..e7c28c47 100644 --- a/src/backend/sgx/mod.rs +++ b/src/backend/sgx/mod.rs @@ -2,77 +2,94 @@ use crate::backend::sgx::attestation::get_attestation; use crate::backend::{Command, Datum, Keep}; -use crate::binary::Component; -use sallyport::syscall::{SYS_ENARX_CPUID, SYS_ENARX_GETATT}; -use sallyport::Block; +use crate::binary::*; use anyhow::Result; +use goblin::elf::program_header::*; use lset::{Line, Span}; -use primordial::Page; -use sgx::enclave::{Builder, Enclave, Entry, Registers, Segment}; -use sgx::types::{ - page::{Flags, SecInfo}, - ssa::Exception, - tcs::Tcs, -}; +use primordial::{Page, Pages}; +use sallyport::syscall::{SYS_ENARX_CPUID, SYS_ENARX_GETATT}; +use sallyport::Block; +use sgx::crypto::Hasher; +use sgx::enclave::{Builder, Enclave, Entry, InterruptVector, Registers}; +use sgx::loader::{self, Loader}; +use sgx::types::page::{Class, Flags, SecInfo}; +use sgx::types::sig::{Author, Parameters}; use std::arch::x86_64::__cpuid_count; use std::convert::TryInto; +use std::fmt::Debug; +use std::num::NonZeroU32; use std::path::Path; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; mod attestation; mod data; -mod shim; -use goblin::elf::program_header::*; -use std::cmp::min; -use std::ops::Range; -fn program_header_2_segment(file: impl AsRef<[u8]>, ph: &ProgramHeader) -> Segment { - let mut rwx = Flags::empty(); +struct Segment { + fline: Line, + mline: Line, + pages: Pages>, + vpage: usize, + sinfo: SecInfo, + flags: flagset::FlagSet, +} - if ph.is_read() { - rwx |= Flags::R; - } - if ph.is_write() { - rwx |= Flags::W; +impl Debug for Segment { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let letter = |b, c| if b { c } else { ' ' }; + + f.write_fmt(format_args!( + "Segment({:08x}:{:08x} => {:08x}:{:08x} => {:08x}:{:08x} {}{}{}{}{})", + self.fline.start, + self.fline.end, + self.mline.start, + self.mline.end, + self.vpage * Page::SIZE, + self.vpage * Page::SIZE + self.pages.len() * Page::SIZE, + letter(self.sinfo.flags.contains(Flags::R), 'r'), + letter(self.sinfo.flags.contains(Flags::W), 'w'), + letter(self.sinfo.flags.contains(Flags::X), 'x'), + letter(self.sinfo.class == Class::Tcs, 't'), + letter(self.flags.contains(loader::Flags::Measure), 'm'), + )) } - if ph.is_executable() { - rwx |= Flags::X; - } - - let src = Span::from(ph.file_range()); - - let unaligned = Line::from(ph.vm_range()); - - let frame = Line { - start: unaligned.start / Page::size(), - end: (unaligned.end + Page::size() - 1) / Page::size(), - }; +} - let aligned = Line { - start: frame.start * Page::size(), - end: frame.end * Page::size(), - }; +impl Segment { + pub fn new(component: &Component, phdr: &ProgramHeader, relocate: usize) -> Self { + assert_eq!(relocate % Page::SIZE, 0); - let subslice = Span::from(Line { - start: unaligned.start - aligned.start, - end: unaligned.end - aligned.start, - }); + let fline = Line::from(phdr.file_range()); + let mline = Line::from(phdr.vm_range()) >> relocate; + let skipb = mline.start % Page::SIZE; + let vpage = mline.start / Page::SIZE; - let subslice = Range::from(Span { - start: subslice.start, - count: min(subslice.count, src.count), - }); + let mspan = Span::from(mline); + let bytes = &component.bytes[phdr.file_range()]; + let pages = Pages::copy_into(bytes, mspan.count, skipb); - let src = &file.as_ref()[Range::from(src)]; - let mut buf = vec![Page::default(); Span::from(frame).count]; - unsafe { buf.align_to_mut() }.1[subslice].copy_from_slice(src); + let mut rwx = Flags::empty(); + for (input, output) in [(PF_R, Flags::R), (PF_W, Flags::W), (PF_X, Flags::X)] { + if phdr.p_flags & input == input { + rwx |= output; + } + } - Segment { - si: SecInfo::reg(rwx), - dst: aligned.start, - src: buf, + Self { + fline, + mline, + pages, + vpage, + sinfo: match phdr.p_flags & PF_ENARX_SGX_TCS { + 0 => SecInfo::reg(rwx), + _ => SecInfo::tcs(), + }, + flags: match phdr.p_flags & PF_ENARX_SGX_UNMEASURED { + 0 => loader::Flags::Measure.into(), + _ => None.into(), + }, + } } } @@ -109,78 +126,54 @@ impl crate::backend::Backend for Backend { code: Component, _sock: Option<&Path>, ) -> Result> { - // Calculate the memory layout for the enclave. - let layout = crate::backend::sgx::shim::Layout::calculate(shim.region(), code.region()); + // Find the offset for loading the code. + let slot = Span::from(shim.find_header(PT_ENARX_CODE).unwrap().vm_range()); + assert!(Span::from(code.region()).count <= slot.count); - let mut shim_segs: Vec<_> = shim - .filter_header(PT_LOAD) - .map(|v| program_header_2_segment(shim.bytes, v)) - .collect(); + // Find the size of the enclave (in powers of two). + let size: u32 = unsafe { shim.read_note("enarx", NOTE_ENARX_SGX_SIZE)?.unwrap() }; + let size = 1 << size; - let mut code_segs: Vec<_> = code - .filter_header(PT_LOAD) - .map(|v| program_header_2_segment(code.bytes, v)) - .collect(); + // Find the number of pages in an SSA frame. + let ssap: u32 = unsafe { shim.read_note("enarx", NOTE_ENARX_SGX_SSAP)?.unwrap() }; + let ssap = NonZeroU32::new(ssap).unwrap(); - // Relocate the shim binary. - let shim_entry = shim.elf.entry as usize + layout.shim.start; + // Get an array of all final segment (relative) locations. + let ssegs = shim + .filter_header(PT_LOAD) + .map(|phdr| Segment::new(&shim, phdr, 0)); + let csegs = code + .filter_header(PT_LOAD) + .map(|phdr| Segment::new(&code, phdr, slot.start)); + let mut segs: Vec<_> = ssegs.chain(csegs).collect(); - for seg in shim_segs.iter_mut() { - seg.dst += layout.shim.start; + // Ensure no segments overlap in memory. + segs.sort_unstable_by_key(|x| x.vpage); + for pair in segs.windows(2) { + assert!(pair[0].vpage + pair[0].pages.len() <= pair[1].vpage); } - // Relocate the code binary. - for seg in code_segs.iter_mut() { - seg.dst += layout.code.start; + // Initialize the new enclave. + let parameters = Parameters::default(); + let mut builder = Builder::new(size, ssap, parameters)?; + let mut hasher = Hasher::new(size, ssap, parameters); + + // Map all the pages. + for seg in segs { + builder.load(&seg.pages, seg.vpage, seg.sinfo, seg.flags)?; + hasher.load(seg.pages, seg.vpage, seg.sinfo, seg.flags)?; } - // Create SSAs and TCS. - let ssas = vec![Page::default(); 3]; - let tcs = Tcs::new( - shim_entry - layout.enclave.start, - Page::size() * 2, // SSAs after Layout (see below) - ssas.len() as _, - ); - - let internal = vec![ - // TCS - Segment { - si: SecInfo::tcs(), - dst: layout.prefix.start, - src: vec![Page::copy(tcs)], - }, - // Layout - Segment { - si: SecInfo::reg(Flags::R), - dst: layout.prefix.start + Page::size(), - src: vec![Page::copy(layout)], - }, - // SSAs - Segment { - si: SecInfo::reg(Flags::R | Flags::W), - dst: layout.prefix.start + Page::size() * 2, - src: ssas, - }, - // Heap - Segment { - si: SecInfo::reg(Flags::R | Flags::W | Flags::X), - dst: layout.heap.start, - src: vec![Page::default(); Span::from(layout.heap).count / Page::size()], - }, - // Stack - Segment { - si: SecInfo::reg(Flags::R | Flags::W), - dst: layout.stack.start, - src: vec![Page::default(); Span::from(layout.stack).count / Page::size()], - }, - ]; - - // Initiate the enclave building process. - let mut builder = Builder::new(layout.enclave).expect("Unable to create builder"); - builder.load(&internal)?; - builder.load(&shim_segs)?; - builder.load(&code_segs)?; - Ok(builder.build()?) + // Generate a signing key. + let exp = openssl::bn::BigNum::from_u32(3u32).unwrap(); + let key = openssl::rsa::Rsa::generate_with_e(3072, &exp)?; + + // Create the enclave signature + let vendor = Author::new(0, 0); + let signature = hasher.finish().sign(vendor, key)?; + + // Build the enclave. + Ok(builder.build(&signature)?) } fn measure(&self, _shim: Component, _code: Component) -> Result { @@ -188,9 +181,9 @@ impl crate::backend::Backend for Backend { } } -impl super::Keep for RwLock { +impl super::Keep for Enclave { fn spawn(self: Arc) -> Result>> { - let thread = match sgx::enclave::Thread::new(self) { + let thread = match self.spawn() { Some(thread) => thread, None => return Ok(None), }; @@ -246,9 +239,10 @@ impl Thread { impl super::Thread for Thread { fn enter(&mut self) -> Result { let prev = self.how; - self.registers.rdx = (&mut self.block).into(); + self.registers.rdi = (&mut self.block).into(); + self.how = match self.thread.enter(prev, &mut self.registers) { - Err(ei) if ei.trap == Exception::InvalidOpcode => Entry::Enter, + Err(ei) if ei.trap == InterruptVector::InvalidOpcode => Entry::Enter, Ok(_) => Entry::Resume, e => panic!("Unexpected AEX: {:?}", e), }; diff --git a/src/backend/sgx/shim.rs b/src/backend/sgx/shim.rs deleted file mode 100644 index ba86207e..00000000 --- a/src/backend/sgx/shim.rs +++ /dev/null @@ -1,78 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -use lset::{Contains as _, Span}; -use nbytes::bytes; - -const PREFIX: usize = bytes![4; MiB]; -const ALIGN: usize = bytes![2; MiB]; -const STACK: usize = bytes![8; MiB]; -const HEAP: usize = bytes![128; MiB]; -const SIZE: usize = bytes![64; GiB]; - -const fn lower(value: usize, boundary: usize) -> usize { - value / boundary * boundary -} - -const fn raise(value: usize, boundary: usize) -> usize { - lower(value + boundary - 1, boundary) -} - -fn above(rel: impl Into>, size: usize) -> Span { - Span { - start: raise(rel.into().end, ALIGN), - count: size, - } -} - -fn below(rel: impl Into>, size: usize) -> Span { - Span { - start: lower(rel.into().start - size, ALIGN), - count: size, - } -} - -include!("../../../internal/shim-sgx/src/hostlib.rs"); - -impl Layout { - /// Calculate the memory layout of the SGX keep - pub fn calculate(shim: Line, code: Line) -> Self { - assert_eq!(shim.start, 0); - - let shim: Line = above( - Span { - start: bytes!(32; TiB) + bytes!(63;GiB), - count: 0, - }, - Span::from(shim).count, - ) - .into(); - - let enclave = Line::from(Span { - start: lower(shim.end, SIZE), - count: SIZE, - }); - - assert!(enclave.contains(&shim.start)); - assert!(enclave.contains(&shim.end)); - assert_eq!(code.start, 0); - - let prefix = Span { - start: enclave.start, - count: PREFIX, - } - .into(); - let code = above(prefix, Span::from(code).count); - let heap = above(code, HEAP); - let stack = below(shim, STACK); - - Self { - enclave, - - prefix, - code: code.into(), - heap: heap.into(), - stack: stack.into(), - shim, - } - } -} diff --git a/src/binary/component.rs b/src/binary/component.rs index 074de1b0..f195d1ac 100644 --- a/src/binary/component.rs +++ b/src/binary/component.rs @@ -3,10 +3,9 @@ use anyhow::{anyhow, Result}; use goblin::elf::{header::*, program_header::*, Elf}; -use lset::Line; use sallyport::SALLYPORT_ABI_VERSION_BASE; -use std::cmp::{max, min}; +use std::ops::Range; #[allow(dead_code)] pub enum ComponentType { @@ -19,9 +18,24 @@ pub enum ComponentType { pub const PT_ENARX_SALLYPORT: u32 = PT_LOOS + 0x34a0001; /// The enarx code program header type -#[cfg(any(feature = "backend-kvm"))] pub const PT_ENARX_CODE: u32 = PT_LOOS + 0x34a0003; +/// This segment contains TCS pages. +#[cfg(feature = "backend-sgx")] +pub const PF_ENARX_SGX_TCS: u32 = 1 << 20; + +/// This segment contains unmeasured pages. +#[cfg(feature = "backend-sgx")] +pub const PF_ENARX_SGX_UNMEASURED: u32 = 1 << 21; + +/// This note indicates the SGX enclave size (u32; in powers of 2) +#[cfg(feature = "backend-sgx")] +pub const NOTE_ENARX_SGX_SIZE: u32 = 0x73677800; + +/// This note indicates the number of pages in an SSA frame (u32) +#[cfg(feature = "backend-sgx")] +pub const NOTE_ENARX_SGX_SSAP: u32 = 0x73677801; + pub struct Component<'a> { pub bytes: &'a [u8], pub elf: Elf<'a>, @@ -113,13 +127,37 @@ impl<'a> Component<'a> { } /// Find the total memory region for the binary. - #[allow(dead_code)] - pub fn region(&self) -> Line { - self.filter_header(PT_LOAD) - .map(|x| Line::from(x.vm_range())) - .fold(usize::max_value()..usize::min_value(), |l, r| { - min(l.start, r.start)..max(l.end, r.end) - }) - .into() + pub fn region(&self) -> Range { + let lo = self + .filter_header(PT_LOAD) + .map(|phdr| phdr.vm_range().start) + .min(); + + let hi = self + .filter_header(PT_LOAD) + .map(|phdr| phdr.vm_range().end) + .max(); + + lo.unwrap_or_default()..hi.unwrap_or_default() + } + + /// Read a note from the note section + #[cfg(feature = "backend-sgx")] + pub unsafe fn read_note(&self, name: &str, kind: u32) -> Result> { + use std::mem::size_of; + + let headers = match self.elf.iter_note_headers(self.bytes) { + Some(headers) => headers, + None => return Ok(None), + }; + + for note in headers { + let note = note?; + if note.name == name && note.n_type == kind && note.desc.len() == size_of::() { + return Ok(Some(note.desc.as_ptr().cast::().read_unaligned())); + } + } + + Ok(None) } }