Compare commits

...

19 Commits

Author SHA1 Message Date
Jan Höppner
77083b1cbb New release s390-tools-2.42.1
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 16:34:32 +02:00
Thomas Richter
21c2a04347 cpumf/pai: Remove unnecessary const parameter definition
With glibc 2.43 const-ness is preserved for standard library functions
and a compiler warning will be issued if this is violated.

pai parse_cpulist() receives user input via the parm function
parameter. The parameter is defined as 'const char *' and used as input
value for strchr(). The target pointer (cp) is defined as mutable
'char *' leading to violation of const correctness and this compiler
warning:

pai.c: In function ‘parse_cpulist’:
pai.c:907:20: warning: assignment discards ‘const’ qualifier from
			pointer target type [-Wdiscarded-qualifiers]
  907 |                 cp = strchr(parm, ':');

Since the user input is coming from optarg 'non-const char *', it is
unnecessary to have the function parameters carrying this data defined
as const.

Remove the unnecessary const definition in the function call chain to
fix the described issue.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Suggested-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 15:59:36 +02:00
Thomas Richter
8f2d77c9d3 cpumf/pai: Improve -m XXX argument verification
Speed up the check of the option -m argument and improve
the error message. The argument number must be a power of 2 number
and this check is improved.
Furthermore split the error message and provide one message for
invalid characters and one error message for the argument
not being a power of 2 number.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Eduard Stefes <eddy@linux.ibm.com>
Suggested-by: Juergen Christ <jchrist@linux.ibm.com>
Tested-by: Jan Polensky <japo@linux.ibm.com>
Reviewed-by: Jan Polensky <japo@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 15:59:36 +02:00
Steffen Eiden
b6a4d7a6c1 pvsecret: Update man files
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 15:50:15 +02:00
Steffen Eiden
f223069f0b pvsecret: Fix argument parsing
The latest commit 'promote' a few optional arguments to required.
Fix this breaking behaviour by making them optional again.

Fixes: 080a6678fb ("pvsecret: Add -i -o option variants")
Reported-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Tested-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 15:50:15 +02:00
Steffen Eiden
19a5af8da9 rust/utils: Add functions to combine I/O arguments
Add functions to properly parse required and optional input/output
parameters that have to be combined into one.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-22 15:49:45 +02:00
Steffen Eiden
03b73ab3f9 pvsecret: Update man and Readme
man and README got out of sync with --help over time.
Resync them.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Steffen Eiden
080a6678fb pvsecret: Add -i -o option variants
All pvattest subcommands use the command line option -i <input> and -o
<output> to specify file input and output respectively. pvsecret however
uses mostly positional arguments for <input> and <output> exclusively,
e.g. pvattest check input.bin output.yaml

$ pvsecret add secret.bin

This provides an inconsistent user interface within the Secure
Execution tools and may confuse users.

Add the -i and -o option to the subcommands if applicable.
Input/output can then be specified like so:

$ pvsecret add -i secret.bin
$ pvsecret list -o list.yaml
$ pvsecret verify -i FILE -o out.yaml
$ pvsecret retrieve -i ID -o id.yaml

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Steffen Eiden
1d6f7d0bec pvattest: Update man and Readme
man and README got out of sync with --help over time.
Resync them.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Steffen Eiden
a50d0485c9 pvattest: Add -i -o option variant for check
Most pvattest subcommands use the command line option -i <input> and -o
<output> to specify file input and output respectively. pvattest check
however only uses positional arguments for <input> and <output>, e.g.

$ pvattest check input.bin output.yaml

This provides an inconsistent user interface within the tool and may
confuse users.

Add the command -i and -o option to the check subcommand to bring it in
line with the rest of the tool.

$ pvattest check -i input.bin -o output.yaml

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Steffen Eiden
d2a6a771a5 pvattest: Show perform -i & -o option in help
Show -i & -o option and display them in the help output. Showing the
additional options to the user may provide a better experience. Users
may expect -i /-o options as other subcommands have them as well.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Steffen Eiden
7568a0790f pv: Fix error description
The error texts printed a hardcoded .0 instead of the actual value.
Fix this by using the proper string format arguments.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Fixes: 61c5d7d431 ("rust/pv: Attestation generation and verification support")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Finn Callies
ca0ee966b8 pvics: Add image prereqs in manpage
Specify the requirements for the base image in the pvics manpage.

Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Finn Callies
36a7b2e6eb pvebc: Minor bash improvements
Add minor improvements to the scripts the dracut module calls.

Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Finn Callies
851f63eb03 pvebc: Fix dependency for non EBC guests
For guests that do not make use of the EBC feature the boot should not
be impacted by this module. This requires removing the boot.mount unit
because it will unconditionally create a dependency on a unit that
conflicts with that idea. The downside is that mounting of the boot
partition has to be done manually.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/202
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Finn Callies
3d679f61fc pvebc: Disable unit logging to /boot
The boot partition is not designed for log files. Disable logging of the
EBC units to /boot/sics/log.

Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Finn Callies
9237c5b675 pvebc: Fix kernel module dependencies
Include the required kernel modules unconditionally when this module is
installed into an initramfs.
The new .conf file contains a list of kernel modules that are loaded by
the systemd-modules-load.service systemd unit.

Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Eduard Shishkin
d1ab6be082 zipl/src: Don't modify job->data.dump and job->data.mvdump sequentially
Set job->data.dump.no_compress (job->data.mvdump.force) only after
making sure that the job is 'dump' ('mvdump') respectively. Othrewise,
the second assignment can potentially corrupt the value that was set by
the first assignment.

Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-05-21 13:20:06 +02:00
Jan Höppner
d6c2bac99f Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2026-04-30 17:07:01 +02:00
43 changed files with 630 additions and 207 deletions

View File

@@ -1,6 +1,24 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.42.1 (2026-05-22)__
For Linux kernel version: 7.0
Changes of existing tools:
- cpumf/pai: Improve -m XXX argument verification
- pvattest: Add -i -o option variant for check
- pvattest: Show perform -i & -o option in help
- pvebc: Disable unit logging to /boot
- pvsecret: Add -i -o option variants
Bug Fixes:
- cpumf/pai: Remove unnecessary const parameter definition
- pv: Fix error description
- pvebc: Fix dependency for non EBC guests
- pvebc: Fix kernel module dependencies
- zipl: Don't modify job->data.dump and job->data.mvdump sequentially
* __v2.42.0 (2026-04-30)__
For Linux kernel version: 7.0

View File

@@ -33,7 +33,7 @@ endif
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION := 2
RELEASE := 42
PATCHLEVEL := 0
PATCHLEVEL := 1
DISTRELEASE := build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
export S390_TOOLS_RELEASE

View File

