rust/pvimg: Add secret flag to allow CCK update

The CCK will be able to be updated by an ultravisor call. For security
reasons, this feature must be enabled at Secure Execution header
creation time.

Because this makes it possible to dump without having set a CCK
earlier, the requirement to specify a CCK when creating an image with
guest dump support is extended to also allow for CCK update instead.

Change a CLI test for this that was a duplicate anyway.

[seiden@linux.ibm.com: Allow --cck & --enable-cck-update simultaneously]
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jakob Naucke <naucke@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Jakob Naucke
2025-04-25 15:49:27 +02:00
committed by Jan Höppner
parent 2cd7c7a875
commit b11bb64732
4 changed files with 55 additions and 11 deletions

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVIMG-CREATE" "1" "2024-12-19" "s390-tools" "Pvimg Manual"
.TH "PVIMG-CREATE" "1" "2025-04-24" "s390-tools" "Pvimg Manual"
.nh
.ad l
.SH NAME
@@ -139,7 +139,7 @@ Secure Execution header protection key is a randomly generated key.
\-\-enable\-dump
.RS 4
Enable Secure Execution guest dump support. This option requires the
\fB\-\-cck\fR option.
\fB\-\-cck\fR or \fB\-\-enable\-cck\-update\fR option.
.RE
.RE
.PP
@@ -163,6 +163,19 @@ Add\-secret requests don't have to provide the CCK\-derived extension secret
.RE
.RE
.PP
\-\-enable\-cck\-update
.RS 4
Enable CCK update support. Requires z17 or up. This option cannot be
used in conjunction with the \fB\-\-enable\-cck\-extension\-secret\fR option.
.RE
.RE
.PP
\-\-disable\-cck\-update
.RS 4
Disable CCK update support (default).
.RE
.RE
.PP
\-\-enable\-pckmo
.RS 4
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption

View File

