From cefc93a70ef36618cd171542e773ab3385591b7e Mon Sep 17 00:00:00 2001 From: DGonzalezVillal Date: Tue, 20 Jan 2026 16:08:28 +0000 Subject: [PATCH 1/2] feat: adding unsafe_parser feature Introduce a new `unsafe_parser` feature that removes the `skip_bytes` logic from extended read and write operations in the parser. This forces structures to be read and written using the exact raw contents present in the input, avoiding issues with unparsable reports when new report versions are released. This change removes behind-the-scenes version-specific parsing of attestation reports and shifts responsibility to the user to validate and interpret report contents during attestation and related workflows. Signed-off-by: DGonzalezVillal --- Cargo.toml | 1 + src/certs/snp/ecdsa/mod.rs | 5 + src/firmware/guest/types/snp.rs | 550 +++++++++++++++--- src/firmware/host/types/snp.rs | 146 ++++- src/measurement/idblock_types.rs | 156 ++++- src/measurement/vmsa.rs | 862 ++++++++++++++++++++-------- src/util/parser_helper/read_ext.rs | 3 + src/util/parser_helper/write_ext.rs | 22 +- 8 files changed, 1372 insertions(+), 373 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0858b3c4..251c4c76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ sev = ["dep:rdrand"] snp = [] crypto_nossl = ["dep:p384", "dep:rsa", "dep:sha2", "dep:x509-cert"] serde = ["dep:serde", "dep:serde-big-array", "dep:serde_bytes"] +unsafe_parser = [] [target.'cfg(target_os = "linux")'.dependencies] iocuddle = "^0.1" diff --git a/src/certs/snp/ecdsa/mod.rs b/src/certs/snp/ecdsa/mod.rs index f7a2fb3a..be5dc1c7 100644 --- a/src/certs/snp/ecdsa/mod.rs +++ b/src/certs/snp/ecdsa/mod.rs @@ -77,7 +77,12 @@ impl Encoder<()> for Signature { writer.write_bytes(self.r, ())?; writer.write_bytes(self.s, ())?; // Reserved bytes + #[cfg(not(feature = "unsafe_parser"))] writer.skip_bytes::<368>()?; + + #[cfg(feature = "unsafe_parser")] + writer.write_bytes([0u8; 368], ())?; + Ok(()) } } diff --git a/src/firmware/guest/types/snp.rs b/src/firmware/guest/types/snp.rs index a84eaa28..6f73115e 100644 --- a/src/firmware/guest/types/snp.rs +++ b/src/firmware/guest/types/snp.rs @@ -265,6 +265,10 @@ pub struct AttestationReport { /// Information related to signing keys in the report. See KeyInfo pub key_info: KeyInfo, + /// Reserved 1 + #[cfg(feature = "unsafe_parser")] + _reserved_1: [u8; 4], + /// Guest-provided 512 Bits of Data #[cfg_attr(feature = "serde", serde(with = "BigArray"))] pub report_data: [u8; 64], @@ -298,6 +302,10 @@ pub struct AttestationReport { /// CPUID Stepping pub cpuid_step: Option, + /// Reserved 2 + #[cfg(feature = "unsafe_parser")] + _reserved_2: [u8; 21], + /// If MaskChipId is set to 0, Identifier unique to the chip. /// Otherwise set to 0h. #[cfg_attr(feature = "serde", serde(with = "BigArray"))] @@ -306,14 +314,30 @@ pub struct AttestationReport { pub committed_tcb: TcbVersion, /// The build number of CurrentVersion pub current: Version, + + /// Reserved 3 + #[cfg(feature = "unsafe_parser")] + _reserved_3: [u8; 1], + /// The build number of CommittedVersion pub committed: Version, + + /// Reserved 4 + #[cfg(feature = "unsafe_parser")] + _reserved_4: [u8; 1], + /// The CurrentTcb at the time the guest was launched or imported. pub launch_tcb: TcbVersion, /// The verified mitigation vecor value at the time the guest was launched (LaunchMitVector). pub launch_mit_vector: Option, /// Value is set to the current verified mitigation vectore value (CurrentMitVector). pub current_mit_vector: Option, + + /// Reserved 5 + #[cfg(feature = "unsafe_parser")] + #[cfg_attr(feature = "serde", serde(with = "BigArray"))] + _reserved_5: [u8; 152], + /// Signature of bytes 0 to 0x29F inclusive of this report. /// The format of the signature is found within Signature. pub signature: Signature, @@ -321,36 +345,79 @@ pub struct AttestationReport { impl Default for AttestationReport { fn default() -> Self { - Self { - version: Default::default(), - guest_svn: Default::default(), - policy: Default::default(), - family_id: Default::default(), - image_id: Default::default(), - vmpl: Default::default(), - sig_algo: Default::default(), - current_tcb: Default::default(), - plat_info: Default::default(), - key_info: Default::default(), - report_data: [0u8; 64], - measurement: [0u8; 48], - host_data: Default::default(), - id_key_digest: [0u8; 48], - author_key_digest: [0u8; 48], - report_id: Default::default(), - report_id_ma: Default::default(), - reported_tcb: Default::default(), - cpuid_fam_id: Default::default(), - cpuid_mod_id: Default::default(), - cpuid_step: Default::default(), - chip_id: [0u8; 64], - committed_tcb: Default::default(), - current: Default::default(), - committed: Default::default(), - launch_tcb: Default::default(), - launch_mit_vector: Default::default(), - current_mit_vector: Default::default(), - signature: Default::default(), + #[cfg(not(feature = "unsafe_parser"))] + { + Self { + version: Default::default(), + guest_svn: Default::default(), + policy: Default::default(), + family_id: Default::default(), + image_id: Default::default(), + vmpl: Default::default(), + sig_algo: Default::default(), + current_tcb: Default::default(), + plat_info: Default::default(), + key_info: Default::default(), + report_data: [0u8; 64], + measurement: [0u8; 48], + host_data: Default::default(), + id_key_digest: [0u8; 48], + author_key_digest: [0u8; 48], + report_id: Default::default(), + report_id_ma: Default::default(), + reported_tcb: Default::default(), + cpuid_fam_id: Default::default(), + cpuid_mod_id: Default::default(), + cpuid_step: Default::default(), + chip_id: [0u8; 64], + committed_tcb: Default::default(), + current: Default::default(), + committed: Default::default(), + launch_tcb: Default::default(), + launch_mit_vector: Default::default(), + current_mit_vector: Default::default(), + signature: Default::default(), + } + } + + #[cfg(feature = "unsafe_parser")] + { + Self { + version: Default::default(), + guest_svn: Default::default(), + policy: Default::default(), + family_id: Default::default(), + image_id: Default::default(), + vmpl: Default::default(), + sig_algo: Default::default(), + current_tcb: Default::default(), + plat_info: Default::default(), + key_info: Default::default(), + _reserved_1: Default::default(), + report_data: [0u8; 64], + measurement: [0u8; 48], + host_data: Default::default(), + id_key_digest: [0u8; 48], + author_key_digest: [0u8; 48], + report_id: Default::default(), + report_id_ma: Default::default(), + reported_tcb: Default::default(), + cpuid_fam_id: Default::default(), + cpuid_mod_id: Default::default(), + cpuid_step: Default::default(), + _reserved_2: Default::default(), + chip_id: [0u8; 64], + committed_tcb: Default::default(), + current: Default::default(), + _reserved_3: Default::default(), + committed: Default::default(), + _reserved_4: Default::default(), + launch_tcb: Default::default(), + launch_mit_vector: Default::default(), + current_mit_vector: Default::default(), + _reserved_5: [0u8; 152], + signature: Default::default(), + } } } } @@ -390,9 +457,14 @@ impl Encoder<()> for AttestationReport { writer.write_bytes(self.current_tcb, generation)?; writer.write_bytes(self.plat_info, ())?; writer.write_bytes(self.key_info, ())?; - writer - .skip_bytes::<4>()? - .write_bytes(self.report_data, ())?; + + // Reserved field 1 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self._reserved_1, ())?; + + writer.write_bytes(self.report_data, ())?; writer.write_bytes(self.measurement, ())?; writer.write_bytes(self.host_data, ())?; writer.write_bytes(self.id_key_digest, ())?; @@ -401,29 +473,55 @@ impl Encoder<()> for AttestationReport { writer.write_bytes(self.report_id_ma, ())?; writer.write_bytes(self.reported_tcb, generation)?; + // Reserved Field 2 + #[cfg(not(feature = "unsafe_parser"))] // Write CPUID fields based on variant match variant { ReportVariant::V2 => { // V2 doesn't have CPUID fields - writer.skip_bytes::<24>()?.write_bytes(self.chip_id, ())?; + writer.skip_bytes::<24>()?; } _ => { // Write CPUID fields for V3 and V4 writer.write_bytes(self.cpuid_fam_id.unwrap_or(0), ())?; writer.write_bytes(self.cpuid_mod_id.unwrap_or(0), ())?; writer.write_bytes(self.cpuid_step.unwrap_or(0), ())?; - writer.skip_bytes::<21>()?.write_bytes(self.chip_id, ())?; + writer.skip_bytes::<21>()?; } } + // Since we are writing data as is in all locations, we don't need to check version, just writing raw data. + #[cfg(feature = "unsafe_parser")] + { + writer.write_bytes(self.cpuid_fam_id.unwrap_or(0), ())?; + writer.write_bytes(self.cpuid_mod_id.unwrap_or(0), ())?; + writer.write_bytes(self.cpuid_step.unwrap_or(0), ())?; + writer.write_bytes(self._reserved_2, ())?; + } + + writer.write_bytes(self.chip_id, ())?; // Write committed TCB based on variant writer.write_bytes(self.committed_tcb, generation)?; writer.write_bytes(self.current, ())?; - writer.skip_bytes::<1>()?.write_bytes(self.committed, ())?; - writer - .skip_bytes::<1>()? - .write_bytes(self.launch_tcb, generation)?; + // Reserved field 3 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<1>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self._reserved_3, ())?; + + writer.write_bytes(self.committed, ())?; + + // Reserved field 4 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<1>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self._reserved_4, ())?; + + writer.write_bytes(self.launch_tcb, generation)?; + + //Reserved field 5 + #[cfg(not(feature = "unsafe_parser"))] // Write launch and current mitigation vectors based on variant match variant { ReportVariant::V2 | ReportVariant::V3 => { @@ -440,6 +538,14 @@ impl Encoder<()> for AttestationReport { } } + #[cfg(feature = "unsafe_parser")] + { + writer.write_bytes(self.launch_mit_vector.unwrap_or(0), ())?; + writer.write_bytes(self.current_mit_vector.unwrap_or(0), ())?; + writer.write_bytes(self._reserved_5, ())?; + writer.write_bytes(self.signature, ())?; + } + Ok(()) } } @@ -479,7 +585,14 @@ impl Decoder<()> for AttestationReport { let current_tcb = stepper.read_bytes_with(generation)?; let plat_info = stepper.read_bytes()?; let key_info = stepper.read_bytes()?; - let report_data = stepper.skip_bytes::<4>()?.read_bytes()?; + + // Reserved 1 + #[cfg(not(feature = "unsafe_parser"))] + stepper.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + let _reserved_1 = stepper.read_bytes()?; + + let report_data = stepper.read_bytes()?; let measurement = stepper.read_bytes()?; let host_data = stepper.read_bytes()?; let id_key_digest = stepper.read_bytes()?; @@ -488,65 +601,152 @@ impl Decoder<()> for AttestationReport { let report_id_ma = stepper.read_bytes()?; let reported_tcb = stepper.read_bytes_with(generation)?; + // Reserved 2 + #[cfg(not(feature = "unsafe_parser"))] // CPUID fields were added in V3 and later. - let (cpuid_fam_id, cpuid_mod_id, cpuid_step, chip_id) = match variant { - ReportVariant::V2 => (None, None, None, stepper.skip_bytes::<24>()?.read_bytes()?), - _ => ( + let (cpuid_fam_id, cpuid_mod_id, cpuid_step) = match variant { + ReportVariant::V2 => { + stepper.skip_bytes::<24>()?; + (None, None, None) + } + _ => { + let fam = Some(stepper.read_bytes()?); + let model = Some(stepper.read_bytes()?); + let step = Some(stepper.read_bytes()?); + stepper.skip_bytes::<21>()?; + (fam, model, step) + } + }; + #[cfg(feature = "unsafe_parser")] + let (cpuid_fam_id, cpuid_mod_id, cpuid_step, _reserved_2) = { + ( Some(stepper.read_bytes()?), Some(stepper.read_bytes()?), Some(stepper.read_bytes()?), - stepper.skip_bytes::<21>()?.read_bytes()?, - ), + stepper.read_bytes()?, + ) }; + let chip_id = stepper.read_bytes()?; let committed_tcb = stepper.read_bytes_with(generation)?; let current = stepper.read_bytes()?; - let committed = stepper.skip_bytes::<1>()?.read_bytes()?; - let launch_tcb = stepper.skip_bytes::<1>()?.read_bytes_with(generation)?; + // Reserved 3 + #[cfg(not(feature = "unsafe_parser"))] + stepper.skip_bytes::<1>()?; + #[cfg(feature = "unsafe_parser")] + let _reserved_3 = stepper.read_bytes()?; + + let committed = stepper.read_bytes()?; + + //Reserved 4 + #[cfg(not(feature = "unsafe_parser"))] + stepper.skip_bytes::<1>()?; + #[cfg(feature = "unsafe_parser")] + let _reserved_4 = stepper.read_bytes()?; + + let launch_tcb = stepper.read_bytes_with(generation)?; + + //Reserved 5 + #[cfg(not(feature = "unsafe_parser"))] // mit vecor fields were added in V5 and later. - let (launch_mit_vector, current_mit_vector, signature) = match variant { + let (launch_mit_vector, current_mit_vector) = match variant { ReportVariant::V2 | ReportVariant::V3 => { - (None, None, stepper.skip_bytes::<168>()?.read_bytes()?) + stepper.skip_bytes::<168>()?; + (None, None) + } + _ => { + let launch_vector = Some(stepper.read_bytes()?); + let current_vector = Some(stepper.read_bytes()?); + stepper.skip_bytes::<152>()?; + (launch_vector, current_vector) } - _ => ( + }; + #[cfg(feature = "unsafe_parser")] + let (launch_mit_vector, current_mit_vector, _reserved_5) = { + ( Some(stepper.read_bytes()?), Some(stepper.read_bytes()?), - stepper.skip_bytes::<152>()?.read_bytes()?, - ), + stepper.read_bytes()?, + ) }; - Ok(Self { - version, - guest_svn, - policy, - family_id, - image_id, - vmpl, - sig_algo, - current_tcb, - plat_info, - key_info, - report_data, - measurement, - host_data, - id_key_digest, - author_key_digest, - report_id, - report_id_ma, - reported_tcb, - cpuid_fam_id, - cpuid_mod_id, - cpuid_step, - chip_id, - committed_tcb, - current, - committed, - launch_tcb, - launch_mit_vector, - current_mit_vector, - signature, - }) + let signature = stepper.read_bytes()?; + + #[cfg(not(feature = "unsafe_parser"))] + { + Ok(Self { + version, + guest_svn, + policy, + family_id, + image_id, + vmpl, + sig_algo, + current_tcb, + plat_info, + key_info, + report_data, + measurement, + host_data, + id_key_digest, + author_key_digest, + report_id, + report_id_ma, + reported_tcb, + cpuid_fam_id, + cpuid_mod_id, + cpuid_step, + chip_id, + committed_tcb, + current, + committed, + launch_tcb, + launch_mit_vector, + current_mit_vector, + signature, + }) + } + + #[cfg(feature = "unsafe_parser")] + { + Ok(Self { + version, + guest_svn, + policy, + family_id, + image_id, + vmpl, + sig_algo, + current_tcb, + plat_info, + key_info, + _reserved_1, + report_data, + measurement, + host_data, + id_key_digest, + author_key_digest, + report_id, + report_id_ma, + reported_tcb, + cpuid_fam_id, + cpuid_mod_id, + cpuid_step, + _reserved_2, + chip_id, + committed_tcb, + current, + _reserved_3, + committed, + _reserved_4, + launch_tcb, + launch_mit_vector, + current_mit_vector, + _reserved_5, + signature, + }) + } } } @@ -675,7 +875,19 @@ Current Mitigation Vector: {} self.current_mit_vector .map_or("None".to_string(), |cmv| cmv.to_string()), self.signature - ) + )?; + + #[cfg(feature = "unsafe_parser")] + { + writeln!(f)?; + writeln!(f, "\n--- Reserved Fields (unsafe_parser) ---")?; + writeln!(f, "\nReserved 1: {}", HexLine(&self._reserved_1))?; + writeln!(f, "\nReserved 2: {}", HexLine(&self._reserved_2))?; + writeln!(f, "\nReserved 3: {}", HexLine(&self._reserved_3))?; + writeln!(f, "\nReserved 4: {}", HexLine(&self._reserved_4))?; + } + + Ok(()) } } @@ -1161,8 +1373,9 @@ mod tests { assert!(!actual.get_tcb_version()); } + #[cfg(not(feature = "unsafe_parser"))] #[test] - fn test_attestation_report_fmt() { + fn test_attestation_report_fmt_safe() { let expected: &str = r#"Attestation Report: Version: 0 @@ -1311,6 +1524,173 @@ Signature: assert_eq!(expected, AttestationReport::default().to_string()) } + #[cfg(feature = "unsafe_parser")] + #[test] + fn test_attestation_report_fmt_unsafe() { + let expected: &str = r#"Attestation Report: + +Version: 0 + +Guest SVN: 0 + +Guest Policy (0x0): + ABI Major: 0 + ABI Minor: 0 + SMT Allowed: false + Migrate MA: false + Debug Allowed: false + Single Socket: false + CXL Allowed: false + AEX 256 XTS: false + RAPL Allowed: false + Ciphertext hiding: false + Page Swap Disable: false + +Family ID: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Image ID: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +VMPL: 0 + +Signature Algorithm: 0 + +Current TCB: + +TCB Version: + Microcode: 0 + SNP: 0 + TEE: 0 + Boot Loader: 0 + FMC: None + +Platform Info (0): + SMT Enabled: false + TSME Enabled: false + ECC Enabled: false + RAPL Disabled: false + Ciphertext Hiding Enabled: false + Alias Check Complete: false + SEV-TIO Enabled: false + +Key Information: + author key enabled: false + mask chip key: false + signing key: vcek + +Report Data: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Measurement: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Host Data: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +ID Key Digest: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Author Key Digest: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Report ID: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Report ID Migration Agent: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Reported TCB: + +TCB Version: + Microcode: 0 + SNP: 0 + TEE: 0 + Boot Loader: 0 + FMC: None + +CPUID Family ID: None + +CPUID Model ID: None + +CPUID Stepping: None + +Chip ID: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +Committed TCB: + +TCB Version: + Microcode: 0 + SNP: 0 + TEE: 0 + Boot Loader: 0 + FMC: None + +Current Version: 0.0.0 + +Committed Version: 0.0.0 + +Launch TCB: + +TCB Version: + Microcode: 0 + SNP: 0 + TEE: 0 + Boot Loader: 0 + FMC: None + +Launch Mitigation Vector: None + +Current Mitigation Vector: None + +Signature: + R: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 + S: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 00 00 00 + +--- Reserved Fields (unsafe_parser) --- + +Reserved 1: +00 00 00 00 + +Reserved 2: +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +00 00 00 00 00 + +Reserved 3: +00 + +Reserved 4: +00 +"#; + assert_eq!(expected, AttestationReport::default().to_string()) + } + #[test] fn test_attestation_report_copy() { let expected: AttestationReport = AttestationReport::default(); diff --git a/src/firmware/host/types/snp.rs b/src/firmware/host/types/snp.rs index ae44a020..c5994bcc 100644 --- a/src/firmware/host/types/snp.rs +++ b/src/firmware/host/types/snp.rs @@ -785,25 +785,46 @@ pub struct WrappedVlekHashstick { /// IV used to wrap chip-unique key pub iv: [u8; 12], // 96 bits = 12 bytes - // Reserved [u8;4] + #[cfg(feature = "unsafe_parser")] + /// Reserved 1 + _reserved_1: [u8; 4], + /// VLEK hashstick wrapped with a chip-unique key using AES-256-GCM pub vlek_wrapped: [u8; 384], /// The TCB version associated with this VLEK hashstick pub tcb_version: TcbVersion, - // Reserved [u8;8] + #[cfg(feature = "unsafe_parser")] + /// Reserved 2 + _reserved_2: [u8; 8], + /// AES-256-GCM authentication tag of the wrapped VLEK hashstick and TCB_VERSION pub vlek_auth_tag: [u8; 16], } impl Default for WrappedVlekHashstick { fn default() -> Self { - Self { - iv: Default::default(), - vlek_wrapped: [0u8; 384], - tcb_version: Default::default(), - vlek_auth_tag: Default::default(), + #[cfg(not(feature = "unsafe_parser"))] + { + Self { + iv: Default::default(), + vlek_wrapped: [0u8; 384], + tcb_version: Default::default(), + vlek_auth_tag: Default::default(), + } + } + + #[cfg(feature = "unsafe_parser")] + { + Self { + iv: Default::default(), + _reserved_1: Default::default(), + vlek_wrapped: [0u8; 384], + tcb_version: Default::default(), + _reserved_2: Default::default(), + vlek_auth_tag: Default::default(), + } } } } @@ -815,15 +836,23 @@ impl Encoder for WrappedVlekHashstick { generation: Generation, ) -> Result<(), std::io::Error> { writer.write_bytes(self.iv, ())?; - // Reserved [u8;4] - writer - .skip_bytes::<4>()? - .write_bytes(self.vlek_wrapped, ())?; + + // Reserved 1 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self._reserved_1, ())?; + + writer.write_bytes(self.vlek_wrapped, ())?; writer.write_bytes(self.tcb_version, generation)?; - // Reserved [u8;8] - writer - .skip_bytes::<8>()? - .write_bytes(self.vlek_auth_tag, ())?; + + // Reserved 2 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<8>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self._reserved_2, ())?; + + writer.write_bytes(self.vlek_auth_tag, ())?; Ok(()) } } @@ -831,15 +860,45 @@ impl Encoder for WrappedVlekHashstick { impl Decoder for WrappedVlekHashstick { fn decode(reader: &mut impl Read, generation: Generation) -> Result { let iv = reader.read_bytes()?; - let vlek_wrapped = reader.skip_bytes::<4>()?.read_bytes()?; + + // Reserved 1 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + let _reserved_1 = reader.read_bytes()?; + + let vlek_wrapped = reader.read_bytes()?; let tcb_version = reader.read_bytes_with(generation)?; - let vlek_auth_tag = reader.skip_bytes::<8>()?.read_bytes()?; - Ok(Self { - iv, - vlek_wrapped, - tcb_version, - vlek_auth_tag, - }) + + // Reserved 2 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<8>()?; + #[cfg(feature = "unsafe_parser")] + let _reserved_2 = reader.read_bytes()?; + + let vlek_auth_tag = reader.read_bytes()?; + + #[cfg(not(feature = "unsafe_parser"))] + { + Ok(Self { + iv, + vlek_wrapped, + tcb_version, + vlek_auth_tag, + }) + } + + #[cfg(feature = "unsafe_parser")] + { + Ok(Self { + iv, + _reserved_1, + vlek_wrapped, + tcb_version, + _reserved_2, + vlek_auth_tag, + }) + } } } @@ -863,7 +922,17 @@ impl Display for WrappedVlekHashstick { HexLine(&self.vlek_wrapped), self.tcb_version, HexLine(&self.vlek_auth_tag) - ) + )?; + + #[cfg(feature = "unsafe_parser")] + { + writeln!(f)?; + writeln!(f, "\n--- Reserved Fields (unsafe_parser) ---")?; + writeln!(f, "\nReserved 1: {}", HexLine(&self._reserved_1))?; + writeln!(f, "\nReserved 2: {}", HexLine(&self._reserved_2))?; + } + + Ok(()) } } @@ -1870,10 +1939,21 @@ mod tests { #[test] fn test_wrapped_vlek_hashstick_to_bytes() { // Create a test hashstick + #[cfg(not(feature = "unsafe_parser"))] + let hashstick = WrappedVlekHashstick { + iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + vlek_wrapped: [42; 384], + tcb_version: TcbVersion::new(None, 1, 2, 3, 4), + vlek_auth_tag: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0], + }; + + #[cfg(feature = "unsafe_parser")] let hashstick = WrappedVlekHashstick { iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + _reserved_1: [0; 4], vlek_wrapped: [42; 384], tcb_version: TcbVersion::new(None, 1, 2, 3, 4), + _reserved_2: [0; 8], vlek_auth_tag: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0], }; @@ -1919,6 +1999,7 @@ mod tests { #[test] fn test_wrapped_vlek_hashstick_display() { // Create a test hashstick + #[cfg(not(feature = "unsafe_parser"))] let hashstick = WrappedVlekHashstick { iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], vlek_wrapped: [42; 384], @@ -1926,6 +2007,16 @@ mod tests { vlek_auth_tag: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0], }; + #[cfg(feature = "unsafe_parser")] + let hashstick = WrappedVlekHashstick { + iv: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], + _reserved_1: [0; 4], + vlek_wrapped: [42; 384], + tcb_version: TcbVersion::new(None, 1, 2, 3, 4), + _reserved_2: [0; 8], + vlek_auth_tag: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0], + }; + // Convert to string and check contents let display_string = format!("{}", hashstick); assert!(display_string.contains("Wrapped VLEK Hashstick:")); @@ -1933,5 +2024,12 @@ mod tests { assert!(display_string.contains("VLEK hashstic Wrapped:")); assert!(display_string.contains("TCB:")); assert!(display_string.contains("VLEK authentication tag:")); + + #[cfg(feature = "unsafe_parser")] + { + // Ensure reserved fields are displayed + assert!(display_string.contains("\nReserved 1:")); + assert!(display_string.contains("\nReserved 2:")); + } } } diff --git a/src/measurement/idblock_types.rs b/src/measurement/idblock_types.rs index e6b613ec..30edd081 100644 --- a/src/measurement/idblock_types.rs +++ b/src/measurement/idblock_types.rs @@ -455,29 +455,58 @@ pub struct IdAuth { pub id_key_algo: u32, /// The algorithm of the Author Key. Defaults to P-384 pub author_key_algo: u32, + + #[cfg(feature = "unsafe_parser")] + /// Reserved 1 + pub reserved1: [u8; Self::ID_AUTH_RESERVED1_BYTES], + /// The signature of all bytes of the ID block pub id_block_sig: SevEcdsaSig, /// The public component of the ID key pub id_pubkey: SevEcdsaPubKey, + + #[cfg(feature = "unsafe_parser")] + /// Reserved 2 + pub reserved2: [u8; Self::ID_AUTH_RESERVED2_BYTES], + /// The signature of the ID_KEY pub id_key_sig: SevEcdsaSig, /// The public component of the Author key pub author_pub_key: SevEcdsaPubKey, + + #[cfg(feature = "unsafe_parser")] + /// Reserved 3 + pub reserved3: [u8; Self::ID_AUTH_RESERVED3_BYTES], } impl Encoder<()> for IdAuth { fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> { writer.write_bytes(self.id_key_algo, ())?; writer.write_bytes(self.author_key_algo, ())?; - writer - .skip_bytes::<{ Self::ID_AUTH_RESERVED1_BYTES }>()? - .write_bytes(self.id_block_sig, ())?; + + // Reserved 1 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<{ Self::ID_AUTH_RESERVED1_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved1, ())?; + + writer.write_bytes(self.id_block_sig, ())?; writer.write_bytes(self.id_pubkey, ())?; - writer - .skip_bytes::<{ Self::ID_AUTH_RESERVED2_BYTES }>()? - .write_bytes(self.id_key_sig, ())?; + + // Reserved 2 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<{ Self::ID_AUTH_RESERVED2_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved2, ())?; + + writer.write_bytes(self.id_key_sig, ())?; writer.write_bytes(self.author_pub_key, ())?; + + // Reserved 3 + #[cfg(not(feature = "unsafe_parser"))] writer.skip_bytes::<{ Self::ID_AUTH_RESERVED3_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved3, ())?; Ok(()) } @@ -487,22 +516,57 @@ impl Decoder<()> for IdAuth { fn decode(reader: &mut impl Read, _: ()) -> Result { let id_key_algo = reader.read_bytes()?; let author_key_algo = reader.read_bytes()?; + + // Reserved 1 + #[cfg(not(feature = "unsafe_parser"))] reader.skip_bytes::<{ Self::ID_AUTH_RESERVED1_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + let reserved1 = reader.read_bytes()?; + let id_block_sig = reader.read_bytes()?; let id_pubkey = reader.read_bytes()?; + + // Reserved 2 + #[cfg(not(feature = "unsafe_parser"))] reader.skip_bytes::<{ Self::ID_AUTH_RESERVED2_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + let reserved2 = reader.read_bytes()?; + let id_key_sig = reader.read_bytes()?; let author_pub_key = reader.read_bytes()?; + + // Reserved 3 + #[cfg(not(feature = "unsafe_parser"))] reader.skip_bytes::<{ Self::ID_AUTH_RESERVED3_BYTES }>()?; + #[cfg(feature = "unsafe_parser")] + let reserved3 = reader.read_bytes()?; + + #[cfg(not(feature = "unsafe_parser"))] + { + Ok(Self { + id_key_algo, + author_key_algo, + id_block_sig, + id_pubkey, + id_key_sig, + author_pub_key, + }) + } - Ok(Self { - id_key_algo, - author_key_algo, - id_block_sig, - id_pubkey, - id_key_sig, - author_pub_key, - }) + #[cfg(feature = "unsafe_parser")] + { + Ok(Self { + id_key_algo, + author_key_algo, + reserved1, + id_block_sig, + id_pubkey, + reserved2, + id_key_sig, + author_pub_key, + reserved3, + }) + } } } @@ -536,26 +600,62 @@ impl IdAuth { _ => DEFAULT_KEY_ALGO, }; - Self { - id_key_algo: id_algo, - author_key_algo: key_algo, - id_block_sig, - id_pubkey, - id_key_sig, - author_pub_key, + #[cfg(not(feature = "unsafe_parser"))] + { + Self { + id_key_algo: id_algo, + author_key_algo: key_algo, + id_block_sig, + id_pubkey, + id_key_sig, + author_pub_key, + } + } + + #[cfg(feature = "unsafe_parser")] + { + Self { + id_key_algo: id_algo, + author_key_algo: key_algo, + reserved1: [0u8; Self::ID_AUTH_RESERVED1_BYTES], + id_block_sig, + id_pubkey, + reserved2: [0u8; Self::ID_AUTH_RESERVED2_BYTES], + id_key_sig, + author_pub_key, + reserved3: [0u8; Self::ID_AUTH_RESERVED3_BYTES], + } } } } impl Default for IdAuth { fn default() -> Self { - Self { - id_key_algo: DEFAULT_KEY_ALGO, - author_key_algo: DEFAULT_KEY_ALGO, - id_block_sig: Default::default(), - id_pubkey: Default::default(), - id_key_sig: Default::default(), - author_pub_key: Default::default(), + #[cfg(not(feature = "unsafe_parser"))] + { + Self { + id_key_algo: DEFAULT_KEY_ALGO, + author_key_algo: DEFAULT_KEY_ALGO, + id_block_sig: Default::default(), + id_pubkey: Default::default(), + id_key_sig: Default::default(), + author_pub_key: Default::default(), + } + } + + #[cfg(feature = "unsafe_parser")] + { + Self { + id_key_algo: DEFAULT_KEY_ALGO, + author_key_algo: DEFAULT_KEY_ALGO, + reserved1: [0u8; Self::ID_AUTH_RESERVED1_BYTES], + id_block_sig: Default::default(), + id_pubkey: Default::default(), + reserved2: [0u8; Self::ID_AUTH_RESERVED2_BYTES], + id_key_sig: Default::default(), + author_pub_key: Default::default(), + reserved3: [0u8; Self::ID_AUTH_RESERVED3_BYTES], + } } } } diff --git a/src/measurement/vmsa.rs b/src/measurement/vmsa.rs index 0e1e2557..39f9bd72 100644 --- a/src/measurement/vmsa.rs +++ b/src/measurement/vmsa.rs @@ -246,9 +246,24 @@ struct SevEsSaveArea { vmpl2_ssp: u64, vmpl3_ssp: u64, u_cet: u64, + + // reserved_0xc8 + #[cfg(feature = "unsafe_parser")] + reserved_0xc8: [u8; 2], + vmpl: u8, cpl: u8, + + // reserved_0xcc + #[cfg(feature = "unsafe_parser")] + reserved_0xcc: [u8; 4], + efer: u64, + + // reserved_0xd8 + #[cfg(feature = "unsafe_parser")] + reserved_0xd8: [u8; 104], + xss: u64, cr4: u64, cr3: u64, @@ -265,6 +280,11 @@ struct SevEsSaveArea { dr1_addr_mask: u64, dr2_addr_mask: u64, dr3_addr_mask: u64, + + // reserved_0x1c0 + #[cfg(feature = "unsafe_parser")] + reserved_0x1c0: [u8; 24], + rsp: u64, s_cet: u64, ssp: u64, @@ -279,17 +299,37 @@ struct SevEsSaveArea { sysenter_esp: u64, sysenter_eip: u64, cr2: u64, + + // reserved_0x248 + #[cfg(feature = "unsafe_parser")] + reserved_0x248: [u8; 32], + g_pat: u64, dbgctrl: u64, br_from: u64, br_to: u64, last_excp_from: u64, last_excp_to: u64, + + // reserved_0x298 + #[cfg(feature = "unsafe_parser")] + reserved_0x298: [u8; 80], + pkru: u32, tsc_aux: u32, + + // reserved_0x2f0 + #[cfg(feature = "unsafe_parser")] + reserved_0x2f0: [u8; 24], + rcx: u64, rdx: u64, rbx: u64, + + // reserved_0x320 + #[cfg(feature = "unsafe_parser")] + reserved_0x320: [u8; 8], + rbp: u64, rsi: u64, rdi: u64, @@ -301,6 +341,11 @@ struct SevEsSaveArea { r13: u64, r14: u64, r15: u64, + + // reserved_0x380 + #[cfg(feature = "unsafe_parser")] + reserved_0x380: [u8; 16], + guest_exit_info_1: u64, guest_exit_info_2: u64, guest_exit_int_info: u64, @@ -314,6 +359,10 @@ struct SevEsSaveArea { event_inj: u64, xcr0: u64, + // reserved_0x3f0 + #[cfg(feature = "unsafe_parser")] + reserved_0x3f0: [u8; 16], + /* Floating Point Area */ x87_dp: u64, mxcsr: u32, @@ -336,102 +385,215 @@ struct SevEsSaveArea { impl Default for SevEsSaveArea { fn default() -> Self { - Self { - es: Default::default(), - cs: Default::default(), - ss: Default::default(), - ds: Default::default(), - fs: Default::default(), - gs: Default::default(), - gdtr: Default::default(), - ldtr: Default::default(), - idtr: Default::default(), - tr: Default::default(), - vmpl0_ssp: Default::default(), - vmpl1_ssp: Default::default(), - vmpl2_ssp: Default::default(), - vmpl3_ssp: Default::default(), - u_cet: Default::default(), - vmpl: Default::default(), - cpl: Default::default(), - efer: Default::default(), - xss: Default::default(), - cr4: Default::default(), - cr3: Default::default(), - cr0: Default::default(), - dr7: Default::default(), - dr6: Default::default(), - rflags: Default::default(), - rip: Default::default(), - dr0: Default::default(), - dr1: Default::default(), - dr2: Default::default(), - dr3: Default::default(), - dr0_addr_mask: Default::default(), - dr1_addr_mask: Default::default(), - dr2_addr_mask: Default::default(), - dr3_addr_mask: Default::default(), - rsp: Default::default(), - s_cet: Default::default(), - ssp: Default::default(), - isst_addr: Default::default(), - rax: Default::default(), - star: Default::default(), - lstar: Default::default(), - cstar: Default::default(), - sfmask: Default::default(), - kernel_gs_base: Default::default(), - sysenter_cs: Default::default(), - sysenter_esp: Default::default(), - sysenter_eip: Default::default(), - cr2: Default::default(), - g_pat: Default::default(), - dbgctrl: Default::default(), - br_from: Default::default(), - br_to: Default::default(), - last_excp_from: Default::default(), - last_excp_to: Default::default(), - pkru: Default::default(), - tsc_aux: Default::default(), - rcx: Default::default(), - rdx: Default::default(), - rbx: Default::default(), - rbp: Default::default(), - rsi: Default::default(), - rdi: Default::default(), - r8: Default::default(), - r9: Default::default(), - r10: Default::default(), - r11: Default::default(), - r12: Default::default(), - r13: Default::default(), - r14: Default::default(), - r15: Default::default(), - guest_exit_info_1: Default::default(), - guest_exit_info_2: Default::default(), - guest_exit_int_info: Default::default(), - guest_nrip: Default::default(), - sev_features: Default::default(), - vintr_ctrl: Default::default(), - guest_exit_code: Default::default(), - virtual_tom: Default::default(), - tlb_id: Default::default(), - pcpu_id: Default::default(), - event_inj: Default::default(), - xcr0: Default::default(), - x87_dp: Default::default(), - mxcsr: Default::default(), - x87_ftw: Default::default(), - x87_fsw: Default::default(), - x87_fcw: Default::default(), - x87_fop: Default::default(), - x87_ds: Default::default(), - x87_cs: Default::default(), - x87_rip: Default::default(), - fpreg_x87: [0u8; 80], - fpreg_xmm: [0u8; 256], - fpreg_ymm: [0u8; 256], - manual_padding: [0u8; 2448], + #[cfg(not(feature = "unsafe_parser"))] + { + Self { + es: Default::default(), + cs: Default::default(), + ss: Default::default(), + ds: Default::default(), + fs: Default::default(), + gs: Default::default(), + gdtr: Default::default(), + ldtr: Default::default(), + idtr: Default::default(), + tr: Default::default(), + vmpl0_ssp: Default::default(), + vmpl1_ssp: Default::default(), + vmpl2_ssp: Default::default(), + vmpl3_ssp: Default::default(), + u_cet: Default::default(), + vmpl: Default::default(), + cpl: Default::default(), + efer: Default::default(), + xss: Default::default(), + cr4: Default::default(), + cr3: Default::default(), + cr0: Default::default(), + dr7: Default::default(), + dr6: Default::default(), + rflags: Default::default(), + rip: Default::default(), + dr0: Default::default(), + dr1: Default::default(), + dr2: Default::default(), + dr3: Default::default(), + dr0_addr_mask: Default::default(), + dr1_addr_mask: Default::default(), + dr2_addr_mask: Default::default(), + dr3_addr_mask: Default::default(), + rsp: Default::default(), + s_cet: Default::default(), + ssp: Default::default(), + isst_addr: Default::default(), + rax: Default::default(), + star: Default::default(), + lstar: Default::default(), + cstar: Default::default(), + sfmask: Default::default(), + kernel_gs_base: Default::default(), + sysenter_cs: Default::default(), + sysenter_esp: Default::default(), + sysenter_eip: Default::default(), + cr2: Default::default(), + g_pat: Default::default(), + dbgctrl: Default::default(), + br_from: Default::default(), + br_to: Default::default(), + last_excp_from: Default::default(), + last_excp_to: Default::default(), + pkru: Default::default(), + tsc_aux: Default::default(), + rcx: Default::default(), + rdx: Default::default(), + rbx: Default::default(), + rbp: Default::default(), + rsi: Default::default(), + rdi: Default::default(), + r8: Default::default(), + r9: Default::default(), + r10: Default::default(), + r11: Default::default(), + r12: Default::default(), + r13: Default::default(), + r14: Default::default(), + r15: Default::default(), + guest_exit_info_1: Default::default(), + guest_exit_info_2: Default::default(), + guest_exit_int_info: Default::default(), + guest_nrip: Default::default(), + sev_features: Default::default(), + vintr_ctrl: Default::default(), + guest_exit_code: Default::default(), + virtual_tom: Default::default(), + tlb_id: Default::default(), + pcpu_id: Default::default(), + event_inj: Default::default(), + xcr0: Default::default(), + x87_dp: Default::default(), + mxcsr: Default::default(), + x87_ftw: Default::default(), + x87_fsw: Default::default(), + x87_fcw: Default::default(), + x87_fop: Default::default(), + x87_ds: Default::default(), + x87_cs: Default::default(), + x87_rip: Default::default(), + fpreg_x87: [0u8; 80], + fpreg_xmm: [0u8; 256], + fpreg_ymm: [0u8; 256], + manual_padding: [0u8; 2448], + } + } + #[cfg(feature = "unsafe_parser")] + { + Self { + es: Default::default(), + cs: Default::default(), + ss: Default::default(), + ds: Default::default(), + fs: Default::default(), + gs: Default::default(), + gdtr: Default::default(), + ldtr: Default::default(), + idtr: Default::default(), + tr: Default::default(), + vmpl0_ssp: Default::default(), + vmpl1_ssp: Default::default(), + vmpl2_ssp: Default::default(), + vmpl3_ssp: Default::default(), + u_cet: Default::default(), + reserved_0xc8: [0u8; 2], + vmpl: Default::default(), + cpl: Default::default(), + reserved_0xcc: [0u8; 4], + efer: Default::default(), + reserved_0xd8: [0u8; 104], + xss: Default::default(), + cr4: Default::default(), + cr3: Default::default(), + cr0: Default::default(), + dr7: Default::default(), + dr6: Default::default(), + rflags: Default::default(), + rip: Default::default(), + dr0: Default::default(), + dr1: Default::default(), + dr2: Default::default(), + dr3: Default::default(), + dr0_addr_mask: Default::default(), + dr1_addr_mask: Default::default(), + dr2_addr_mask: Default::default(), + dr3_addr_mask: Default::default(), + reserved_0x1c0: [0u8; 24], + rsp: Default::default(), + s_cet: Default::default(), + ssp: Default::default(), + isst_addr: Default::default(), + rax: Default::default(), + star: Default::default(), + lstar: Default::default(), + cstar: Default::default(), + sfmask: Default::default(), + kernel_gs_base: Default::default(), + sysenter_cs: Default::default(), + sysenter_esp: Default::default(), + sysenter_eip: Default::default(), + cr2: Default::default(), + reserved_0x248: [0u8; 32], + g_pat: Default::default(), + dbgctrl: Default::default(), + br_from: Default::default(), + br_to: Default::default(), + last_excp_from: Default::default(), + last_excp_to: Default::default(), + reserved_0x298: [0u8; 80], + pkru: Default::default(), + tsc_aux: Default::default(), + reserved_0x2f0: [0u8; 24], + rcx: Default::default(), + rdx: Default::default(), + rbx: Default::default(), + reserved_0x320: [0u8; 8], + rbp: Default::default(), + rsi: Default::default(), + rdi: Default::default(), + r8: Default::default(), + r9: Default::default(), + r10: Default::default(), + r11: Default::default(), + r12: Default::default(), + r13: Default::default(), + r14: Default::default(), + r15: Default::default(), + reserved_0x380: [0u8; 16], + guest_exit_info_1: Default::default(), + guest_exit_info_2: Default::default(), + guest_exit_int_info: Default::default(), + guest_nrip: Default::default(), + sev_features: Default::default(), + vintr_ctrl: Default::default(), + guest_exit_code: Default::default(), + virtual_tom: Default::default(), + tlb_id: Default::default(), + pcpu_id: Default::default(), + event_inj: Default::default(), + xcr0: Default::default(), + reserved_0x3f0: [0u8; 16], + x87_dp: Default::default(), + mxcsr: Default::default(), + x87_ftw: Default::default(), + x87_fsw: Default::default(), + x87_fcw: Default::default(), + x87_fop: Default::default(), + x87_ds: Default::default(), + x87_cs: Default::default(), + x87_rip: Default::default(), + fpreg_x87: [0u8; 80], + fpreg_xmm: [0u8; 256], + fpreg_ymm: [0u8; 256], + manual_padding: [0u8; 2448], + } } } } @@ -453,13 +615,30 @@ impl Encoder<()> for SevEsSaveArea { writer.write_bytes(self.vmpl2_ssp, ())?; writer.write_bytes(self.vmpl3_ssp, ())?; writer.write_bytes(self.u_cet, ())?; - // reserved_0xc8 [u8;2] - writer.skip_bytes::<2>()?.write_bytes(self.vmpl, ())?; + + // reserved_0xc8 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<2>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0xc8, ())?; + + writer.write_bytes(self.vmpl, ())?; writer.write_bytes(self.cpl, ())?; - // reserved_0xcc [u8;4] - writer.skip_bytes::<4>()?.write_bytes(self.efer, ())?; - // reserved_0xd8 [u8;104] - writer.skip_bytes::<104>()?.write_bytes(self.xss, ())?; + // reserved_0xcc + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0xcc, ())?; + + writer.write_bytes(self.efer, ())?; + + // reserved_0xd8 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<104>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0xd8, ())?; + + writer.write_bytes(self.xss, ())?; writer.write_bytes(self.cr4, ())?; writer.write_bytes(self.cr3, ())?; writer.write_bytes(self.cr0, ())?; @@ -475,8 +654,14 @@ impl Encoder<()> for SevEsSaveArea { writer.write_bytes(self.dr1_addr_mask, ())?; writer.write_bytes(self.dr2_addr_mask, ())?; writer.write_bytes(self.dr3_addr_mask, ())?; - // reserved_0x1c0 [u8;24] - writer.skip_bytes::<24>()?.write_bytes(self.rsp, ())?; + + // reserved_0x1c0 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<24>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x1c0, ())?; + + writer.write_bytes(self.rsp, ())?; writer.write_bytes(self.s_cet, ())?; writer.write_bytes(self.ssp, ())?; writer.write_bytes(self.isst_addr, ())?; @@ -490,22 +675,46 @@ impl Encoder<()> for SevEsSaveArea { writer.write_bytes(self.sysenter_esp, ())?; writer.write_bytes(self.sysenter_eip, ())?; writer.write_bytes(self.cr2, ())?; - // reserved_0x248[u8;32] - writer.skip_bytes::<32>()?.write_bytes(self.g_pat, ())?; + + // reserved_0x248 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<32>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x248, ())?; + + writer.write_bytes(self.g_pat, ())?; writer.write_bytes(self.dbgctrl, ())?; writer.write_bytes(self.br_from, ())?; writer.write_bytes(self.br_to, ())?; writer.write_bytes(self.last_excp_from, ())?; writer.write_bytes(self.last_excp_to, ())?; - // reserved_0x298 [u8;80] - writer.skip_bytes::<80>()?.write_bytes(self.pkru, ())?; + + // reserved_0x298 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<80>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x298, ())?; + + writer.write_bytes(self.pkru, ())?; writer.write_bytes(self.tsc_aux, ())?; - // reserved_0x2f0 [u8;24] - writer.skip_bytes::<24>()?.write_bytes(self.rcx, ())?; + + // reserved_0x2f0 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<24>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x2f0, ())?; + + writer.write_bytes(self.rcx, ())?; writer.write_bytes(self.rdx, ())?; writer.write_bytes(self.rbx, ())?; - // reserved_0x320 u64 - writer.skip_bytes::<8>()?.write_bytes(self.rbp, ())?; + + // reserved_0x320 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<8>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x320, ())?; + + writer.write_bytes(self.rbp, ())?; writer.write_bytes(self.rsi, ())?; writer.write_bytes(self.rdi, ())?; writer.write_bytes(self.r8, ())?; @@ -516,10 +725,14 @@ impl Encoder<()> for SevEsSaveArea { writer.write_bytes(self.r13, ())?; writer.write_bytes(self.r14, ())?; writer.write_bytes(self.r15, ())?; - // reserved_0x380 [u8;16] - writer - .skip_bytes::<16>()? - .write_bytes(self.guest_exit_info_1, ())?; + + // reserved_0x380 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<16>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x380, ())?; + + writer.write_bytes(self.guest_exit_info_1, ())?; writer.write_bytes(self.guest_exit_info_2, ())?; writer.write_bytes(self.guest_exit_int_info, ())?; writer.write_bytes(self.guest_nrip, ())?; @@ -531,8 +744,14 @@ impl Encoder<()> for SevEsSaveArea { writer.write_bytes(self.pcpu_id, ())?; writer.write_bytes(self.event_inj, ())?; writer.write_bytes(self.xcr0, ())?; - // reserved_0x3f0 [u8;16] - writer.skip_bytes::<16>()?.write_bytes(self.x87_dp, ())?; + + // reserved_0x3f0 + #[cfg(not(feature = "unsafe_parser"))] + writer.skip_bytes::<16>()?; + #[cfg(feature = "unsafe_parser")] + writer.write_bytes(self.reserved_0x3f0, ())?; + + writer.write_bytes(self.x87_dp, ())?; writer.write_bytes(self.mxcsr, ())?; writer.write_bytes(self.x87_ftw, ())?; writer.write_bytes(self.x87_fsw, ())?; @@ -567,13 +786,31 @@ impl Decoder<()> for SevEsSaveArea { let vmpl2_ssp = reader.read_bytes()?; let vmpl3_ssp = reader.read_bytes()?; let u_cet = reader.read_bytes()?; - // reserved_0xc8: [u8;2] - let vmpl = reader.skip_bytes::<2>()?.read_bytes()?; + + // reserved_0xc8 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<2>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0xc8 = reader.read_bytes()?; + + let vmpl = reader.read_bytes()?; let cpl = reader.read_bytes()?; - // reserved_0xcc: [u8;4] - let efer = reader.skip_bytes::<4>()?.read_bytes()?; - // reserved 0xd8: [u8;104] - let xss = reader.skip_bytes::<104>()?.read_bytes()?; + + // reserved_0xcc + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<4>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0xcc = reader.read_bytes()?; + + let efer = reader.read_bytes()?; + + // reserved 0xd8 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<104>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0xd8 = reader.read_bytes()?; + + let xss = reader.read_bytes()?; let cr4 = reader.read_bytes()?; let cr3 = reader.read_bytes()?; let cr0 = reader.read_bytes()?; @@ -589,8 +826,14 @@ impl Decoder<()> for SevEsSaveArea { let dr1_addr_mask = reader.read_bytes()?; let dr2_addr_mask = reader.read_bytes()?; let dr3_addr_mask = reader.read_bytes()?; - // reserved_0x1c0: [u8;24] - let rsp = reader.skip_bytes::<24>()?.read_bytes()?; + + // reserved_0x1c0 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<24>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x1c0 = reader.read_bytes()?; + + let rsp = reader.read_bytes()?; let s_cet = reader.read_bytes()?; let ssp = reader.read_bytes()?; let isst_addr = reader.read_bytes()?; @@ -604,22 +847,46 @@ impl Decoder<()> for SevEsSaveArea { let sysenter_esp = reader.read_bytes()?; let sysenter_eip = reader.read_bytes()?; let cr2 = reader.read_bytes()?; - // reserved_0x248: [u8;32] - let g_pat = reader.skip_bytes::<32>()?.read_bytes()?; + + // reserved_0x248 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<32>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x248 = reader.read_bytes()?; + + let g_pat = reader.read_bytes()?; let dbgctrl = reader.read_bytes()?; let br_from = reader.read_bytes()?; let br_to = reader.read_bytes()?; let last_excp_from = reader.read_bytes()?; let last_excp_to = reader.read_bytes()?; - // reserved_0x298: [u8;80] - let pkru = reader.skip_bytes::<80>()?.read_bytes()?; + + // reserved_0x298 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<80>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x298 = reader.read_bytes()?; + + let pkru = reader.read_bytes()?; let tsc_aux = reader.read_bytes()?; - // reserved_0x2f0: [u8;24] - let rcx = reader.skip_bytes::<24>()?.read_bytes()?; + + // reserved_0x2f0 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<24>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x2f0 = reader.read_bytes()?; + + let rcx = reader.read_bytes()?; let rdx = reader.read_bytes()?; let rbx = reader.read_bytes()?; - // reserved_0x320 u64 - let rbp = reader.skip_bytes::<8>()?.read_bytes()?; + + // reserved_0x320 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<8>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x320 = reader.read_bytes()?; + + let rbp = reader.read_bytes()?; let rsi = reader.read_bytes()?; let rdi = reader.read_bytes()?; let r8 = reader.read_bytes()?; @@ -630,8 +897,14 @@ impl Decoder<()> for SevEsSaveArea { let r13 = reader.read_bytes()?; let r14 = reader.read_bytes()?; let r15 = reader.read_bytes()?; - // reserved_0x380 [u8;16] - let guest_exit_info_1 = reader.skip_bytes::<16>()?.read_bytes()?; + + // reserved_0x380 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<16>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x380 = reader.read_bytes()?; + + let guest_exit_info_1 = reader.read_bytes()?; let guest_exit_info_2 = reader.read_bytes()?; let guest_exit_int_info = reader.read_bytes()?; let guest_nrip = reader.read_bytes()?; @@ -643,9 +916,14 @@ impl Decoder<()> for SevEsSaveArea { let pcpu_id = reader.read_bytes()?; let event_inj = reader.read_bytes()?; let xcr0 = reader.read_bytes()?; - // reserved_0x3f0: [u8;16] - let x87_dp = reader.skip_bytes::<16>()?.read_bytes()?; + // reserved_0x3f0 + #[cfg(not(feature = "unsafe_parser"))] + reader.skip_bytes::<16>()?; + #[cfg(feature = "unsafe_parser")] + let reserved_0x3f0 = reader.read_bytes()?; + + let x87_dp = reader.read_bytes()?; let mxcsr = reader.read_bytes()?; let x87_ftw = reader.read_bytes()?; let x87_fsw = reader.read_bytes()?; @@ -658,103 +936,217 @@ impl Decoder<()> for SevEsSaveArea { let fpreg_xmm = reader.read_bytes()?; let fpreg_ymm = reader.read_bytes()?; let manual_padding = reader.read_bytes()?; - Ok(Self { - es, - cs, - ss, - ds, - fs, - gs, - gdtr, - ldtr, - idtr, - tr, - vmpl0_ssp, - vmpl1_ssp, - vmpl2_ssp, - vmpl3_ssp, - u_cet, - vmpl, - cpl, - efer, - xss, - cr4, - cr3, - cr0, - dr7, - dr6, - rflags, - rip, - dr0, - dr1, - dr2, - dr3, - dr0_addr_mask, - dr1_addr_mask, - dr2_addr_mask, - dr3_addr_mask, - rsp, - s_cet, - ssp, - isst_addr, - rax, - star, - lstar, - cstar, - sfmask, - kernel_gs_base, - sysenter_cs, - sysenter_esp, - sysenter_eip, - cr2, - g_pat, - dbgctrl, - br_from, - br_to, - last_excp_from, - last_excp_to, - pkru, - tsc_aux, - rcx, - rdx, - rbx, - rbp, - rsi, - rdi, - r8, - r9, - r10, - r11, - r12, - r13, - r14, - r15, - guest_exit_info_1, - guest_exit_info_2, - guest_exit_int_info, - guest_nrip, - sev_features, - vintr_ctrl, - guest_exit_code, - virtual_tom, - tlb_id, - pcpu_id, - event_inj, - xcr0, - x87_dp, - mxcsr, - x87_ftw, - x87_fsw, - x87_fcw, - x87_fop, - x87_ds, - x87_cs, - x87_rip, - fpreg_x87, - fpreg_xmm, - fpreg_ymm, - manual_padding, - }) + + #[cfg(not(feature = "unsafe_parser"))] + { + Ok(Self { + es, + cs, + ss, + ds, + fs, + gs, + gdtr, + ldtr, + idtr, + tr, + vmpl0_ssp, + vmpl1_ssp, + vmpl2_ssp, + vmpl3_ssp, + u_cet, + vmpl, + cpl, + efer, + xss, + cr4, + cr3, + cr0, + dr7, + dr6, + rflags, + rip, + dr0, + dr1, + dr2, + dr3, + dr0_addr_mask, + dr1_addr_mask, + dr2_addr_mask, + dr3_addr_mask, + rsp, + s_cet, + ssp, + isst_addr, + rax, + star, + lstar, + cstar, + sfmask, + kernel_gs_base, + sysenter_cs, + sysenter_esp, + sysenter_eip, + cr2, + g_pat, + dbgctrl, + br_from, + br_to, + last_excp_from, + last_excp_to, + pkru, + tsc_aux, + rcx, + rdx, + rbx, + rbp, + rsi, + rdi, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + guest_exit_info_1, + guest_exit_info_2, + guest_exit_int_info, + guest_nrip, + sev_features, + vintr_ctrl, + guest_exit_code, + virtual_tom, + tlb_id, + pcpu_id, + event_inj, + xcr0, + x87_dp, + mxcsr, + x87_ftw, + x87_fsw, + x87_fcw, + x87_fop, + x87_ds, + x87_cs, + x87_rip, + fpreg_x87, + fpreg_xmm, + fpreg_ymm, + manual_padding, + }) + } + #[cfg(feature = "unsafe_parser")] + { + Ok(Self { + es, + cs, + ss, + ds, + fs, + gs, + gdtr, + ldtr, + idtr, + tr, + vmpl0_ssp, + vmpl1_ssp, + vmpl2_ssp, + vmpl3_ssp, + u_cet, + reserved_0xc8, + vmpl, + cpl, + reserved_0xcc, + efer, + reserved_0xd8, + xss, + cr4, + cr3, + cr0, + dr7, + dr6, + rflags, + rip, + dr0, + dr1, + dr2, + dr3, + dr0_addr_mask, + dr1_addr_mask, + dr2_addr_mask, + dr3_addr_mask, + reserved_0x1c0, + rsp, + s_cet, + ssp, + isst_addr, + rax, + star, + lstar, + cstar, + sfmask, + kernel_gs_base, + sysenter_cs, + sysenter_esp, + sysenter_eip, + cr2, + reserved_0x248, + g_pat, + dbgctrl, + br_from, + br_to, + last_excp_from, + last_excp_to, + reserved_0x298, + pkru, + tsc_aux, + reserved_0x2f0, + rcx, + rdx, + rbx, + reserved_0x320, + rbp, + rsi, + rdi, + r8, + r9, + r10, + r11, + r12, + r13, + r14, + r15, + reserved_0x380, + guest_exit_info_1, + guest_exit_info_2, + guest_exit_int_info, + guest_nrip, + sev_features, + vintr_ctrl, + guest_exit_code, + virtual_tom, + tlb_id, + pcpu_id, + event_inj, + xcr0, + reserved_0x3f0, + x87_dp, + mxcsr, + x87_ftw, + x87_fsw, + x87_fcw, + x87_fop, + x87_ds, + x87_cs, + x87_rip, + fpreg_x87, + fpreg_xmm, + fpreg_ymm, + manual_padding, + }) + } } } diff --git a/src/util/parser_helper/read_ext.rs b/src/util/parser_helper/read_ext.rs index dc7e4fcb..ddff85c9 100644 --- a/src/util/parser_helper/read_ext.rs +++ b/src/util/parser_helper/read_ext.rs @@ -23,6 +23,7 @@ pub trait ReadExt: Read { } /// Read SKIP bytes and verify they are zero; returns a mutable reference to the same reader. + #[cfg(not(feature = "unsafe_parser"))] fn skip_bytes(&mut self) -> Result<&mut Self, std::io::Error> { if SKIP != 0 { // Read in chunks to avoid huge stack allocations for large SKIP. @@ -88,6 +89,7 @@ mod read_ext_tests { assert_eq!(result.unwrap(), 0x78563412); } + #[cfg(not(feature = "unsafe_parser"))] // Test case 2: Skip, Valid Data #[test] fn test_skip_valid_data() { @@ -97,6 +99,7 @@ mod read_ext_tests { assert_eq!(result.unwrap(), 0x78563412); } + #[cfg(not(feature = "unsafe_parser"))] // Test case 3: Skip, Invalid Data #[test] fn test_skip_invalid_data() { diff --git a/src/util/parser_helper/write_ext.rs b/src/util/parser_helper/write_ext.rs index de6a1ffc..2b71e051 100644 --- a/src/util/parser_helper/write_ext.rs +++ b/src/util/parser_helper/write_ext.rs @@ -12,12 +12,16 @@ pub trait WriteExt: Write { value.encode(self, params) } + #[cfg(not(feature = "unsafe_parser"))] fn skip_bytes(&mut self) -> Result<&mut Self, std::io::Error> where Self: Sized, { if SKIP != 0 { - self.write_all(&[0; SKIP])?; + { + // Default behavior: write zeros + self.write_all(&[0; SKIP])?; + } } Ok(self) } @@ -56,6 +60,7 @@ mod write_ext_tests { Ok(()) } + #[cfg(not(feature = "unsafe_parser"))] #[test] fn test_write_bytes_with_skip() -> Result<(), std::io::Error> { let mut writer = MockWriter::default(); @@ -74,4 +79,19 @@ mod write_ext_tests { assert_eq!(writer.written.len(), 0); Ok(()) } + + #[cfg(not(feature = "unsafe_parser"))] + #[test] + fn test_skip_bytes_unsafe_raw_bytes() -> Result<(), std::io::Error> { + let mut writer = MockWriter::default(); + writer.skip_bytes::<4>()?; + + // When unsafe feature is enabled, we should write 4 bytes + assert_eq!(writer.written.len(), 4); + + // The bytes written are uninitialized memory, so we can't predict their exact values + // But we can verify they were written and that the function completed successfully + println!("Unsafe skip_bytes wrote: {:?}", writer.written); + Ok(()) + } } From 46a1e7ae1b5530ac70972614a7c8faff0e4ff742 Mon Sep 17 00:00:00 2001 From: DGonzalezVillal Date: Tue, 20 Jan 2026 16:27:16 +0000 Subject: [PATCH 2/2] chore: add CI linting and tests for unsafe-parser Introduce lint checks and cargo unit tests in GitHub workflows to cover the new unsafe-parser feature. Signed-off-by: DGonzalezVillal --- .github/workflows/lint.yml | 11 +++++ .github/workflows/test.yml | 83 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 1009e5b2..2ced8d1b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,6 +34,17 @@ jobs: toolchain: 1.85.0 - run: cargo clippy --features=crypto_nossl,hw_tests,dangerous_hw_tests --all-targets -- -D clippy::all -D unused_imports -D warnings -D clippy::style + clippy-unsafe-parser: + name: cargo clippy unsafe-parser + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + toolchain: 1.85.0 + - run: cargo clippy --features=unsafe_parser,hw_tests,dangerous_hw_tests --all-targets -- -D clippy::all -D unused_imports -D warnings -D clippy::style + readme: name: cargo rdme runs-on: ubuntu-latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c5094234..e8c46e09 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -213,3 +213,86 @@ jobs: flag: --release features: - crypto_nossl + + sw-unsafe-parser: + name: sw unsafe-parser ${{ matrix.runner }} ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.toolchain }} + - run: cargo test ${{ matrix.profile.flag }} --features=${{ matrix.features }} + + strategy: + fail-fast: false + matrix: + runner: + - ubuntu-latest + - macos-15-intel + - windows-latest + toolchain: + - 1.85.0 + - stable + profile: + - name: debug + - name: release + flag: --release + features: + - unsafe_parser + + sw-unsafe-parser-openssl: + name: sw unsafe-parser-openssl ${{ matrix.runner }} ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.toolchain }} + - run: cargo test ${{ matrix.profile.flag }} --features=${{ matrix.features }} + + strategy: + fail-fast: false + matrix: + runner: + - ubuntu-latest + - macos-15-intel + - windows-latest + toolchain: + - 1.85.0 + - stable + profile: + - name: debug + - name: release + flag: --release + features: + - unsafe_parser + - openssl + + sw-unsafe-parser-crypto_nossl: + name: sw unsafe-parser-crypto-nossl ${{ matrix.runner }} ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: ${{ matrix.toolchain }} + - run: cargo test ${{ matrix.profile.flag }} --features=${{ matrix.features }} + + strategy: + fail-fast: false + matrix: + runner: + - ubuntu-latest + - macos-15-intel + - windows-latest + toolchain: + - 1.85.0 + - stable + profile: + - name: debug + - name: release + flag: --release + features: + - unsafe_parser + - crypto_nossl