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 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(()) + } }