@@ -95,11 +95,13 @@ pub struct ComponentPaths {
#[derive(Args, Debug)]
#[cfg_attr(test, derive(Default))]
#[command(group(ArgGroup::new("header-flags").multiple(true).conflicts_with_all(["x_pcf", "x_scf"])))]
#[command(
group(ArgGroup::new("header-flags").multiple(true).conflicts_with_all(["x_pcf", "x_scf"])),
group(ArgGroup::new("cck-available").multiple(true)))]
pub struct CreateBootImageLegacyFlags {
/// Enable Secure Execution guest dump support. This option requires the
/// '--cck' option.
#[arg(long, action = clap::ArgAction::SetTrue, requires="cck", group="header-flags")]
/// '--cck' or '--enable-cck-update' option.
#[arg(long, action = clap::ArgAction::SetTrue, requires = "cck-available", group="header-flags")]
pub enable_dump: Option<bool>,
/// Disable Secure Execution guest dump support (default).
@@ -117,6 +119,15 @@ pub struct CreateBootImageLegacyFlags {
#[arg(long, action = clap::ArgAction::SetTrue, conflicts_with="enable_cck_extension_secret", group="header-flags")]
pub disable_cck_extension_secret: Option<bool>,
/// Enable CCK update support. Requires z17 or up. This option cannot be
/// used in conjunction with the '--enable-cck-extension-secret' option.
#[arg(long, action = clap::ArgAction::SetTrue, conflicts_with="enable_cck_extension_secret", group="cck-available", group="header-flags")]
pub enable_cck_update: Option<bool>,
/// Disable CCK update support (default).
#[arg(long, action = clap::ArgAction::SetTrue, conflicts_with="enable_cck_update", group="header-flags")]
pub disable_cck_update: Option<bool>,
/// Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
/// functions (default).
#[arg(long, action = clap::ArgAction::SetTrue, group="header-flags")]
@@ -335,7 +346,12 @@ pub struct CreateBootImageArgs {
///
/// The file must contain exactly 32 bytes of data. This option used to be
/// called '--comm-key' in previous versions.
#[arg(long, value_name = "FILE", visible_alias = "comm-key")]
#[arg(
long,
value_name = "FILE",
group = "cck-available",
visible_alias = "comm-key"
)]
pub cck: Option<PathBuf>,
/// Use the content of FILE as the Secure Execution header protection key.
@@ -495,7 +511,8 @@ mod test {
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"]),
CliOption::new("comm-key", ["--cck", "/dev/null"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"]),
CliOption::new("comm-key", ["--comm-key", "/dev/null"])])),
CliOption::new("comm-key", ["--comm-key", "/dev/null"]),
CliOption::new("enable-cck-update", ["--enable-cck-update"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-pcf", ["--x-pcf", "0x0"]),
CliOption::new("x-scf", ["--x-scf", "0x0"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-psw", ["--x-psw", "0x0"])])),
@@ -507,6 +524,9 @@ mod test {
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-image-encryption", ["--enable-image-encryption"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-header-key", ["--x-header-key", "/dev/null"]),])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-header-key", ["--hdr-key", "/dev/null"]),])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-cck-update", ["--enable-cck-update"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("disable-cck-update", ["--disable-cck-update"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("multiple-cck", ["--disable-cck-update", "--cck", "/dev/null"])])),
];
let invalid_create_args = [
flat_map_collect(remove(mvcanv.clone(), "no-verify")),
@@ -514,7 +534,7 @@ mod test {
flat_map_collect(remove(mvcanv.clone(), "hkd")),
flat_map_collect(remove(mvcanv, "output")),
// missing `--comm-key`
// missing both `--cck' and `--enable-cck-update'
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-dump", ["--enable-dump"])])),
// -v and -q cannot be combined
@@ -535,6 +555,9 @@ mod test {
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("enable-image-encryption", ["--enable-image-encryption"]),
CliOption::new("disable-image-encryption", ["--disable-image-encryption"])])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("x-header-key", ["--hdr-key"]),])),
flat_map_collect(insert(mvca.clone(), vec![CliOption::new("extension", ["--enable-cck-extension-secret"]),
CliOption::new("update", ["--enable-cck-update"])])),
];
let mut genprotimg_valid_args = vec![

View File

@@ -92,6 +92,8 @@ fn parse_flags(
lf.enable_cck_extension_secret,
[ScfV1::CckExtensionSecretEnforcement]
),
flag_disabled!(lf.disable_cck_update, [ScfV1::CckUpdateAllowed]),
flag_enabled!(lf.enable_cck_update, [ScfV1::CckUpdateAllowed]),
]
.into_iter()
.flatten()
@@ -217,14 +219,18 @@ mod test {
let args = CreateBootImageArgs {
legacy_flags: CreateBootImageLegacyFlags {
enable_dump: Some(true),
enable_cck_update: Some(true),
..Default::default()
},
..Default::default()
};
let parsed_flags = super::parse_flags(&args).expect("Failed to parse flags {args:?}");
let mut exp_flags = Vec::from(PlaintextControlFlagsV1::PCKMO);
exp_flags.push(PcfV1::AllowDumping);
let pcf = PlaintextControlFlagsV1::from_flags(PcfV1::all_enabled(exp_flags));
let mut exp_pcf = Vec::from(PlaintextControlFlagsV1::PCKMO);
exp_pcf.push(PcfV1::AllowDumping);
let pcf = PlaintextControlFlagsV1::from_flags(PcfV1::all_enabled(exp_pcf));
assert_eq!(parsed_flags.0, pcf);
let exp_scf = vec![ScfV1::CckUpdateAllowed];
let scf = SecretControlFlagsV1::from_flags(ScfV1::all_enabled(exp_scf));
assert_eq!(parsed_flags.1, scf);
}
}

View File

@@ -205,6 +205,8 @@ impl ControlFlagTrait for PcfV1 {}
pub enum ScfV1 {
/// All add-secret requests must provide an extension secret
CckExtensionSecretEnforcement = 1,
/// Whether CCK can be updated
CckUpdateAllowed = 2,
}
pub type SecretControlFlagsV1 = ControlFlags<ScfV1>;
impl ControlFlagTrait for ScfV1 {}