Skip to content

Conversation

@hyperfinitism
Copy link
Contributor

@hyperfinitism hyperfinitism commented Aug 7, 2025

This PR adds support for SEV-SNP Report Version 5 by updating the code and bumping the sev crate.

Fixes #113

What's changed

  • Bump the sev crate to the latest version
  • Modifies the code to support new fields introduced in Report Version 5 (e.g., launch_mit_vector)
  • Update README.md to reflect these changes

⚠️ Temporary Measure (as of 7 Aug 2025)

This PR (draft) is a temporary workaround using an unreleased version of sev. Once an official release of the sev crate with Report V5 support becomes available, I will:

  • Revert the GitHub dependency in Cargo.toml to a versioned release.
  • Regenerate Cargo.lock accordingly.

Added on 28 Aug 2025

The sev crate has been replaced with the latest release v6.3.0. This PR is now ready-for-review.

Summary by Sourcery

Add support for SEV-SNP Report Version 5 by upgrading the sev crate, extending the CLI and request logic to include a new launch mitigation vector parameter, and updating documentation to reflect the changes.

New Features:

  • Add --launch_mit_vector flag to include the launch mitigation vector in derived key requests
  • Extend guest_field_select to accept 7-bit binary strings that cover the new launch mitigation vector field
  • Bump sev dependency to v6.3.0 to enable Report V5 support

Enhancements:

  • Validate guest_field_select input for correct length (6 or 7 bits) and binary format
  • Select message version 2 when launch mitigation vector is provided, otherwise use version 1

Build:

  • Upgrade sev crate to version 6.3.0 in Cargo.toml and update Cargo.lock

Documentation:

  • Update README to document the launch mitigation vector option, updated field select length, and revised field table

@sourcery-ai
Copy link

sourcery-ai bot commented Aug 7, 2025

Reviewer's Guide

Introduce support for SEV-SNP Report Version 5 by bumping the sev crate, extending the key-derivation API to include a launch mitigation vector, and updating the CLI and documentation accordingly.

Entity relationship diagram for Guest Field Select bits update

erDiagram
    DERIVED_KEY {
        u64 guest_field_select
        u64 launch_mit_vector
    }
    DERIVED_KEY ||--o| REPORT_V5 : includes
    REPORT_V5 {
        u64 launch_mit_vector
    }
Loading

Class diagram for updated KeyArgs struct and key derivation

classDiagram
    class KeyArgs {
        +Option<u32> vmpl
        +Option<String> gfs
        +Option<u32> gsvn
        +Option<u64> tcbv
        +Option<u64> lmv
    }
    class DerivedKey {
        +new(root_key_select, GuestFieldSelect, vmpl, gsvn, tcbv, lmv)
    }
    KeyArgs --> DerivedKey: used in get_derived_key()
Loading

File-Level Changes

Change Details Files
Bump sev crate to support Report V5
  • Update Cargo.toml to sev 6.3.0 Git dependency
  • Regenerate Cargo.lock
Cargo.toml
Cargo.lock
Add launch mitigation vector to derived key API
  • Add --launch_mit_vector CLI argument in KeyArgs
  • Allow 6–7 digit guest_field_select binary, validate length and characters
  • Include lmv in DerivedKey::new call and adjust message version based on its presence
src/key.rs
Document new Report V5 fields in README
  • Add launch_mit_vector option to key command usage
  • Update guest_field_select length, bit definitions table, and examples
README.md

Assessment against linked issues

Issue Objective Addressed Explanation
#113 Fix the bug where the 'report' command fails with 'Skipped bytes were expected to be zeroed' when using the --random flag, by ensuring the snp_report_req structure is generated with all reserved bytes zeroed and only user_data populated, in alignment with kernel expectations for SEV-SNP Report Version 5.
#113 Update the codebase to support SEV-SNP Report Version 5, including any new fields or struct layout changes required for compatibility with newer kernels.
#113 Update documentation (README.md) to reflect changes in the report/key command and new options/fields introduced for SEV-SNP Report Version 5.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@hyperfinitism
Copy link
Contributor Author

Build

git clone https://github.com/hyperfinitism/snpguest -b support-v5-format
cd snpguest
cargo build -r

Test 1 (Report Ver 5)

Environment

  • AWS EC2 c6a (AMD Milan)
  • OS — Ubuntu Server 24.04
  • Kernel — 6.8.0-1030-aws

1. Key

sudo snpguest key key.bin vcek -v 0 -g 110000
# failed (as intended?)
error message
ERROR: Failed to request derived key
because: I/O Error Encountered: Launch Mitigation Vector must be provided for message version >= 2
because: Launch Mitigation Vector must be provided for message version >= 2
Error: Failed to request derived key