@@ -894,7 +894,7 @@ static int parse_event_attr(char *cp)
}
/* Parse CPU list and event specifications */
static void parse_cpulist(int enr, const char *parm)
static void parse_cpulist(int enr, char *parm)
{
unsigned int evt_attr = 0;
cpu_set_t cmdlist, result;
@@ -948,33 +948,27 @@ static const struct util_prg prg = {
}
};
static void record_cpus_crypto(const char *cp)
static void record_cpus_crypto(char *cp)
{
if (!libcpumf_have_pai_crypto())
errx(EXIT_FAILURE, "No support for PAI crypto counters");
parse_cpulist(S390_EVT_PAI_CRYPTO, cp);
}
static void record_cpus_nnpa(const char *cp)
static void record_cpus_nnpa(char *cp)
{
if (!libcpumf_have_pai_nnpa())
errx(EXIT_FAILURE, "No support for PAI nnpa counters");
parse_cpulist(S390_EVT_PAI_NNPA, cp);
}
/* Mapsize must be power of 2 and larger than 4. Count bits in n and
* return 0 if input is invalid and has a bit count larger than one.
/* Mapsize must be power of 2 and larger than 4. Return true in this case.
*/
static unsigned long check_mapsize(unsigned long n)
static bool check_mapsize(unsigned long n)
{
int bit, cnt = 0;
if (n < 4)
return 0;
for (bit = 0; bit < __BITS_PER_LONG; ++bit)
if (n & (1 << bit))
++cnt;
return cnt == 1 ? n : 0;
return (n & (n - 1)) == 0;
}
static void setprio(const char *prio)
@@ -1040,11 +1034,11 @@ int main(int argc, char **argv)
errx(EXIT_FAILURE, "Invalid argument for -%c", ch);
break;
case 'm':
errno = 0;
mapsize = strtoul(optarg, &slash, 0);
mapsize = check_mapsize(mapsize);
if (errno || !mapsize || *slash)
if (!mapsize || *slash)
errx(EXIT_FAILURE, "Invalid argument for -%c", ch);
if (!check_mapsize(mapsize))
errx(EXIT_FAILURE, "No power of 2 number for -%c", ch);
break;
case 'n':
record_cpus_nnpa(optarg);

View File

@@ -114,8 +114,10 @@ ifneq ($(HAVE_DRACUT),0)
$(INSTALL) -m 755 pvebc/$(SEL_EBC_MODDIR)/module-setup.sh \
pvebc/$(SEL_EBC_MODDIR)/override-crypttab.sh \
pvebc/$(SEL_EBC_MODDIR)/pvebc-wrapper.sh \
pvebc/$(SEL_EBC_MODDIR)/boot-mount.sh \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-modules.conf \
$(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
$(INSTALL) -m 644 pvebc/$(SEL_EBC_MODDIR)/boot.mount \
$(INSTALL) -m 644 pvebc/$(SEL_EBC_MODDIR)/sel-ebc-boot-mount.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-override-crypttab.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-paes-enforce.service \
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-pvebc.service \

View File

@@ -90,11 +90,11 @@ pub enum Error {
#[error("Input does not contain an attestation request")]
NoArcb,
#[error("The attestation request has an unknown version (.0)")]
#[error("The attestation request has an unknown version {0}")]
BinArcbInvVersion(u32),
#[error(
"The attestation request encrypted sice is to0 small (.0). Request probably tampered with."
"The attestation request encrypted sice is to0 small {0}. Request probably tampered with."
)]
BinArcbSeaSmall(u32),

View File

@@ -17,7 +17,7 @@ Create an attestation measurement request
- **perform**
<ul>
Send the attestation request to the Ultravisor
Send the attestation request to the Ultravisor (s390x only.)
</ul>
- **verify**
@@ -150,11 +150,11 @@ Print help (see a summary with '-h').
### Synopsis
`pvattest perform [OPTIONS] [IN] [OUT]`
### Description
Send the attestation request to the Ultravisor. Run a measurement of this system
through /dev/uv. This device must be accessible and the attestation
Ultravisor facility must be present. The input must be an attestation request
created with pvattest create. Output will contain the original request and
the response from the Ultravisor.
Send the attestation request to the Ultravisor (s390x only.) Run a measurement
of this system through /dev/uv. This device must be accessible and the
attestation Ultravisor facility must be present. The input must be an
attestation request created with pvattest create. Output will contain the
original request and the response from the Ultravisor. Only available on s390x.
### Arguments
`<IN>`
@@ -171,6 +171,18 @@ Write the result to FILE.
### Options
`-i`, `--input <FILE>`
<ul>
Specify the request to be sent.
</ul>
`-o`, `--output <FILE>`
<ul>
Write the result to FILE.
</ul>
`-u`, `--user-data <File>`
<ul>
Provide up to 256 bytes of user input User-data is arbitrary user-defined data
@@ -256,7 +268,7 @@ Print help (see a summary with '-h').
## pvattest check
### Synopsis
`pvattest check [OPTIONS] <IN> <OUT>`
`pvattest check [OPTIONS] [IN] [OUT]`
### Description
Check if the attestation result matches defined policies. After the attestation
verification, check whether the attestation result complies with user-defined
@@ -277,6 +289,18 @@ Specify the output file for the check result.
### Options
`-i`, `--input <FILE>`
<ul>
Specify the attestation response to check whether the policies are validated.
</ul>
`-o`, `--output <FILE>`
<ul>
Specify the output file for the check result.
</ul>
`--format <FORMAT>`
<ul>
Define the output format.

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVATTEST-CHECK" "1" "2025-03-12" "s390-tools" "Attestation Manual"
.TH "PVATTEST-CHECK" "1" "2026-05-19" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
@@ -11,7 +11,7 @@ pvattest-check \- Check if the attestation result matches defined policies
.SH SYNOPSIS
.nf
.fam C
pvattest check [OPTIONS] <IN> <OUT>
pvattest check [OPTIONS] [IN] [OUT]
.fam C
.fi
.SH DESCRIPTION
@@ -31,6 +31,18 @@ Specify the output file for the check result.
.RE
.RE
.PP
\-i, \-\-input <FILE>
.RS 4
Specify the attestation response to check whether the policies are validated.
.RE
.RE
.PP
\-o, \-\-output <FILE>
.RS 4
Specify the output file for the check result.
.RE
.RE
.PP
\-\-format <FORMAT>
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVATTEST-CREATE" "1" "2026-02-12" "s390-tools" "Attestation Manual"
.TH "PVATTEST-CREATE" "1" "2026-05-20" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
@@ -21,6 +21,7 @@ Workstation. To avoid compromising the attestation do not publish the
attestation request protection key and shred it after verification. Every
\fBcreate\fR will generate a new, random protection key.
.SH OPTIONS
.PP
\-k, \-\-host\-key\-document <FILE>
.RS 4

View File

@@ -3,11 +3,11 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVATTEST-PERFORM" "1" "2025-03-12" "s390-tools" "Attestation Manual"
.TH "PVATTEST-PERFORM" "1" "2026-05-19" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
pvattest-perform \- Send the attestation request to the Ultravisor
pvattest-perform \- Send the attestation request to the Ultravisor (s390x only.)
.SH SYNOPSIS
.nf
.fam C
@@ -18,7 +18,8 @@ pvattest perform [OPTIONS] [IN] [OUT]
Run a measurement of this system through /dev/uv. This device must be
accessible and the attestation Ultravisor facility must be present. The input
must be an attestation request created with pvattest create. Output will
contain the original request and the response from the Ultravisor.
contain the original request and the response from the Ultravisor. Only
available on s390x.
.SH OPTIONS
.PP
<IN>
@@ -33,6 +34,18 @@ Write the result to FILE.
.RE
.RE
.PP
\-i, \-\-input <FILE>
.RS 4
Specify the request to be sent.
.RE
.RE
.PP
\-o, \-\-output <FILE>
.RS 4
Write the result to FILE.
.RE
.RE
.PP
\-u, \-\-user\-data <File>
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVATTEST-VERIFY" "1" "2026-02-12" "s390-tools" "Attestation Manual"
.TH "PVATTEST-VERIFY" "1" "2026-05-20" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
@@ -26,6 +26,7 @@ solely verifies that the Attestation measurement is correct. It does not check
for the content of additional data or user data. See `pvattest check` for policy
checks after you verified the Attestation measurement.
.SH OPTIONS
.PP
\-i, \-\-input <FILE>
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVATTEST" "1" "2026-02-12" "s390-tools" "Attestation Manual"
.TH "PVATTEST" "1" "2026-05-19" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
@@ -29,7 +29,7 @@ Create an attestation measurement request
\fBpvattest\-perform(1)\fR
.RS 4
Send the attestation request to the Ultravisor
Send the attestation request to the Ultravisor (s390x only.)
.RE
.PP
@@ -47,6 +47,7 @@ Check if the attestation result matches defined policies
.RE
.SH OPTIONS
.PP
\-v, \-\-verbose
.RS 4

