From 2ef82e8e3faadc2ee31b20781ad6026c95586128 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Mon, 11 Sep 2023 15:42:36 -0700 Subject: [PATCH 1/5] attest: Simplify error generation when the cert len overflows u32. --- task/attest/src/main.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/task/attest/src/main.rs b/task/attest/src/main.rs index 09feecb53..65427587d 100644 --- a/task/attest/src/main.rs +++ b/task/attest/src/main.rs @@ -192,11 +192,7 @@ impl idl::InOrderAttestImpl for AttestServer { let len = self.get_cert_bytes_from_index(index)?.len(); ringbuf_entry!(Trace::CertLen(len)); - let len = u32::try_from(len).map_err(|_| { - >>::into( - AttestError::CertTooBig, - ) - })?; + let len = u32::try_from(len).map_err(|_| AttestError::CertTooBig)?; Ok(len) } From e8c1159f643809a0525961a2f922239a27551644 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Wed, 30 Aug 2023 17:35:52 -0700 Subject: [PATCH 2/5] attest: Replace use of ArrayVec w/ custom type. ArrayVec wants to be serialized as a sequence and that's not compatible with hubpack. --- task/attest/src/main.rs | 61 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/task/attest/src/main.rs b/task/attest/src/main.rs index 65427587d..d45f277a6 100644 --- a/task/attest/src/main.rs +++ b/task/attest/src/main.rs @@ -11,7 +11,6 @@ mod config; -use arrayvec::ArrayVec; use attest_api::{AttestError, HashAlgorithm}; use config::DataRegion; use core::slice; @@ -84,12 +83,22 @@ const SHA3_256_DIGEST_SIZE: usize = // the number of Measurements we can record const CAPACITY: usize = 16; +// Digest is a fixed length array of bytes #[derive(Clone, Copy, Debug, PartialEq)] struct Digest([u8; N]); +impl Default for Digest { + fn default() -> Self { + Digest([0u8; N]) + } +} + +type Sha3_256Digest = Digest; + +// Measurement is an enum that can hold any of the supported hash algorithms #[derive(Clone, Copy, Debug, PartialEq)] enum Measurement { - Sha3_256(Digest), + Sha3_256(Sha3_256Digest), } impl Measurement { @@ -104,7 +113,7 @@ impl Measurement { return Err(AttestError::BadLease.into()); } - let mut digest = Digest([0u8; SHA3_256_DIGEST_SIZE]); + let mut digest = Sha3_256Digest::default(); data.read_range(0..digest.0.len(), &mut digest.0) .map_err(|_| RequestError::went_away())?; @@ -114,10 +123,52 @@ impl Measurement { } } +impl Default for Measurement { + fn default() -> Self { + Measurement::Sha3_256(Sha3_256Digest::default()) + } +} + +// Would have been nice to use ArrayVec but it's particularly difficult to +// use with hubpack. +struct Log { + index: usize, + measurements: [Measurement; N], +} + +impl Log { + fn is_full(&self) -> bool { + if self.index == N { + true + } else { + false + } + } + + fn push(&mut self, measurement: Measurement) -> bool { + if !self.is_full() { + self.measurements[self.index] = measurement; + self.index += 1; + true + } else { + false + } + } +} + +impl Default for Log { + fn default() -> Self { + Self { + index: 0, + measurements: [Measurement::default(); N], + } + } +} + struct AttestServer { alias_data: Option, cert_data: Option, - measurements: ArrayVec, + measurements: Log, } impl Default for AttestServer { @@ -125,7 +176,7 @@ impl Default for AttestServer { Self { alias_data: load_data_from_region(&ALIAS_DATA), cert_data: load_data_from_region(&CERT_DATA), - measurements: ArrayVec::::new(), + measurements: Log::::default(), } } } From dc70793b6698aaf8c724c204350e1c7c055571d5 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Mon, 11 Sep 2023 14:46:58 -0700 Subject: [PATCH 3/5] attest: Add 'log' and 'log_len' to Attest idl & implementation. --- Cargo.lock | 81 +++++++++++++++++++++++++++++++----- app/lpc55xpresso/app.toml | 2 +- app/oxide-rot-1/app-dev.toml | 2 +- app/oxide-rot-1/app.toml | 2 +- app/rot-carrier/app.toml | 4 +- idl/attest.idol | 23 ++++++++++ task/attest-api/src/lib.rs | 4 +- task/attest/Cargo.toml | 2 + task/attest/src/main.rs | 74 +++++++++++++++++++++++++------- 9 files changed, 163 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 197d7c5cd..1ce23f873 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -537,8 +537,18 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "757c0ded2af11d8e739c4daea1ac623dd1624b06c844cf3f5a39f1bdbd99bb12" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.13.0", + "darling_macro 0.13.0", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", ] [[package]] @@ -555,17 +565,42 @@ dependencies = [ "syn 1.0.94", ] +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.29", +] + [[package]] name = "darling_macro" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade7bff147130fe5e6d39f089c6bd49ec0250f35d70b2eebf72afdfc919f15cc" dependencies = [ - "darling_core", + "darling_core 0.13.0", "quote", "syn 1.0.94", ] +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.29", +] + [[package]] name = "demo-stm32f4-discovery" version = "0.1.0" @@ -3146,7 +3181,7 @@ dependencies = [ "num-traits", "ron", "serde", - "serde_with", + "serde_with 1.11.0", ] [[package]] @@ -3522,9 +3557,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.147" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] @@ -3549,13 +3584,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 1.0.94", + "syn 2.0.29", ] [[package]] @@ -3597,7 +3632,17 @@ checksum = "ad6056b4cb69b6e43e3a0f055def223380baecc99da683884f205bf347f7c4b3" dependencies = [ "rustversion", "serde", - "serde_with_macros", + "serde_with_macros 1.5.1", +] + +[[package]] +name = "serde_with" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +dependencies = [ + "serde", + "serde_with_macros 3.3.0", ] [[package]] @@ -3606,12 +3651,24 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e" dependencies = [ - "darling", + "darling 0.13.0", "proc-macro2", "quote", "syn 1.0.94", ] +[[package]] +name = "serde_with_macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "sha2" version = "0.10.6" @@ -3934,9 +3991,11 @@ dependencies = [ "idol", "idol-runtime", "lib-dice", + "mutable-statics", "num-traits", "ringbuf", "serde", + "serde_with 3.3.0", "sha3", "stage0-handoff", "unwrap-lite", diff --git a/app/lpc55xpresso/app.toml b/app/lpc55xpresso/app.toml index d62195c81..465aeb828 100644 --- a/app/lpc55xpresso/app.toml +++ b/app/lpc55xpresso/app.toml @@ -142,7 +142,7 @@ extern-regions = ["sram2"] [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 13600, ram = 16384} +max-sizes = {flash = 14800, ram = 16384} stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index 27564f8d1..8f25936db 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -158,7 +158,7 @@ binary_path = "../../target/gimlet-c/dist/default/final.bin" [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 13600, ram = 16384} +max-sizes = {flash = 14800, ram = 16384} stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index 1ee9f2f55..5347a6797 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -137,7 +137,7 @@ task-slots = ["swd"] [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 13600, ram = 16384} +max-sizes = {flash = 14800, ram = 16384} stacksize = 9304 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index 320c993d0..10654f84d 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -204,8 +204,8 @@ binary_path = "../../target/gemini-bu/dist/final.bin" [tasks.attest] name = "task-attest" priority = 5 -max-sizes = {flash = 13600, ram = 16384} -stacksize = 9304 +max-sizes = {flash = 14800, ram = 16384} +stacksize = 9952 start = true extern-regions = ["dice_alias", "dice_certs"] diff --git a/idl/attest.idol b/idl/attest.idol index e28216d28..1baf4c0d4 100644 --- a/idl/attest.idol +++ b/idl/attest.idol @@ -55,5 +55,28 @@ Interface( ), encoding: Hubpack, ), + "log": ( + doc: "Get the measurement log", + args: { + "offset" : "u32", + }, + leases: { + "dest": (type: "[u8]", write: true), + }, + reply: Result( + ok: "()", + err: Complex("AttestError"), + ), + encoding: Hubpack, + ), + "log_len": ( + doc: "Get length of the serialized measurement log", + reply: Result( + ok: "u32", + err: Complex("AttestError"), + ), + encoding: Hubpack, + idempotent: true, + ), } ) diff --git a/task/attest-api/src/lib.rs b/task/attest-api/src/lib.rs index 309f7e480..9b6935063 100644 --- a/task/attest-api/src/lib.rs +++ b/task/attest-api/src/lib.rs @@ -18,10 +18,12 @@ pub enum AttestError { InvalidCertIndex, NoCerts, OutOfRange, - MeasurementLogFull, + LogFull, + LogTooBig, TaskRestarted, BadLease, UnsupportedAlgorithm, + SerializeLog, } impl From for AttestError { diff --git a/task/attest/Cargo.toml b/task/attest/Cargo.toml index 4702e1039..6f4d79a5c 100644 --- a/task/attest/Cargo.toml +++ b/task/attest/Cargo.toml @@ -9,9 +9,11 @@ crypto-common = { workspace = true } lib-dice = { path = "../../lib/dice" } hubpack = { workspace = true } idol-runtime = { workspace = true } +mutable-statics = { path = "../../lib/mutable-statics" } num-traits = { workspace = true } ringbuf = { path = "../../lib/ringbuf" } serde = { workspace = true } +serde_with = { version = "3.3.0", default-features = false, features = ["macros"] } stage0-handoff = { path = "../../lib/stage0-handoff" } attest-api = { path = "../attest-api" } sha3 = { workspace = true } diff --git a/task/attest/src/main.rs b/task/attest/src/main.rs index d45f277a6..3ba7862c6 100644 --- a/task/attest/src/main.rs +++ b/task/attest/src/main.rs @@ -18,8 +18,10 @@ use crypto_common::{typenum::Unsigned, OutputSizeUser}; use hubpack::SerializedSize; use idol_runtime::{ClientError, Leased, RequestError, W}; use lib_dice::{AliasData, CertData}; +use mutable_statics::mutable_statics; use ringbuf::{ringbuf, ringbuf_entry}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; use sha3::Sha3_256Core; use stage0_handoff::{HandoffData, HandoffDataLoadError}; use zerocopy::AsBytes; @@ -46,6 +48,8 @@ enum Trace { Startup, Record(HashAlgorithm), BadLease(usize), + LogLen(u32), + Log, None, } @@ -84,8 +88,9 @@ const SHA3_256_DIGEST_SIZE: usize = const CAPACITY: usize = 16; // Digest is a fixed length array of bytes -#[derive(Clone, Copy, Debug, PartialEq)] -struct Digest([u8; N]); +#[serde_as] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, SerializedSize)] +struct Digest(#[serde_as(as = "[_; N]")] [u8; N]); impl Default for Digest { fn default() -> Self { @@ -96,7 +101,7 @@ impl Default for Digest { type Sha3_256Digest = Digest; // Measurement is an enum that can hold any of the supported hash algorithms -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, SerializedSize)] enum Measurement { Sha3_256(Sha3_256Digest), } @@ -129,25 +134,24 @@ impl Default for Measurement { } } -// Would have been nice to use ArrayVec but it's particularly difficult to -// use with hubpack. +// ArrayVec has everything we need but isn't compatible with hubpack. We only +// need a small subset of its functionality so this saves us some flash. +#[serde_as] +#[derive(Serialize, SerializedSize)] struct Log { - index: usize, + index: u32, + #[serde_as(as = "[_; N]")] measurements: [Measurement; N], } impl Log { fn is_full(&self) -> bool { - if self.index == N { - true - } else { - false - } + self.index as usize == N } fn push(&mut self, measurement: Measurement) -> bool { if !self.is_full() { - self.measurements[self.index] = measurement; + self.measurements[self.index as usize] = measurement; self.index += 1; true } else { @@ -167,14 +171,19 @@ impl Default for Log { struct AttestServer { alias_data: Option, + buf: &'static mut [u8; Log::::MAX_SIZE], cert_data: Option, measurements: Log, } impl Default for AttestServer { fn default() -> Self { + let buf = mutable_statics! { + static mut LOG_BUF: [u8; Log::::MAX_SIZE] = [|| 0; _]; + }; Self { alias_data: load_data_from_region(&ALIAS_DATA), + buf, cert_data: load_data_from_region(&CERT_DATA), measurements: Log::::default(), } @@ -293,13 +302,50 @@ impl idl::InOrderAttestImpl for AttestServer { ringbuf_entry!(Trace::Record(algorithm)); if self.measurements.is_full() { - return Err(AttestError::MeasurementLogFull.into()); + return Err(AttestError::LogFull.into()); } self.measurements.push(Measurement::new(algorithm, data)?); Ok(()) } + + fn log( + &mut self, + _: &userlib::RecvMessage, + offset: u32, + dest: Leased, + ) -> Result<(), RequestError> { + ringbuf_entry!(Trace::Log); + + let offset = offset as usize; + let log_len = hubpack::serialize(self.buf, &self.measurements) + .map_err(|_| AttestError::SerializeLog)?; + + if log_len < offset || dest.len() > log_len - offset { + let err = AttestError::OutOfRange; + ringbuf_entry!(Trace::AttestError(err)); + return Err(err.into()); + } + + dest.write_range(0..dest.len(), &self.buf[offset..offset + dest.len()]) + .map_err(|_| RequestError::Fail(ClientError::WentAway))?; + + Ok(()) + } + + fn log_len( + &mut self, + _: &userlib::RecvMessage, + ) -> Result> { + let len = hubpack::serialize(self.buf, &self.measurements) + .map_err(|_| AttestError::SerializeLog)?; + let len = u32::try_from(len).map_err(|_| AttestError::LogTooBig)?; + + ringbuf_entry!(Trace::LogLen(len)); + + Ok(len) + } } #[export_name = "main"] From 8e1ec204d82bdca5aa941fb437d4e6a0f4151693 Mon Sep 17 00:00:00 2001 From: Philip Tricca Date: Tue, 12 Sep 2023 18:06:35 -0700 Subject: [PATCH 4/5] sprot: Expose log & log_len from the Attest task. --- app/oxide-rot-1/app-dev.toml | 2 +- app/oxide-rot-1/app.toml | 2 +- app/rot-carrier/app.toml | 2 +- drv/lpc55-sprot-server/src/handler.rs | 39 +++++++++++++++-- drv/sprot-api/src/lib.rs | 4 ++ drv/stm32h7-sprot-server/src/main.rs | 61 +++++++++++++++++++++++++++ idl/sprot.idol | 26 +++++++++++- 7 files changed, 128 insertions(+), 8 deletions(-) diff --git a/app/oxide-rot-1/app-dev.toml b/app/oxide-rot-1/app-dev.toml index 8f25936db..37f3d8893 100644 --- a/app/oxide-rot-1/app-dev.toml +++ b/app/oxide-rot-1/app-dev.toml @@ -77,7 +77,7 @@ task-slots = ["syscon_driver"] [tasks.sprot] name = "drv-lpc55-sprot-server" priority = 6 -max-sizes = {flash = 45792, ram = 32768} +max-sizes = {flash = 46300, ram = 32768} uses = ["flexcomm8", "bootrom"] features = ["spi0"] start = true diff --git a/app/oxide-rot-1/app.toml b/app/oxide-rot-1/app.toml index 5347a6797..889d66d67 100644 --- a/app/oxide-rot-1/app.toml +++ b/app/oxide-rot-1/app.toml @@ -68,7 +68,7 @@ task-slots = ["syscon_driver"] [tasks.sprot] name = "drv-lpc55-sprot-server" priority = 6 -max-sizes = {flash = 45792, ram = 32768} +max-sizes = {flash = 46300, ram = 32768} uses = ["flexcomm8", "bootrom"] features = ["spi0"] start = true diff --git a/app/rot-carrier/app.toml b/app/rot-carrier/app.toml index 10654f84d..7b048e6f0 100644 --- a/app/rot-carrier/app.toml +++ b/app/rot-carrier/app.toml @@ -108,7 +108,7 @@ task-slots = ["syscon_driver"] [tasks.sprot] name = "drv-lpc55-sprot-server" priority = 6 -max-sizes = {flash = 45792, ram = 32768} +max-sizes = {flash = 46300, ram = 32768} uses = ["flexcomm8", "bootrom"] features = ["spi0"] start = true diff --git a/drv/lpc55-sprot-server/src/handler.rs b/drv/lpc55-sprot-server/src/handler.rs index d76968e44..4526ab112 100644 --- a/drv/lpc55-sprot-server/src/handler.rs +++ b/drv/lpc55-sprot-server/src/handler.rs @@ -45,7 +45,8 @@ pub struct StartupState { /// Marker for data which should be copied after the packet is encoded pub enum TrailingData { Caboose { slot: SlotId, start: u32, size: u32 }, - Attest { index: u32, offset: u32, size: u32 }, + AttestCert { index: u32, offset: u32, size: u32 }, + AttestLog { offset: u32, size: u32 }, RotPage { page: RotPage }, } @@ -135,7 +136,7 @@ impl Handler { } } } - Some(TrailingData::Attest { + Some(TrailingData::AttestCert { index, offset, size, @@ -176,6 +177,27 @@ impl Handler { Err(e) => Response::pack(&Ok(e), tx_buf), } } + Some(TrailingData::AttestLog { offset, size }) => { + let size: usize = usize::try_from(size).unwrap_lite(); + if size > drv_sprot_api::MAX_BLOB_SIZE { + Response::pack( + &Err(SprotError::Protocol( + SprotProtocolError::BadMessageLength, + )), + tx_buf, + ) + } else { + match Response::pack_with_cb(&rsp_body, tx_buf, |buf| { + self.attest + .log(offset, &mut buf[..size]) + .map_err(|e| RspBody::Attest(Err(e)))?; + Ok(size) + }) { + Ok(size) => size, + Err(e) => Response::pack(&Ok(e), tx_buf), + } + } + } _ => Response::pack(&rsp_body, tx_buf), } } @@ -296,7 +318,7 @@ impl Handler { // the work can be done elsewhere. Ok(( RspBody::Attest(Ok(AttestRsp::Cert)), - Some(TrailingData::Attest { + Some(TrailingData::AttestCert { index, offset, size, @@ -334,6 +356,17 @@ impl Handler { Some(TrailingData::RotPage { page }), )) } + ReqBody::Attest(AttestReq::Log { offset, size }) => Ok(( + RspBody::Attest(Ok(AttestRsp::Log)), + Some(TrailingData::AttestLog { offset, size }), + )), + ReqBody::Attest(AttestReq::LogLen) => { + let rsp = match self.attest.log_len() { + Ok(l) => Ok(AttestRsp::LogLen(l)), + Err(e) => Err(e), + }; + Ok((RspBody::Attest(rsp), None)) + } } } } diff --git a/drv/sprot-api/src/lib.rs b/drv/sprot-api/src/lib.rs index 38a25d50e..70ea696b0 100644 --- a/drv/sprot-api/src/lib.rs +++ b/drv/sprot-api/src/lib.rs @@ -385,6 +385,8 @@ pub enum AttestReq { CertLen(u32), Cert { index: u32, offset: u32, size: u32 }, Record { algorithm: HashAlgorithm }, + Log { offset: u32, size: u32 }, + LogLen, } /// A response used for RoT updates @@ -410,6 +412,8 @@ pub enum AttestRsp { CertLen(u32), Cert, Record, + Log, + LogLen(u32), } /// The body of a sprot response. diff --git a/drv/stm32h7-sprot-server/src/main.rs b/drv/stm32h7-sprot-server/src/main.rs index f934f9840..f76fa2341 100644 --- a/drv/stm32h7-sprot-server/src/main.rs +++ b/drv/stm32h7-sprot-server/src/main.rs @@ -948,6 +948,67 @@ impl idl::InOrderSpRotImpl for ServerImpl { Err(e) => Err(e.into()), } } + + fn log( + &mut self, + _msg: &userlib::RecvMessage, + offset: u32, + data: idol_runtime::Leased, + ) -> Result<(), idol_runtime::RequestError> { + let body = ReqBody::Attest(AttestReq::Log { + offset, + size: data.len() as u32, + }); + let tx_size = Request::pack(&body, self.tx_buf); + let rsp = + self.do_send_recv_retries(tx_size, DUMP_TIMEOUT, DEFAULT_ATTEMPTS)?; + + match rsp.body { + Ok(RspBody::Attest(Ok(AttestRsp::Log))) => { + // Copy from the trailing data into the lease + if rsp.blob.len() < data.len() { + return Err(idol_runtime::RequestError::Fail( + idol_runtime::ClientError::BadLease, + )); + } + data.write_range(0..data.len(), &rsp.blob[..data.len()]) + .map_err(|()| { + idol_runtime::RequestError::Fail( + idol_runtime::ClientError::WentAway, + ) + })?; + Ok(()) + } + Ok(RspBody::Attest(Err(e))) => { + Err(AttestOrSprotError::Attest(e).into()) + } + Ok(RspBody::Attest(_)) | Ok(_) => Err(AttestOrSprotError::Sprot( + SprotError::Protocol(SprotProtocolError::UnexpectedResponse), + ) + .into()), + Err(e) => Err(AttestOrSprotError::Sprot(e).into()), + } + } + + fn log_len( + &mut self, + _msg: &userlib::RecvMessage, + ) -> Result> { + let body = ReqBody::Attest(AttestReq::LogLen); + let tx_size = Request::pack(&body, self.tx_buf); + let rsp = self.do_send_recv_retries(tx_size, TIMEOUT_QUICK, 1)?; + match rsp.body { + Ok(RspBody::Attest(Ok(AttestRsp::LogLen(s)))) => Ok(s), + Ok(RspBody::Attest(Err(e))) => { + Err(AttestOrSprotError::Attest(e).into()) + } + Ok(RspBody::Attest(_)) | Ok(_) => Err(AttestOrSprotError::Sprot( + SprotError::Protocol(SprotProtocolError::UnexpectedResponse), + ) + .into()), + Err(e) => Err(AttestOrSprotError::Sprot(e).into()), + } + } } mod idl { diff --git a/idl/sprot.idol b/idl/sprot.idol index 7c479bed2..2e2ae8f8d 100644 --- a/idl/sprot.idol +++ b/idl/sprot.idol @@ -234,6 +234,28 @@ Interface( encoding: Hubpack, idempotent: true, ), - - } + "log": ( + doc: "Get the measurement log", + args: { + "offset" : "u32", + }, + leases: { + "dest": (type: "[u8]", write: true), + }, + reply: Result( + ok: "()", + err: Complex("AttestOrSprotError"), + ), + encoding: Hubpack, + ), + "log_len": ( + doc: "Get length of the serialized measurement log", + reply: Result( + ok: "u32", + err: Complex("AttestOrSprotError"), + ), + encoding: Hubpack, + idempotent: true, + ), + } ) From 6d6daa6787004305098eab4f5f3e47e2f5032ba1 Mon Sep 17 00:00:00 2001 From: Kevin Ji <1146876+kevinji@users.noreply.github.com> Date: Wed, 16 Aug 2023 15:15:58 -0700 Subject: [PATCH 5/5] doc(tr1): syntax highlight Rust code --- doc/tr1.adoc | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/doc/tr1.adoc b/doc/tr1.adoc index c7d7a8303..80fc9d2c3 100644 --- a/doc/tr1.adoc +++ b/doc/tr1.adoc @@ -291,7 +291,8 @@ Here are some highlights. As with most operating systems, tasks can be in a number of states: stopped, runnable, blocked, etc. A common way to express this might be: -.... +[source,rust] +---- struct Task { state: State, // other stuff omitted @@ -302,14 +303,15 @@ enum State { Runnable, Blocked, } -.... +---- A fault event causes a task to no longer be schedulable, until the fault is resolved or the task is restarted. A fault cannot *replace* the task's state, because we want to remember it -- for debugging, at the least. And so we might be tempted to do this: -.... +[source,rust] +---- struct Task { state: State, fault: Option, @@ -326,19 +328,20 @@ enum Fault { MemoryAccess(Address), OtherReasons, } -.... +---- But this makes it really easy to schedule a faulted task _by accident,_ in a way that's hard to spot with local reasoning. Specifically: -.... +[source,rust] +---- for task in tasks { if task.state == State::Runnable { schedule(task); break; } } -.... +---- Looks correct! Is not correct. (The same issue could happen when replying to a blocked task, setting it runnable without noticing a fault.) @@ -349,7 +352,9 @@ but are _not_: a fault makes the other state temporarily irrelevant. We can express this at the type level to make this class of mistake much less likely: -.... + +[source,rust] +---- struct Task { state: HealthState, // other stuff omitted @@ -373,7 +378,7 @@ enum Fault { MemoryAccess(Address), OtherReasons, } -.... +---- That is, while the original `State` is preserved when a fault is taken, it's moved inside the `HealthState::Faulted` variant where it's structurally distinct @@ -382,14 +387,15 @@ from `Healthy`. Our scheduler loop above no longer compiles, because `task.state` is not a `State`. Instead, we write the code like this: -.... +[source,rust] +---- for task in tasks { if task.state == HealthState::Healthy(State::Runnable) { schedule(task); break; } } -.... +---- Any faulted state fails that equality test without further thought. @@ -412,14 +418,15 @@ the next scheduling round without checking. Hubris currently addresses this with the `NextTask` enum, which looks like this: -.... +[source,rust] +---- #[must_use] enum NextTask { Same, Specific(usize), Other, } -.... +---- An operation returns `NextTask` if it *may* affect scheduling. `Same` indicates that no context switch is required; `Specific(x)` indicates that a switch to a @@ -440,7 +447,8 @@ When two `NextTask` values meet, they can be combined; this provides better composition of operations than a simple "switch needed" flag. Combining two `NextTask` values works as follows (expressed as a Rust `match`): -.... +[source,rust] +---- match (self, other) { // If both agree, our job is easy. (x, y) if x == y => x, @@ -454,7 +462,7 @@ match (self, other) { // All we have left is... (Same, Same) => Same, } -.... +---- (That's copied verbatim from the kernel source.)