Caused by:
    0: I/O Error Encountered: Launch Mitigation Vector must be provided for message version >= 2
    1: Launch Mitigation Vector must be provided for message version >= 2
sudo snpguest key key.bin vcek -v 0 -g 110000 -l 0
# successfully fetched

2. Report

sudo snpguest report report.bin report-data.bin -r
# successfully fetched

3. Display

snpguest display report report.bin
# successfully displayed
results (selected)
Attestation Report:

Version:                      5

Guest SVN:                    0

...

Launch Mitigation Vector:     1

Current Mitigation Vector:    1

...

Test 2 (Report Version <= 4)

Environment

  • GCP N2D (AMD Milan)
  • OS — Ubuntu Pro 24.04
  • Kernel — 6.14.0-1012-gcp

1. Key

sudo snpguest key key.bin vcek -v 0 -g 110000
# failed (not intended)
error message
ERROR: Failed to request derived key
because: I/O Error Encountered: Launch Mitigation Vector must be provided for message version >= 2
because: Launch Mitigation Vector must be provided for message version >= 2
Error: Failed to request derived key

Caused by:
    0: I/O Error Encountered: Launch Mitigation Vector must be provided for message version >= 2
    1: Launch Mitigation Vector must be provided for message version >= 2

This behavior is not intended, because the LAUNCH_MIT_VECTOR field is only available in Report Version 5. This is probably a bug originating from the sev crate (sev/src/firmware/guest/mod.rs#L222-L235).

sudo snpguest key key.bin vcek -v 0 -g 110000 -l 0
# failed (as intended)
error message
ERROR: Failed to request derived key
because: Firmware Error Encountered: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
because: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
Error: Failed to request derived key

Caused by:
    0: Firmware Error Encountered: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
    1: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.

2. Report

sudo snpguest report report.bin report-data.bin -r
# successfully fetched

3. Display

snpguest display report report.bin
# successfully displayed
results (selected)
Attestation Report:

Version:                      4

Guest SVN:                    0

...

Launch Mitigation Vector:     None

Current Mitigation Vector:    None

...

@hyperfinitism
Copy link
Contributor Author

The following changes were made to the initial commit.

  • Added switch the version of MSG_KEY_REQ depending on whether the --launch_mit_vector atgument is supplied. (This fixes the issue mentioned in the previous tests.)
  • Added the LAUNCH_MIT_VECTOR bit field to the --guest_field_select argument.

Test 1 (Report Ver 5)

  • AWS EC2 c6a (AMD Milan)
  • OS — Ubuntu Server 24.04
  • Kernel — 6.8.0-1031-aws
sudo snpguest key key.bin vcek -v 0 -g 110000
# => successfully fetched (Msg ver. 1)

sudo snpguest key key.bin vcek -v 0 -g 1100001
# => successfully fetched (Msg ver. 1)

sudo snpguesr key key.bin vcek -v 0 -g 1100001 -l 1
# => successfully fetched (Msg ver. 2)

Test 2 (Report Ver 4)

  • GCP N2D (AMD Milan)
  • OS — Ubuntu 24.04.1
  • Kernel — 6.14.0-1012-gcp
sudo snpguest key key.bin vcek -v 0 -g 110000
# => successfully fetched (Msg ver. 1)

sudo snpguest key key.bin vcek -v 0 -g 1100001
# => Error (Msg ver. 1)

sudo snpguest key key.bin vcek -v 0 -g 110000 -l 1
# => Error (Msg ver. 2) & SEV-guest FW crashed
error message (common)
ERROR: Failed to request derived key
because: Firmware Error Encountered: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
because: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
Error: Failed to request derived key

Caused by:
    0: Firmware Error Encountered: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
    1: Known SEV FW Error: Status Code: 0x16: Given parameter is invalid.
error message (after FW crashed)
ERROR: Failed to request derived key
because: Firmware Error Encountered: Unknown SEV FW Error Encountered: 255
because: Unknown SEV FW Error Encountered: 255
Error: Failed to request derived key

Caused by:
    0: Firmware Error Encountered: Unknown SEV FW Error Encountered: 255
    1: Unknown SEV FW Error Encountered: 255

@tylerfanelli
Copy link
Member

This is only waiting on a new release of sev, correct?

}
if gfs.chars().any(|c| c != '0' && c != '1') {
return Err(anyhow::anyhow!(
"Invalid Guest Field Select option. Must be a binary string."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we perhaps want to make this input hex? Seems like that would be more reasonable.

Copy link
Contributor Author

@hyperfinitism hyperfinitism Aug 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree — specifying this as a fixed-length hex string (16 characters for 64 bits) could reduce confusion compared to the current 6–7 bit binary format.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I support the idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we switch the --guest-field-select argument to hex, should we also unify other inputs such as --launch-mit-vector and --tcbv, which are currently parsed as decimal, into hex as well?

Alternatively, we could provide a parser like:

fn parse_u64_multi_format(s: &str) -> Result<u64, ParseIntError> {
    if let Some(hex) = s.strip_prefix("0x") {
        u64::from_str_radix(hex, 16)
    } else if let Some(bin) = s.strip_prefix("0b") {
        u64::from_str_radix(bin, 2)
    } else {
        u64::from_str_radix(s, 10)
    }
}

and then use it as follows:

#[arg(short, long = "guest_field_select", value_parser = parse_u64_multi_format)]
pub gfs: Option<u64>,

This would allow us to support multiple formats. (Though requiring a 0x prefix for hex values might be slightly inconvenient.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about this, and I like the idea of supporting multiple formats. There isn’t really a single obvious way to provide this information.

The reason GuestFieldSelect was made a binary string is that each field is represented by a binary number—1 meaning enabled and 0 meaning disabled. Meanwhile, the TCB is also a u64 field, but it has a completely different meaning since you’re providing values of the TCB, where each value can be expressed as a decimal. Then, the MIT VECTOR is a vector of values, so hex makes the most sense there.

If you could extend the parser so we can see what that would look like, we could then implement the same approach in other functionality like this:
#117

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I'm thinking of implementing this as a separate module (e.g., src/clparser/*) so that it can be reused easily across different subcommands. Using it from each subcommand should be straightforward.

For this PR, since its primary purpose is to add support for the new ABI version, I would suggest keeping (inheriting) the current implementation (--guest_field_select as binary), and then opening a follow-up PR to introduce the multi-format parser. Do you think that separation makes sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, maybe we will cut a minor release when this PR is merged and then make bigger changes when 7.0.0 and the new parser implementation is merged.

@hyperfinitism
Copy link
Contributor Author

Yes, once a new release of sev is published, I will update the sev dependency in Cargo.toml to the latest version and mark the PR as ready-for-review.

@tylerfanelli
Copy link
Member

Great, thank you. We're currently preparing the 7.0.0 release.

@bssrikanth
Copy link

Recently I hit the issue #113 on one of turin servers, applying this patch resolved the issue with report.

@DGonzalezVillal
Copy link
Member

Hello @hyperfinitism,

We decided to release a 6.3.0 version of the library while we make other major changes to the api prior to 7.0.0. You can probably use this to update the tooling now!

Thank you for your patience and contribution

@hyperfinitism
Copy link
Contributor Author

Hi @DGonzalezVillal,

Thank you for letting us know about the release. I have replaced sev with v6.3.0 release from main.

Once the argument format issue is addressed, I will mark this PR as ready-for-review. However, if you prefer, I can mark this PR as ready-for-review first and discuss/address the argument format issue in a separate issue/PR.

@hyperfinitism hyperfinitism marked this pull request as ready for review August 28, 2025 01:03
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Replace the unwrap() on u64::from_str_radix with proper error handling to prevent potential panics and return a clear user-facing error.
  • Add validation for the --launch_mit_vector value (e.g., range or bit‐length checks) similar to how other key parameters are validated.
  • Pin the Git dependency for the sev crate to a specific commit SHA in Cargo.toml for reproducible builds until the official release is available.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Replace the `unwrap()` on `u64::from_str_radix` with proper error handling to prevent potential panics and return a clear user-facing error.
- Add validation for the `--launch_mit_vector` value (e.g., range or bit‐length checks) similar to how other key parameters are validated.
- Pin the Git dependency for the `sev` crate to a specific commit SHA in Cargo.toml for reproducible builds until the official release is available.

## Individual Comments

### Comment 1
<location> `src/key.rs:90` </location>
<code_context>
+        args.lmv,
+    );
+
+    let msg_ver = if args.lmv.is_some() { 2 } else { 1 };
+
     let mut sev_fw = Firmware::open().context("failed to open SEV firmware device.")?;
</code_context>

<issue_to_address>
The logic for msg_ver may need clarification for future maintainers.

Please document the dependency between msg_ver and lmv, or ensure updates to lmv semantics are consistently reflected in this logic.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
    let msg_ver = if args.lmv.is_some() { 2 } else { 1 };
=======
    // The message version (msg_ver) is determined by the presence of the 'lmv' argument.
    // If 'lmv' is Some, we use version 2; otherwise, we use version 1.
    // IMPORTANT: If the semantics of 'lmv' change, ensure this logic is updated accordingly.
    let msg_ver = if args.lmv.is_some() { 2 } else { 1 };
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `README.md:179` </location>
<code_context>
 | `$ROOT_KEY_SELECT` | is the root key from which to derive the key (either "vcek" or "vmrk"). | required |
 | `-v, --vmpl $VMPL` | option specifies the VMPL level the Guest is running on. | 1 |
-| `-g, --guest_field_select $GFS` | option specifies which Guest Field Select bits to enable as a 6-digit binary string. For each bit, 0 denotes off, and 1 denotes on. | — |
+| `-g, --guest_field_select $GFS` | option specifies which Guest Field Select bits to enable as a binary string (length 6 or 7). For each bit, 0 denotes off, and 1 denotes on. | all 0s |
 | `-s, --guest_svn $GSVN` | option specifies the guest SVN to mix into the key. ||
 | `-t, --tcb_version $TCBV` | option specifies the TCB version to mix into the derived key. ||
</code_context>

<issue_to_address>
Clarify binary string length and update earlier references.

Please ensure all documentation consistently describes the Guest Field Select as a binary string of length 6 or 7.

Suggested implementation:

```
Creates the derived key based on input parameters and stores it. `$KEY_PATH` is the path to store the derived key. `$ROOT_KEY_SELECT` is the root key from which to derive the key (either "vcek" or "vmrk"). The `--guest_field_select` option specifies which Guest Field Select bits to enable as a binary string (length 6 or 7). Each of the bits from *right to left* correspond to Guest Policy, Image ID, Family ID, Measurement, SVN and TCB Version, Launch Mitigation Vector, respectively. For each bit, 0 denotes off, and 1 denotes on. The `--guest_svn` option specifies the guest SVN to mix into the key, the `--tcb_version` option specifies the TCB version to mix into the derived key, and the `--launch_mit_vector` option specifies the launch mitigation vector value to mix into the derived key. The `--vmpl` option specifies the VMPL level the Guest is running on and defaults to 1.

```

```
| `-g, --guest_field_select $GFS` | option specifies which Guest Field Select bits to enable as a binary string (length 6 or 7). For each bit, 0 denotes off, and 1 denotes on. | all 0s |

```

If there are other sections in the README.md that reference Guest Field Select, ensure they also describe it as a binary string of length 6 or 7 for consistency.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

args.lmv,
);

let msg_ver = if args.lmv.is_some() { 2 } else { 1 };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The logic for msg_ver may need clarification for future maintainers.

Please document the dependency between msg_ver and lmv, or ensure updates to lmv semantics are consistently reflected in this logic.

Suggested change
let msg_ver = if args.lmv.is_some() { 2 } else { 1 };
// The message version (msg_ver) is determined by the presence of the 'lmv' argument.
// If 'lmv' is Some, we use version 2; otherwise, we use version 1.
// IMPORTANT: If the semantics of 'lmv' change, ensure this logic is updated accordingly.
let msg_ver = if args.lmv.is_some() { 2 } else { 1 };

Copy link
Member

@tylerfanelli tylerfanelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but this PR seems to be mainly relevant for getting the derived key. What does it have to do with the new report version?

@hyperfinitism
Copy link
Contributor Author

You're right — the new report version (format) itself is handled by the sev crate bump, which resolves report parsing errors. The main substantive change in this PR is indeed the derived key–related functionality. If you think it would help, I can update the PR title to something more explicit like "Support SEV-SNP ABI Spec 1.58".

- Bump sev crate to v6.3.0 for supporting ABI Spec Rev 1.58
- Update Cargo.toml and Cargo.lock
- Modify the `key` subcommand to handle `launch_mit_vector`
- Add description of launch_mit_vector in README.md

Signed-off-by: Takuma IMAMURA <[email protected]>
Copy link
Member

@tylerfanelli tylerfanelli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, LGTM.

@DGonzalezVillal DGonzalezVillal merged commit c1d8292 into virtee:main Aug 28, 2025
12 checks passed
@hyperfinitism hyperfinitism deleted the support-v5-format branch September 4, 2025 12:52
@bssrikanth
Copy link

Currently as users when we checkout latest tagged version which is v0.9.1, which does not have this fix. Is there a plan to tag v0.9.2 near term so that we can check that out instead of main branch?

@tylerfanelli
Copy link
Member

@bssrikanth Not sure if you've already been made aware, but we release v0.9.2 of this tool a few days ago. You should be able to use that now.

@bssrikanth
Copy link

@tylerfanelli I got notified, thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

report command fails with "Skipped bytes were expected to be zeroed"

5 participants