From 1d2a89b3876ca7169220db001d1feff9f12ac3f5 Mon Sep 17 00:00:00 2001 From: Marc Hartmayer Date: Mon, 2 Feb 2026 15:54:46 +0100 Subject: [PATCH] pvimg: Improve the readability of Display output for control flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Display implementation should produce human-readable output. Convert the flags into a descriptive flag list to improve readability. Reviewed-by: Steffen Eiden Signed-off-by: Marc Hartmayer Signed-off-by: Jan Höppner --- rust/pvimg/src/cmd/create.rs | 4 +- rust/pvimg/src/pv_utils/se_hdr/flags.rs | 134 +++++++++++++++++++++--- 2 files changed, 119 insertions(+), 19 deletions(-) diff --git a/rust/pvimg/src/cmd/create.rs b/rust/pvimg/src/cmd/create.rs index 17640804..2e2f1614 100644 --- a/rust/pvimg/src/cmd/create.rs +++ b/rust/pvimg/src/cmd/create.rs @@ -107,14 +107,14 @@ fn parse_flags( None => PlaintextControlFlagsV1::default(), }; pcf.parse_flags(&plaintext_flags); - debug!("Using plaintext flags: {pcf}"); + debug!("Using plaintext flags: {pcf:#x}"); let mut scf: SecretControlFlagsV1 = match &args.experimental_args.x_scf { Some(v) => try_parse_u64(v, "x-scf")?.into(), None => SecretControlFlagsV1::default(), }; scf.parse_flags(&secret_flags); - debug!("Using secret flags: {scf}"); + debug!("Using secret flags: {scf:#x}"); Ok((pcf, scf)) } diff --git a/rust/pvimg/src/pv_utils/se_hdr/flags.rs b/rust/pvimg/src/pv_utils/se_hdr/flags.rs index c0afd60a..48c32f63 100644 --- a/rust/pvimg/src/pv_utils/se_hdr/flags.rs +++ b/rust/pvimg/src/pv_utils/se_hdr/flags.rs @@ -24,16 +24,23 @@ //! assert!(flags.is_set(PcfV1::AllowDumping)); //! ``` -use std::{fmt::Display, marker::PhantomData, mem::size_of}; +use std::{fmt::Display, fmt::LowerHex, marker::PhantomData, mem::size_of}; use pv::misc::{Flags, Msb0Flags64}; +pub trait IntoEnumIterator { + /// Returns an iterator over all variants of this enum. + fn iter() -> impl Iterator; +} + /// Trait for individual control flag types. /// /// This trait defines the interface for control flag enums, providing methods /// to get the flag's bit position and create enabled/disabled flag data. /// Implementors must be enum types with `#[repr(u8)]` to ensure proper bit positioning. -pub trait ControlFlagTrait: std::fmt::Debug + std::hash::Hash + Copy + Eq + Ord { +pub trait ControlFlagTrait: + std::fmt::Debug + std::hash::Hash + Copy + Eq + Ord + Display + IntoEnumIterator +{ /// Returns the bit position (0-63) for this flag in MSB0 ordering. /// /// # Safety @@ -111,7 +118,7 @@ impl FlagData { /// /// This trait provides methods for parsing, checking, and validating /// control flags used in Secure Execution headers. -pub trait ControlFlagsTrait: Display { +pub trait ControlFlagsTrait { /// The underlying control flag type type T: ControlFlagTrait; @@ -200,6 +207,17 @@ impl ControlFlags { t: PhantomData {}, } } + + /// Returns a vector of all currently enabled flags. + /// + /// # Returns + /// + /// A vector containing all flags that are currently set (enabled) + pub fn flags(&self) -> Vec { + T::iter() + .filter(|flag| self.flags.is_set(flag.discriminant())) + .collect() + } } impl From for ControlFlags { @@ -244,7 +262,7 @@ impl ControlFlagsTrait for ControlFlags { } } -impl Display for ControlFlags { +impl LowerHex for ControlFlags { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let value: u64 = self.flags.into(); write!(f, "{value:#018x}") @@ -303,6 +321,47 @@ pub enum PcfV1 { BackupTargetKeys = 62, } +impl IntoEnumIterator for PcfV1 { + fn iter() -> impl Iterator { + [ + Self::AllowDumping, + Self::NoComponentEncryption, + Self::PckmoDeaTdea, + Self::PckmoAes, + Self::PckmoEcc, + Self::PckmoHmac, + Self::BackupTargetKeys, + ] + .into_iter() + } +} + +impl ControlFlagTrait for PcfV1 {} + +impl Display for ControlFlags { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + write!(f, "{:#066b}", ::from(self.flags)) + } else { + let known_flags = self.flags(); + let mut flags_s = known_flags + .iter() + .map(|flag| format!(" - {flag}")) + .collect::>(); + let known_flags_u64: u64 = Self::from_flags(T::all_enabled(known_flags)).into(); + let unknown_flags = ::from(self.flags) - known_flags_u64; + if unknown_flags != 0x0 { + flags_s.push(format!( + " - unknown flags {:#}", + ::from(unknown_flags) + )); + } + + write!(f, "{}", flags_s.join("\n")) + } + } +} + /// Type alias for plaintext control flags version 1. /// /// This is the primary type used for managing plaintext control flags in @@ -331,18 +390,16 @@ impl Display for PcfV1 { match self { Self::AllowDumping => "allow dumping", Self::NoComponentEncryption => "no component encryption", - Self::PckmoDeaTdea => "DEA and TDEA PCMKO", - Self::PckmoAes => "AES", - Self::PckmoEcc => "ECC PCKMO", - Self::PckmoHmac => "HMAC PCKMO", - Self::BackupTargetKeys => "backup target keys", + Self::PckmoDeaTdea => "DEA and TDEA PCKMO support", + Self::PckmoAes => "AES PCKMO support", + Self::PckmoEcc => "ECC PCKMO support", + Self::PckmoHmac => "HMAC PCKMO support", + Self::BackupTargetKeys => "backup target keys support", } ) } } -impl ControlFlagTrait for PcfV1 {} - /// Secret Control Flags for Secure Execution header version 1. /// /// These flags control various aspects of Protected Virtualization (PV) guest @@ -370,14 +427,33 @@ pub enum ScfV1 { CckUpdateAllowed = 2, } +impl IntoEnumIterator for ScfV1 { + fn iter() -> impl Iterator { + [Self::CckExtensionSecretEnforcement, Self::CckUpdateAllowed].into_iter() + } +} + +impl ControlFlagTrait for ScfV1 {} + +impl Display for ScfV1 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::CckExtensionSecretEnforcement => "CCK extension secret enforced", + Self::CckUpdateAllowed => "CCK update allowed", + } + ) + } +} + /// Type alias for secret control flags version 1. /// /// This is the primary type used for managing secret control flags in /// SE header version 1. pub type SecretControlFlagsV1 = ControlFlags; -impl ControlFlagTrait for ScfV1 {} - impl Default for SecretControlFlagsV1 { /// Creates default secret control flags. fn default() -> Self { @@ -388,8 +464,10 @@ impl Default for SecretControlFlagsV1 { #[allow(clippy::shadow_unrelated)] #[cfg(test)] mod test { - - use super::{ControlFlagTrait, ControlFlagsTrait, PcfV1, PlaintextControlFlagsV1}; + use super::{ + ControlFlagTrait, ControlFlagsTrait, PcfV1, PlaintextControlFlagsV1, ScfV1, + SecretControlFlagsV1, + }; #[test] fn test_from_flags() { @@ -434,7 +512,8 @@ mod test { #[test] fn test_display() { let flags = PlaintextControlFlagsV1::from_flags([PcfV1::NoComponentEncryption.enabled()]); - assert_eq!("0x0000000010000000", format!("{flags}")); + assert_eq!("0x0000000010000000", format!("{flags:#x}")); + assert_eq!(format!("{flags}"), " - no component encryption"); let flags = PlaintextControlFlagsV1::from_flags([ PcfV1::AllowDumping.enabled(), @@ -445,7 +524,28 @@ mod test { PcfV1::PckmoEcc.enabled(), PcfV1::PckmoHmac.enabled(), ]); - assert_eq!("0x00000000300000f2", format!("{flags}")); + assert_eq!("0x00000000300000f2", format!("{flags:#x}")); + assert_eq!( + format!("{flags}"), + " - allow dumping + - no component encryption + - DEA and TDEA PCKMO support + - AES PCKMO support + - ECC PCKMO support + - HMAC PCKMO support + - backup target keys support" + ); + + let flags = SecretControlFlagsV1::from_flags([ + ScfV1::CckExtensionSecretEnforcement.enabled(), + ScfV1::CckUpdateAllowed.enabled(), + ]); + assert_eq!(format!("{flags:#x}"), "0x6000000000000000"); + assert_eq!( + format!("{flags}"), + " - CCK extension secret enforced + - CCK update allowed" + ); } #[test]