View File

@@ -113,20 +113,20 @@ pub enum AttAddFlags {
#[derive(Args, Debug)]
pub struct PerformAttOpt {
/// Specify the request to be sent.
#[arg(hide=true, short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: Option<String>,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<String>,
/// Specify the request to be sent.
#[arg(value_name = "IN", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
pub input_pos: Option<String>,
input_pos: Option<String>,
/// Write the result to FILE.
#[arg(hide=true, short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub output: Option<String>,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
output: Option<String>,
/// Write the result to FILE.
#[arg(value_name = "OUT", value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
pub output_pos: Option<String>,
output_pos: Option<String>,
/// Provide up to 256 bytes of user input
///
@@ -134,7 +134,7 @@ pub struct PerformAttOpt {
/// It is verified during the Attestation measurement verification.
/// May be any arbitrary data, as long as it is less or equal to 256 bytes
#[arg(short, long, value_name = "File", value_hint = ValueHint::FilePath,)]
pub user_data: Option<String>,
user_data: Option<String>,
}
#[cfg(target_arch = "s390x")]
@@ -217,12 +217,20 @@ pub enum OutputType {
#[derive(Args, Debug)]
pub struct CheckOpt {
/// Specify the attestation response to check whether the policies are validated.
#[arg(value_name = "IN", value_hint = ValueHint::FilePath,)]
pub input: PathBuf,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<PathBuf>,
/// Specify the attestation response to check whether the policies are validated.
#[arg(value_name = "IN", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<PathBuf>,
/// Specify the output file for the check result.
#[arg(value_name = "OUT", value_hint = ValueHint::FilePath,)]
pub output: PathBuf,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
output: Option<PathBuf>,
/// Specify the output file for the check result.
#[arg(value_name = "OUT", value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
output_pos: Option<PathBuf>,
/// Define the output format.
#[arg(long, value_enum, default_value_t)]
@@ -300,6 +308,30 @@ pub struct CheckOpt {
pub firmware_verify_url: Option<String>,
}
#[derive(Debug)]
pub struct CheckOptIO<'a> {
pub input: &'a PathBuf,
pub output: &'a PathBuf,
}
impl<'a> From<&'a CheckOpt> for CheckOptIO<'a> {
fn from(value: &'a CheckOpt) -> Self {
let input = match (&value.input, &value.input_pos) {
(None, Some(i)) => i,
(Some(i), None) => i,
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
let output = match (&value.output, &value.output_pos) {
(None, Some(o)) => o,
(Some(o), None) => o,
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
Self { input, output }
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
pub enum HostKeyCheckPolicy {
/// Check the host-key used for the attestation request.

View File

@@ -12,7 +12,12 @@ use self::{
secret_store::secret_store_check,
secret_store::SecretStoreCheck,
};
use crate::{additional::AttestationResult, cli::CheckOpt, exchange::ExchangeFormatResponse};
use crate::{
additional::AttestationResult,
cli::{CheckOpt, CheckOptIO},
exchange::ExchangeFormatResponse,
};
use anyhow::Result;
use log::{debug, info, warn};
use pv::{
@@ -104,7 +109,8 @@ pub struct CheckResult<'a> {
/// Perform the policy checks
pub fn check(opt: &CheckOpt) -> Result<ExitCode> {
let mut input = open_file(&opt.input)?;
let opt_io = CheckOptIO::from(opt);
let mut input = open_file(opt_io.input)?;
let inp = ExchangeFormatResponse::read(&mut input)?;
let auth = AttestationRequest::auth_bin(inp.arcb())?;
let att_res = AttestationResult::from_exchange(&inp, auth.flags())?;
@@ -139,7 +145,7 @@ pub fn check(opt: &CheckOpt) -> Result<ExitCode> {
};
debug!("res {res:?}");
let output = create_file(&opt.output)?;
let output = create_file(opt_io.output)?;
serde_yaml::to_writer(output, &res)?;
match res.successful {

View File

@@ -0,0 +1,31 @@
#!/bin/bash
# SPDX-License-Identifier: MIT
#
# Copyright IBM Corp.
set -eu
mntp="/boot"
block_dev="$(blkid -L boot)"
if [[ -z "${block_dev}" ]]; then
echo "Unable to find partition with label boot"
exit 1
elif [[ ! -b "${block_dev}" ]]; then
echo "Unable to find block device ${block_dev}"
exit 1
else
echo "Found block device ${block_dev}"
fi
if [[ ! -d "${mntp}" ]]; then
echo "Mountpoint ${mntp} does not exist, creating..."
mkdir "${mntp}"
else
echo "Mountpoint ${mntp} exists"
fi
echo "Mounting ${block_dev} to ${mntp}"
mount --options ro "${block_dev}" "${mntp}"
exit 0

View File

@@ -1,28 +0,0 @@
[Unit]
Description=Mount /boot early in initramfs
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs (and not post-pivot if the
# unit ever appears there)
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=root
# we use /dev/disk/by-label because it identifies the boot partition system
# independently IF set up correctly
Requires=dev-disk-by\x2dlabel-boot.device
# Ordering dependencies
After=dev-disk-by\x2dlabel-boot.device
Before=sel-ebc-pvebc.service
[Mount]
# system independent identification of boot partition requires that the label
# boot is set for the boot partition
What=/dev/disk/by-label/boot
Where=/boot
Type=auto
Options=defaults
[Install]
WantedBy=sel-ebc-pvebc.service

View File

@@ -23,11 +23,11 @@ depends() {
# Called by dracut
installkernel() {
# kernel modules needed for opening an encrypted rfs
instmods -c uvdevice
instmods -c paes_s390
instmods -c pkey_uv
instmods -c pkey_pckmo
instmods -c pkey
hostonly='' instmods -c uvdevice
hostonly='' instmods -c paes_s390
hostonly='' instmods -c pkey_uv
hostonly='' instmods -c pkey_pckmo
hostonly='' instmods -c pkey
}
# Called by dracut
@@ -43,8 +43,8 @@ install() {
"$systemdsystemunitdir/sel-ebc-paes-enforce.service"
inst_simple "$moddir/sel-ebc-override-crypttab.service" \
"$systemdsystemunitdir/sel-ebc-override-crypttab.service"
inst_simple "$moddir/boot.mount" \
"$systemdsystemunitdir/boot.mount"
inst_simple "$moddir/sel-ebc-boot-mount.service" \
"$systemdsystemunitdir/sel-ebc-boot-mount.service"
# already exisitng unit we depend on for kernel modules
inst_simple /usr/lib/systemd/system/systemd-modules-load.service \
@@ -58,6 +58,14 @@ install() {
inst_simple "$moddir/override-crypttab.sh" \
"/etc/sel-ebc/override-crypttab.sh"
# mount boot partition to /boot
inst_simple "$moddir/boot-mount.sh" \
"/etc/sel-ebc/boot-mount.sh"
# install kernel module dependencies
inst_simple "$moddir/sel-ebc-modules.conf" \
"/usr/lib/modules-load.d/sel-ebc-modules.conf"
# copy main application
inst_binary "/usr/bin/pvebc"
inst_binary "/usr/bin/pvsecret"
@@ -72,5 +80,5 @@ install() {
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-override-crypttab.service
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-paes-enforce.service
systemctl --root "$initdir" --no-reload --quiet enable systemd-modules-load.service
systemctl --root "$initdir" --no-reload --quiet enable boot.mount
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-boot-mount.service
}

View File

@@ -3,7 +3,20 @@
#
# Copyright IBM Corp.
set -eu
IBM_RSRC_DIR="/etc/sel-ebc"
block_dev="$(blkid -L cryptroot)"
if [[ -z "${block_dev}" ]]; then
echo "Unable to find partition with label cryptroot"
exit 1
elif [[ ! -b "${block_dev}" ]]; then
echo "Unable to find block device ${block_dev}"
exit 1
else
echo "Found block device ${block_dev}"
fi
if [[ ! -f "${IBM_RSRC_DIR}/crypttab" ]]; then
echo "Error: source file $IBM_RSRC_DIR/crypttab does not exist"
@@ -15,6 +28,11 @@ cp "${IBM_RSRC_DIR}/crypttab" "/etc/crypttab"
systemctl daemon-reload
systemctl restart systemd-cryptsetup@cryptroot_mapper.service
udevadm trigger --subsystem-match=block --settle
if ! systemctl restart systemd-cryptsetup@cryptroot_mapper.service; then
systemctl status systemd-cryptsetup@cryptroot_mapper.service
exit 1
fi
exit 0

View File

@@ -48,16 +48,23 @@ fi
pvebc --toc "$EBC_TMPFS/$TOC"
rc=$?
if [[ $rc -ne 0 ]]; then
echo "pvebc failed with rc=${rc}"
exit $rc
fi
# Retrieve and check for dummy LUKS passphrase
pvsecret retrieve --inform name -o "$EBC_TMPFS/$ASR_NAME" --outform bin "$ASR_NAME"
rc=$?
if [[ $rc -ne 0 ]]; then
echo "pvsecret failed with rc=${rc}"
exit $rc
fi
if [[ ! -f "$EBC_TMPFS/$ASR_NAME" ]]; then
echo "$EBC_TMPFS/$ASR_NAME does not exist"
exit 1
fi
chmod 400 "$EBC_TMPFS/$ASR_NAME"
exit 0
exit $?

View File

@@ -0,0 +1,21 @@
[Unit]
Description=Mount a partition identified by label boot to /boot
# Ensure this runs before the handoff to the real root, if that's required:
Before=sel-ebc-pvebc.service
# Initramfs requirement
DefaultDependencies=no
# Make absolutely sure this only runs in initramfs
ConditionPathExists=/etc/initrd-release
ConditionKernelCommandLine=rd.sel-ebc
[Service]
Type=oneshot
ExecStart=/bin/bash /etc/sel-ebc/boot-mount.sh
RemainAfterExit=yes
# On failure immediately abort boot
FailureAction=poweroff-immediate
[Install]
RequiredBy=sel-ebc-pvebc.service

View File

@@ -0,0 +1,5 @@
uvdevice
paes_s390
pkey_uv
pkey_pckmo
pkey

View File

@@ -4,10 +4,8 @@ Description=Override crypttab
# boot partition contains SICS
# Loading of kernel modules is required which are needed for protected keys
Requires=systemd-modules-load.service
Requires=boot.mount
# Ensure this runs before the handoff to the real root, if that's required:
After=boot.mount
After=systemd-modules-load.service
Before=cryptsetup-pre.target
Before=cryptsetup.target
@@ -30,8 +28,8 @@ RemainAfterExit=yes
FailureAction=poweroff-immediate
# boot partition is unencrypted and contains SICS so we can get logs out this way
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
StandardOutput=console
StandardError=console
[Install]
RequiredBy=sel-ebc.target

View File

@@ -20,8 +20,8 @@ FailureAction=poweroff-immediate
RemainAfterExit=yes
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
StandardOutput=console
StandardError=console
[Install]
RequiredBy=sel-ebc.target

View File

@@ -4,14 +4,14 @@ Description=Run pvebc during early boot to process SICS
# boot partition contains SICS
# Loading of kernel modules is required which are needed for protected keys
Requires=systemd-modules-load.service
Wants=boot.mount
Requires=sel-ebc-boot-mount.service
# Ensure this runs before the handoff to the real root, if that's required:
Before=initrd-root-device.target
Before=cryptsetup-pre.target
Before=cryptsetup.target
After=boot.mount
After=systemd-modules-load.service
After=sel-ebc-boot-mount.service
# Initramfs requirement
DefaultDependencies=no
@@ -29,8 +29,8 @@ RemainAfterExit=yes
FailureAction=poweroff-immediate
# boot partition is unencrypted and contains SICS so we can get logs out this way
# logs do not leek any sensitive information
StandardOutput=file:/boot/sics/log
StandardError=file:/boot/sics/log
StandardOutput=console
StandardError=console
[Install]
RequiredBy=sel-ebc.target

View File

@@ -253,6 +253,28 @@ Optional. No user-data by default.
</ul>
`--policy <FILE>`
<ul>
Links an AddSecret-Request (ASR) to a policy file. This option embeds a
PolicyReference in the ASR user data field. The PolicyReference includes the
relative file path and the SHA512 hash of the policy file, allowing the
policys integrity to be verified.
This option conflicts with --user-data, because both options use the same user
data field in the ASR structure.
</ul>
`--toc-policy <FILE>`
<ul>
Adds the AESGCM authentication tag to a TOC policy file. This option appends
the AESGCM authentication tag to the specified TOC policy file. This allows
the TOC policy to maintain a list of all ASR MAC tags for completeness
verification during boot. During verification, the TOC checks the MAC tags
against this list to ensure that all expected ASRs are present and unmodified.
</ul>
`--user-sign-key <FILE>`
<ul>
Use the content of FILE as user signing key. Adds a signature calculated from
@@ -407,14 +429,14 @@ Print help (see a summary with '-h').
## pvsecret add
### Synopsis
`pvsecret add [OPTIONS] <FILE>`
`pvsecret add [OPTIONS] [INPUT]`
### Description
Submit an add-secret request to the Ultravisor (s390x only). Perform an
add-secret request using a previously generated add-secret request. Only
available on s390x.
### Arguments
`<FILE>`
`<INPUT>`
<ul>
Specify the request to be sent.
</ul>
@@ -422,6 +444,12 @@ Specify the request to be sent.
### Options
`-i`, `--input <FILE>`
<ul>
Specify the request to be sent.
</ul>
`-f`, `--force`
<ul>
Force the addition of add-secret requests. Add an add-secret request even if
@@ -445,22 +473,27 @@ fail. Only available on s390x.
## pvsecret list
### Synopsis
`pvsecret list [OPTIONS] [FILE]`
`pvsecret list [OPTIONS] [OUTPUT]`
### Description
List all ultravisor secrets (s390x only). Lists the IDs of all non-null secrets
currently stored in the ultravisor for the currently running IBM Secure
Execution guest. Only available on s390x.
### Arguments
`<FILE>`
`<OUTPUT>`
<ul>
Store the result in FILE.
Default value: '-'
</ul>
### Options
`-o`, `--output <FILE>`
<ul>
Store the result in FILE.
</ul>
`--format <FORMAT>`
<ul>
Define the output format of the list.
@@ -480,7 +513,7 @@ Print help (see a summary with '-h').
## pvsecret verify
### Synopsis
`pvsecret verify [OPTIONS] <FILE>`
`pvsecret verify [OPTIONS] [INPUT] [OUTPUT]`
### Description
Verifies that the given request is an Add-Secret request by testing for some
values to be present. If the request contains signed user-data, the signature
@@ -520,14 +553,27 @@ The verification process works as follows:
### Arguments
`<FILE>`
`<INPUT>`
<ul>
Specify the request to be checked.
</ul>
`<OUTPUT>`
<ul>
Store the result in FILE If the request contained abirtary user-data the output
contains this user-data with padded zeros if available.
</ul>
### Options
`-i`, `--input <FILE>`
<ul>
Specify the request to be checked.
</ul>
`--user-cert <FILE>`
<ul>
Certificate containing a public key used to verify the user data signature.
@@ -540,11 +586,10 @@ curve over a 521 bit prime field (secp521r1).
</ul>
`-o`, `--output <FILE>`
`-o`, `--output <OUTPUT>`
<ul>
Store the result in FILE If the request contained abirtary user-data the output
contains this user-data with padded zeros if available.
Default value: '-'
</ul>
@@ -556,13 +601,13 @@ Print help (see a summary with '-h').
## pvsecret retrieve
### Synopsis
`pvsecret retrieve [OPTIONS] <ID>`
`pvsecret retr [OPTIONS] <ID>`
`pvsecret retrieve [OPTIONS] [INPUT] [OUTPUT]`
`pvsecret retr [OPTIONS] [INPUT] [OUTPUT]`
### Description
Retrieve a secret from the UV secret store (s390x only)
### Arguments
`<ID>`
`<INPUT>`
<ul>
Specify the secret ID to be retrieved. Input type depends on '--inform'. If
`yaml` (default) is specified, it must be a yaml created by the create
@@ -574,12 +619,29 @@ retrieved.
</ul>
`<OUTPUT>`
<ul>
Specify the output path to place the secret value.
</ul>
### Options
`-i`, `--input <ID>`
<ul>
Specify the secret ID to be retrieved. Input type depends on '--inform'. If
`yaml` (default) is specified, it must be a yaml created by the create
subcommand of this tool. If `hex` is specified, it must be a 32 byte handle
encodes in hexadecimal. Leading zeros are required. If there are multiple
secrets in the store with the same Id there are no guarantees on which specific
secret is retrieved. Use --inform=idx to make sure a specific secret is
retrieved.
</ul>
`-o`, `--output <FILE>`
<ul>
Specify the output path to place the secret value.
Default value: '-'
</ul>

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-ADD" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-ADD" "1" "2026-05-21" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -11,7 +11,7 @@ pvsecret-add \- Submit an add-secret request to the Ultravisor (s390x only)
.SH SYNOPSIS
.nf
.fam C
pvsecret add [OPTIONS] <FILE>
pvsecret add [OPTIONS] [INPUT]
.fam C
.fi
.SH DESCRIPTION
@@ -19,12 +19,18 @@ Perform an add\-secret request using a previously generated add\-secret request.
Only available on s390x.
.SH OPTIONS
.PP
<FILE>
<INPUT>
.RS 4
Specify the request to be sent.
.RE
.RE
.PP
\-i, \-\-input <FILE>
.RS 4
Specify the request to be sent.
.RE
.RE
.PP
\-f, \-\-force
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-CREATE-RETRIEVABLE" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-CREATE-RETRIEVABLE" "1" "2026-05-20" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -29,30 +29,30 @@ the following curves: secp256r1, secp384r1, secp521r1, ed25519, or ed448.
\fBHMAC\-SHA preprocessing\fP
.RS 2
The \fBHMAC\-SHA\fP key supplied in the plain bytes file is the key \fBK_0\fP
as of \fBFIPS\-198\-1\fP, i.e. the key \fBK\fP after any necessary
pre\-processing. The pre\-processing must be performed by the user prior to
creating the retrievable secret.
.PP Pre\-processing means that if the key \fBK\fP is shorter than the block
size of the to\-be\-used HMAC digest, then the key must be padded with binary
zeros to the right up to the block size. The block size of SHA\-224 and
SHA\-256 is 512 bits (64 bytes) and the bock size of SHA\-384 and SHA\-512 is
1024 bits (128 bytes). Such padding can for example be achieved by using the
\fBtruncate\fP command with the desired size in bytes, e.g. \fB'truncate
\-\-size 64 <key\-file>'\fP for creating a \fBK_0\fP key for HMAC\-SHA\-224
and HMAC\-SHA\-256.
The \fBHMAC\-SHA\fP key supplied in the plain bytes file is the key \fBK_0\fP as
of \fBFIPS\-198\-1\fP, i.e. the key \fBK\fP after any necessary pre\-processing.
The pre\-processing must be performed by the user prior to creating the
retrievable secret.
.PP Pre\-processing means that if the key \fBK\fP is shorter than the block size
of the to\-be\-used HMAC digest, then the key must be padded with binary zeros
to the right up to the block size. The block size of SHA\-224 and SHA\-256 is
512 bits (64 bytes) and the bock size of SHA\-384 and SHA\-512 is 1024 bits (128
bytes). Such padding can for example be achieved by using the \fBtruncate\fP
command with the desired size in bytes, e.g. \fB'truncate \-\-size 64
<key\-file>'\fP for creating a \fBK_0\fP key for HMAC\-SHA\-224 and
HMAC\-SHA\-256.
.PP
In case key \fBK\fP is longer than the block size of the to\-be\-used HMAC
digest, then key \fBK\fP must first be hashed with the to\-be\-used HMAC
digest, and the result must then be padded with binary zeros to the right up to
the block size of the digest. This can be achieved by using the following
OpenSSL command followed by the \fBtruncate\fP command: \fB'openssl sha256
\-binary \-out <key2\-file> <key\-file>'\fP and then \fB'truncate \-\-size
64 <key2\-file>'\fP for creating a \fBK_0\fP key for HMAC\-SHA\-256.
digest, then key \fBK\fP must first be hashed with the to\-be\-used HMAC digest,
and the result must then be padded with binary zeros to the right up to the
block size of the digest. This can be achieved by using the following OpenSSL
command followed by the \fBtruncate\fP command: \fB'openssl sha256 \-binary
\-out <key2\-file> <key\-file>'\fP and then \fB'truncate \-\-size 64
<key2\-file>'\fP for creating a \fBK_0\fP key for HMAC\-SHA\-256.
.PP
\fBATTENTION:\fP The digest used for hashing the key \fBK\fP must be the exact
same as the later to\-be\-used HMAC digest! If the pre\-processing and the
HMAC calculation use different digests, then a wrong MAC is calculated!
same as the later to\-be\-used HMAC digest! If the pre\-processing and the HMAC
calculation use different digests, then a wrong MAC is calculated!
.RE
.SH OPTIONS

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-CREATE-UPDATE-CCK" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-CREATE-UPDATE-CCK" "1" "2026-05-20" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -18,6 +18,7 @@ pvsecret create cck \-\-secret <CCK\-FILE>
.SH DESCRIPTION
Insert a customer communication key into a guest.
.SH OPTIONS
.PP
\-\-secret <CCK\-FILE>
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-CREATE" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-CREATE" "1" "2026-05-19" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -55,6 +55,7 @@ Update customer communication key
.RE
.SH OPTIONS
.PP
\-k, \-\-host\-key\-document <FILE>
.RS 4
@@ -196,23 +197,23 @@ Optional. No user\-data by default.
.PP
\-\-policy <FILE>
.RS 4
Links an add\-secret request to a policy file.
This option embeds a reference to a policy in the add\-secret request user data field. The
reference includes the relative file path and the SHA-512 hash of the
policy file, enabling verification of the policy files integrity.
This option conflicts with \fB\-\-user\-data\fR, because both options use the
same user data field in the add\-secret request structure.
Links an AddSecret\-Request (ASR) to a policy file. This option embeds a
PolicyReference in the ASR user data field. The PolicyReference includes the
relative file path and the SHA512 hash of the policy file, allowing the
policys integrity to be verified.
This option conflicts with \-\-user\-data, because both options use the same
user data field in the ASR structure.
.RE
.RE
.PP
\-\-toc\-policy <FILE>
.RS 4
Adds the AES\-GCM authentication tag to a table-of-contents (TOC) policy file.
This option appends the AES\-GCM authentication tag to the specified TOC policy
file. This allows the TOC policy to maintain a list of all add\-secret request MAC tags for
completeness verification during boot. During verification, the TOC checks the
AES\-GCM tags against this list to ensure that all expected add\-secret request are present and
unmodified.
Adds the AESGCM authentication tag to a TOC policy file. This option appends
the AESGCM authentication tag to the specified TOC policy file. This allows
the TOC policy to maintain a list of all ASR MAC tags for completeness
verification during boot. During verification, the TOC checks the MAC tags
against this list to ensure that all expected ASRs are present and unmodified.
.RE
.RE
.PP

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-LIST" "1" "2024-12-19" "s390-tools" "UV-Secret Manual"
.TH "PVSECRET-LIST" "1" "2026-05-21" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -11,7 +11,7 @@ pvsecret-list \- List all ultravisor secrets (s390x only)
.SH SYNOPSIS
.nf
.fam C
pvsecret list [OPTIONS] [FILE]
pvsecret list [OPTIONS] [OUTPUT]
.fam C
.fi
.SH DESCRIPTION
@@ -19,13 +19,18 @@ Lists the IDs of all non\-null secrets currently stored in the ultravisor for
the currently running IBM Secure Execution guest. Only available on s390x.
.SH OPTIONS
.PP
<FILE>
<OUTPUT>
.RS 4
Store the result in FILE.
[default: '-']
.RE
.RE
.PP
\-o, \-\-output <FILE>
.RS 4
Store the result in FILE.
.RE
.RE
.PP
\-\-format <FORMAT>
.RS 4

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-RETRIEVE" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-RETRIEVE" "1" "2026-05-21" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -11,8 +11,8 @@ pvsecret-retrieve \- Retrieve a secret from the UV secret store (s390x only)
.SH SYNOPSIS
.nf
.fam C
pvsecret retrieve [OPTIONS] <ID>
pvsecret retr [OPTIONS] <ID>
pvsecret retrieve [OPTIONS] [INPUT] [OUTPUT]
pvsecret retr [OPTIONS] [INPUT] [OUTPUT]
.fam C
.fi
.SH DESCRIPTION
@@ -24,7 +24,7 @@ keys the PEM name \fBIBM PROTECTED KEY\fP is used.
.SH OPTIONS
.PP
<ID>
<INPUT>
.RS 4
Specify the secret ID to be retrieved. Input type depends on \fB\-\-inform\fR.
If `yaml` (default) is specified, it must be a yaml created by the create
@@ -35,12 +35,29 @@ secret is retrieved. Use \-\-inform=idx to make sure a specific secret is
retrieved.
.RE
.RE
.PP
<OUTPUT>
.RS 4
Specify the output path to place the secret value.
.RE
.RE
.PP
\-i, \-\-input <ID>
.RS 4
Specify the secret ID to be retrieved. Input type depends on \fB\-\-inform\fR.
If `yaml` (default) is specified, it must be a yaml created by the create
subcommand of this tool. If `hex` is specified, it must be a 32 byte handle
encodes in hexadecimal. Leading zeros are required. If there are multiple
secrets in the store with the same Id there are no guarantees on which specific
secret is retrieved. Use \-\-inform=idx to make sure a specific secret is
retrieved.
.RE
.RE
.PP
\-o, \-\-output <FILE>
.RS 4
Specify the output path to place the secret value.
[default: '-']
.RE
.RE
.PP

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET-VERIFY" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET-VERIFY" "1" "2026-05-21" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -11,7 +11,7 @@ pvsecret-verify \- Verify that an add-secret request is sane
.SH SYNOPSIS
.nf
.fam C
pvsecret verify [OPTIONS] <FILE>
pvsecret verify [OPTIONS] [INPUT] [OUTPUT]
.fam C
.fi
.SH DESCRIPTION
@@ -81,12 +81,25 @@ verify the signature of the request but the last 16 bytes
.SH OPTIONS
.PP
<FILE>
<INPUT>
.RS 4
Specify the request to be checked.
.RE
.RE
.PP
<OUTPUT>
.RS 4
Store the result in FILE If the request contained abirtary user\-data the output
contains this user\-data with padded zeros if available.
.RE
.RE
.PP
\-i, \-\-input <FILE>
.RS 4
Specify the request to be checked.
.RE
.RE
.PP
\-\-user\-cert <FILE>
.RS 4
@@ -100,11 +113,10 @@ curve over a 521 bit prime field (secp521r1).
.RE
.RE
.PP
\-o, \-\-output <FILE>
\-o, \-\-output <OUTPUT>
.RS 4
Store the result in FILE If the request contained abirtary user\-data the output
contains this user\-data with padded zeros if available.
[default: '-']
.RE
.RE
.PP

View File

@@ -3,7 +3,7 @@
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH "PVSECRET" "1" "2026-02-12" "s390-tools" "UV\-Secret Manual"
.TH "PVSECRET" "1" "2026-05-20" "s390-tools" "UV\-Secret Manual"
.nh
.ad l
.SH NAME
@@ -76,6 +76,7 @@ Retrieve a secret from the UV secret store (s390x only)
.RE
.SH OPTIONS
.PP
\-v, \-\-verbose
.RS 4

View File

@@ -6,7 +6,9 @@ use std::fmt::Display;
use clap::error::ErrorKind::ValueValidation;
use clap::{ArgGroup, Args, CommandFactory, Parser, Subcommand, ValueEnum, ValueHint};
use utils::{CertificateOptions, DeprecatedVerbosityOptions, STDOUT};
use utils::{
combined_path_opt, combined_path_req, CertificateOptions, DeprecatedVerbosityOptions, STDOUT,
};
/// Manage secrets for IBM Secure Execution guests.
///
@@ -292,8 +294,12 @@ impl Display for RetrieveableSecretInpKind {
#[derive(Args, Debug)]
pub struct AddSecretOpt {
/// Specify the request to be sent.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<String>,
/// Specify the request to be sent.
#[arg(value_name = "INPUT", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Force the addition of add-secret requests.
///
@@ -303,6 +309,22 @@ pub struct AddSecretOpt {
pub force: bool,
}
#[derive(Debug)]
pub struct AddSecretOptComb<'a> {
pub input: &'a str,
pub force: bool,
}
impl<'a> From<&'a AddSecretOpt> for AddSecretOptComb<'a> {
fn from(value: &'a AddSecretOpt) -> Self {
let input = combined_path_req(&value.input, &value.input_pos);
Self {
input,
force: value.force,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)]
pub enum ListSecretOutputType {
/// Human-focused, non-parsable output format
@@ -317,19 +339,43 @@ pub enum ListSecretOutputType {
#[derive(Args, Debug)]
pub struct ListSecretOpt {
/// Store the result in FILE
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
pub output: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
output: Option<String>,
/// Store the result in FILE
#[arg(value_name = "OUTPUT", value_hint = ValueHint::FilePath, conflicts_with("output"))]
output_pos: Option<String>,
/// Define the output format of the list.
#[arg(long, value_enum, default_value_t)]
pub format: ListSecretOutputType,
}
#[derive(Debug)]
pub struct ListSecretOptComb<'a> {
pub output: &'a str,
pub format: ListSecretOutputType,
}
impl<'a> From<&'a ListSecretOpt> for ListSecretOptComb<'a> {
fn from(value: &'a ListSecretOpt) -> Self {
let output = combined_path_opt(&value.output, &value.output_pos, STDOUT);
Self {
output,
format: value.format,
}
}
}
#[derive(Args, Debug)]
pub struct VerifyOpt {
/// Specify the request to be checked.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<String>,
/// Specify the request to be checked.
#[arg(value_name = "INPUT", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Certificate containing a public key used to verify the user data signature.
///
@@ -345,8 +391,34 @@ pub struct VerifyOpt {
///
/// If the request contained abirtary user-data the output contains this user-data with padded
/// zeros if available.
#[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
pub output: String,
#[arg(short, long, value_name = "OUTPUT", value_hint = ValueHint::FilePath,)]
output: Option<String>,
/// Store the result in FILE
///
/// If the request contained abirtary user-data the output contains this user-data with padded
/// zeros if available.
#[arg(value_name = "OUTPUT", value_hint = ValueHint::FilePath, conflicts_with("output"))]
output_pos: Option<String>,
}
#[derive(Debug)]
pub struct VerifyOptComb<'a> {
pub input: &'a str,
pub user_cert: Option<&'a str>,
pub output: &'a str,
}
impl<'a> From<&'a VerifyOpt> for VerifyOptComb<'a> {
fn from(value: &'a VerifyOpt) -> Self {
let input = combined_path_req(&value.input, &value.input_pos);
let output = combined_path_opt(&value.output, &value.output_pos, STDOUT);
Self {
input,
user_cert: value.user_cert.as_deref(),
output,
}
}
}
#[derive(Args, Debug)]
@@ -358,12 +430,26 @@ pub struct RetrSecretOptions {
/// handle encodes in hexadecimal. Leading zeros are required. If there are multiple secrets in
/// the store with the same Id there are no guarantees on which specific secret is retrieved.
/// Use --inform=idx to make sure a specific secret is retrieved.
#[arg(value_name = "ID", value_hint = ValueHint::FilePath)]
pub input: String,
#[arg(short, long, value_name = "ID", value_hint = ValueHint::FilePath)]
input: Option<String>,
/// Specify the secret ID to be retrieved.
///
/// Input type depends on '--inform'. If `yaml` (default) is specified, it must be a yaml
/// created by the create subcommand of this tool. If `hex` is specified, it must be a 32 byte
/// handle encodes in hexadecimal. Leading zeros are required. If there are multiple secrets in
/// the store with the same Id there are no guarantees on which specific secret is retrieved.
/// Use --inform=idx to make sure a specific secret is retrieved.
#[arg(value_name = "INPUT", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Specify the output path to place the secret value
#[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath)]
pub output: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath)]
output: Option<String>,
/// Specify the output path to place the secret value
#[arg(value_name = "OUTPUT", value_hint = ValueHint::FilePath, conflicts_with("output"))]
output_pos: Option<String>,
/// Define input type for the Secret ID
#[arg(long, value_enum, default_value_t)]
@@ -400,6 +486,25 @@ pub enum RetrOutFmt {
Bin,
}
#[derive(Debug)]
pub struct RetrSecretOptionsComb<'a> {
pub input: &'a str,
pub output: &'a str,
pub inform: RetrInpFmt,
}
impl<'a> From<&'a RetrSecretOptions> for RetrSecretOptionsComb<'a> {
fn from(value: &'a RetrSecretOptions) -> Self {
let input = combined_path_req(&value.input, &value.input_pos);
let output = combined_path_opt(&value.output, &value.output_pos, STDOUT);
Self {
input,
output,
inform: value.inform,
}
}
}
#[derive(Subcommand, Debug)]
pub enum Command {
/// Create a new add-secret request.

View File

@@ -2,7 +2,10 @@
//
// Copyright IBM Corp. 2023
use crate::{cli::AddSecretOpt, cmd::list::list_uvc};
use crate::{
cli::{AddSecretOpt, AddSecretOptComb},
cmd::list::list_uvc,
};
use anyhow::{bail, Context, Result};
use log::warn;
use pv::{
@@ -13,15 +16,16 @@ use utils::get_reader_from_cli_file_arg;
/// Do an Add Secret UVC
pub fn add(opt: &AddSecretOpt) -> Result<()> {
let opt_comb = AddSecretOptComb::from(opt);
let uv = UvDevice::open()?;
let mut rd_in = get_reader_from_cli_file_arg(&opt.input)?;
let mut rd_in = get_reader_from_cli_file_arg(opt_comb.input)?;
let mut cmd =
AddCmd::new(&mut rd_in).context(format!("Processing input file {}", opt.input))?;
AddCmd::new(&mut rd_in).context(format!("Processing input file {}", opt_comb.input))?;
if let Some(id) = AddSecretRequest::bin_id(cmd.data().unwrap())? {
if list_uvc(&uv)?.iter().any(|e| e.id() == id.as_ref()) {
warn!("There is already a secret in the secret store with that id.");
match opt.force {
match opt_comb.force {
true => warn!("'--force' specified: Adding the secret anyways."),
false => bail!("Unable to add the secret due to duplicated IDs"),
}

View File

@@ -322,7 +322,7 @@ fn write_yaml<P: AsRef<Path>>(
write_out(&yaml_path, secret_info, "secret information")?;
warn!(
"Successfully wrote secret info to '{}'",
yaml_path.display().to_string()
yaml_path.display()
);
Ok(())
}

View File

@@ -4,7 +4,7 @@
use std::io::ErrorKind;
use crate::cli::{ListSecretOpt, ListSecretOutputType};
use crate::cli::{ListSecretOpt, ListSecretOptComb, ListSecretOutputType};
use anyhow::{Context, Error, Result};
use log::{info, warn};
use pv::uv::{ListCmd, SecretList, UvDevice};
@@ -34,11 +34,12 @@ pub fn list_uvc(uv: &UvDevice) -> Result<SecretList> {
/// Do a List Secrets UVC and output the list in the requested format
pub fn list(opt: &ListSecretOpt) -> Result<()> {
let opt_comb = ListSecretOptComb::from(opt);
let uv = UvDevice::open()?;
let secret_list = list_uvc(&uv)?;
let mut wr_out = get_writer_from_cli_file_arg(&opt.output)?;
let mut wr_out = get_writer_from_cli_file_arg(opt_comb.output)?;
match &opt.format {
match opt_comb.format {
ListSecretOutputType::Human => {
write!(wr_out, "{secret_list}").context("Cannot generate output")?
}
@@ -50,10 +51,10 @@ pub fn list(opt: &ListSecretOpt) -> Result<()> {
}
wr_out.flush()?;
if opt.output != STDOUT {
if opt_comb.output != STDOUT {
warn!(
"Successfully wrote the list of secrets to '{}'",
&opt.output
opt_comb.output
);
}
Ok(())

View File

@@ -15,7 +15,7 @@ use pv::{
use utils::get_writer_from_cli_file_arg;
use super::list::list_uvc;
use crate::cli::{RetrInpFmt, RetrOutFmt, RetrSecretOptions};
use crate::cli::{RetrInpFmt, RetrOutFmt, RetrSecretOptions, RetrSecretOptionsComb};
enum Value {
Id(SecretId),
@@ -31,19 +31,19 @@ impl Display for Value {
}
}
impl TryFrom<&RetrSecretOptions> for Value {
impl TryFrom<&RetrSecretOptionsComb<'_>> for Value {
type Error = anyhow::Error;
fn try_from(opt: &RetrSecretOptions) -> Result<Self> {
fn try_from(opt: &RetrSecretOptionsComb) -> Result<Self> {
match opt.inform {
RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(&opt.input)?)? {
RetrInpFmt::Yaml => match serde_yaml::from_reader(&mut open_file(opt.input)?)? {
GuestSecret::Retrievable { id, .. } => Ok(Self::Id(id)),
gs => bail!("The file contains a {gs}-secret, which is not retrievable."),
},
RetrInpFmt::Hex => serde_yaml::from_str(&opt.input)
RetrInpFmt::Hex => serde_yaml::from_str(opt.input)
.context("Cannot parse SecretId information")
.map(Self::Id),
RetrInpFmt::Name => Ok(Self::Id(SecretId::from_string(&opt.input))),
RetrInpFmt::Name => Ok(Self::Id(SecretId::from_string(opt.input))),
RetrInpFmt::Idx => opt
.input
.parse()
@@ -104,8 +104,9 @@ fn retrieve(value: Value) -> Result<RetrievedSecret> {
}
pub fn retr(opt: &RetrSecretOptions) -> Result<()> {
let mut output = get_writer_from_cli_file_arg(&opt.output)?;
let retr_secret = retrieve(opt.try_into()?)
let opt_comb = RetrSecretOptionsComb::from(opt);
let mut output = get_writer_from_cli_file_arg(opt_comb.output)?;
let retr_secret = retrieve((&opt_comb).try_into()?)
.context("Could not retrieve the secret from the UV secret store.")?;
let out_data = match opt.outform {
@@ -115,7 +116,7 @@ pub fn retr(opt: &RetrSecretOptions) -> Result<()> {
write(
&mut output,
out_data.value(),
&opt.output,
opt_comb.output,
"IBM Protected Key",
)?;
Ok(())

View File

@@ -2,7 +2,7 @@
//
// Copyright IBM Corp. 2024
use crate::cli::VerifyOpt;
use crate::cli::{VerifyOpt, VerifyOptComb};
use anyhow::{anyhow, Context, Result};
use log::warn;
use pv::misc::{read_certs, read_file};
@@ -22,16 +22,16 @@ fn read_sgn_key(path: &str) -> Result<PKey<Public>> {
}
pub fn verify(opt: &VerifyOpt) -> Result<()> {
let mut rd_in = get_reader_from_cli_file_arg(&opt.input)?;
let opt_comb = VerifyOptComb::from(opt);
let mut rd_in = get_reader_from_cli_file_arg(opt_comb.input)?;
let mut data_in = Vec::with_capacity(0x1000);
rd_in
.read_to_end(&mut data_in)
.with_context(|| format!("Cannot read input file {}", opt.input))?;
.with_context(|| format!("Cannot read input file {}", opt_comb.input))?;
let verify_cert = opt
let verify_cert = opt_comb
.user_cert
.as_ref()
.map(|p| read_sgn_key(p))
.map(read_sgn_key)
.transpose()
.context("Cannot read user-verification certificate.")?;
@@ -39,9 +39,9 @@ pub fn verify(opt: &VerifyOpt) -> Result<()> {
.context("Could not verify the the Add-secret request")?;
if let Some(user_data) = user_data {
get_writer_from_cli_file_arg(&opt.output)?
get_writer_from_cli_file_arg(opt_comb.output)?
.write_all(&user_data)
.with_context(|| format!("Cannot write user data to {}", opt.output))?;
.with_context(|| format!("Cannot write user data to {}", opt_comb.output))?;
}
warn!("Successfully verified the request.");
Ok(())

View File

@@ -276,6 +276,29 @@ impl DeprecatedVerbosityOptions {
)
}
}
pub fn combined_path_opt<'a, N: AsRef<str>, P: AsRef<str>>(
named: &'a Option<N>,
positional: &'a Option<P>,
default: &'a str,
) -> &'a str {
match (named, positional) {
(None, Some(i)) => i.as_ref(),
(Some(i), None) => i.as_ref(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => default,
}
}
pub fn combined_path_req<'a, N: AsRef<str>, P: AsRef<str>>(
named: &'a Option<N>,
positional: &'a Option<P>,
) -> &'a str {
match (named, positional) {
(None, Some(i)) => i.as_ref(),
(Some(i), None) => i.as_ref(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
}
}
#[cfg(test)]
mod test {

View File

@@ -16,8 +16,9 @@ pub use ::log::LevelFilter;
pub use crate::{
cli::{
get_reader_from_cli_file_arg, get_writer_from_cli_file_arg, print_cli_error, print_error,
CertificateOptions, DeprecatedVerbosityOptions, VerbosityOptions, STDIN, STDOUT,
combined_path_opt, combined_path_req, get_reader_from_cli_file_arg,
get_writer_from_cli_file_arg, print_cli_error, print_error, CertificateOptions,
DeprecatedVerbosityOptions, VerbosityOptions, STDIN, STDOUT,
},
exit_code::{docstring, ExitCodeDoc, ExitCodeTrait, ExitCodeVariantDoc},
file::{AtomicFile, AtomicFileOperation},

View File

@@ -34,6 +34,21 @@ All operations preserve the original base image. Logs are written to a
temporary file, with the filename logged as the first message during runtime.
Temporary artifacts are automatically cleaned up on completion or failure.
.SH Base Image Prerequisites
The following prerequisites have to be fulfilled by the base image:
.IP \(bu 2
label of boot partition set to boot
.IP \(bu 2
label of root partition set to root
.IP \(bu 2
guest is to be backed by a qcow2 image
.IP \(bu 2
an initramfs containing the dracut module 95sel-ebc which is part of s390-tools
.IP \(bu 2
a boot loader specifying that initramfs and a kernel parameter line on which root is specified by label
.IP \(bu 2
any line starting with default= should be removed from /etc/zipl.conf
.SH ACTIONS
.TP
.B list

View File

@@ -160,6 +160,8 @@ struct job_data {
int command_line;
int is_secure;
int is_ldipl_dump;
int no_compress;
int force;
};
static inline struct target *target_at(struct job_target_data *data,

View File

@@ -1548,6 +1548,7 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
}
else
job->data.dump.mem = -1LL;
job->data.dump.no_compress = job->no_compress;
break;
case section_mvdump:
/* DUMP TO MULTI-VOLUME job */
@@ -1570,6 +1571,7 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
(1024LL * 1024LL));
} else
job->data.mvdump.mem = -1LL;
job->data.mvdump.force = job->force;
break;
default:
/* Should not happen */
@@ -2021,8 +2023,8 @@ job_get(int argc, char* argv[], struct job_data** data)
job->noninteractive = cmdline.noninteractive;
job->verbose = cmdline.verbose;
job->add_files = cmdline.add_files;
job->data.dump.no_compress = cmdline.no_compress;
job->data.mvdump.force = cmdline.force;
job->no_compress = cmdline.no_compress;
job->force = cmdline.force;
job->dry_run = cmdline.dry_run;
job->is_secure = SECURE_BOOT_UNDEFINED;
job->is_ldipl_dump = cmdline.is_ldipl_dump;