Compare commits

...

194 Commits

Author SHA1 Message Date
Jan Höppner
c2db7ce05f New release s390-tools-2.35.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 13:23:01 +02:00
Steffen Eiden
0031c762cf rust/pv_core: Fix rusttest owned file descriptor already closed
Newer rust std libary code checks if a fd is already closes and panics.
Test code created a file with fd=17 and relied that test code never
touched the file. This cannot be done anymore. Just use the working dir
as backing file.

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>
2024-10-01 12:16:19 +02:00
Steffen Eiden
7031429d1e rust/pv: Fix new warnings for rustc 1.80
`sizeof` was added into the prelude in rustc 1.80.
This triggers a lint-warning for `unused_qualifications` if rustc 1.80+
is used. Fix this warning by using a use statement to stay compatible
for <1.80.

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>
2024-10-01 12:16:19 +02:00
Steffen Eiden
73d8597db1 rust/pv_core: Clarify error reason for 003* return codes
The RCs 30, 31, 32 may be caused by a malicious host or host bug.
Make this clear and advise to stop the SE-guest.

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>
2024-10-01 12:16:19 +02:00
Marc Hartmayer
77d0d1d1a1 rust/Makefile: Consider HAVE_CARGO in the clean target
This fixes `make clean` errors when cargo is not available:

  $ make clean
  ...
  | make[1]: Entering directory '/home/mhartmay/storage/git/poky/build/workspace/sources/s390-tools/rust'
  | cargo clean  --release
  | /bin/bash: cargo: command not found
  | make[1]: *** [Makefile:72: clean] Error 127

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Finn Callies
77a7e11a51 rust/Makefile: Build pvapconfig only on s390x
Configuring the AP bus only makes sense on s390x.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Suggested-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
279070fa43 zdump/ngdump: Fix seek error on 'zgetdump -d'
When checking CDL formatted DASD for installed dump-tool (zgetdump -d),
we might stumble upon an 'empty' boot record pointer in the volume label
filled with bytes of 0x40 (EBCDIC spaces). This leads to the following
seek error reported:

  # zgetdump -d /dev/dasdb
  zgetdump: Could not seek "/dev/dasdb" (Invalid argument)

Check for empty boot record and return proper error code by
ngdump_get_eckd_part_num() in order to end up with a regular
"No dump tool found" message.

Fixes: f3bcd94524 ("zdump: Add zgetdump -d support for ECKD ldipl-dump")
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
3989e1b741 zipl/src: fix segfault on '--dry-run' for device-based dumps
This fixes a segfault when the option '--dry-run' is specified for
device-based dumps (for which the bootmap file is created on a RAW
device, not formatted with a file system).

The actual status is that the option '--dry-run' for device-based
dumps is not implemented. The implementation is evaluated as not
trivial: In contrast with filesystem-based dumps, it is not possible
to simply make do with rename/unlink of temporary created bootmap.

The fixup returns error on any not file system based dumps being
created with the option '--dry-run'.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
c230b5385a zipl/src: move common checks to disk_is_appropriate()
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
68ecf79b01 zipl/src: cleanups in add_dump_progrem()
Drop a pair of duplicated assignmets
Replace the parameter 'struct job_data' with 'struct job_dump_data'

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
f2960eb0df zipl/src: drop check_dump_device_late()
Move all checks from check_dump_device_late() to disk_is_approproate()
and drop check_dump_device_late() entirely

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
4d004cf8b1 zipl/src: drop never happening case in check_dump_device_late()
In the function check_dump_device_late() drop the case of
(info->device != target_info->device) which never happens. Indeed,
the @info created in check_dump_device_late() coincides with the
@target_info previously created by
prepare_build_program_table_{file, device}.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
d8f504f271 zdump/dfi: Fix vm_info_get() check for non-VR kernel
Since the following kernel commit:
"32db401965f1 s390/mm: Pin identity mapping base to zero"
we can have zero identity_base value in os_info. This makes zgetdump
check for non-VR kernel in vm_info_get() incorrect what leads to missing
data (e.g. UTS kernel version) in 'zgetdump -i' output.
Check for zero kaslr_offset value instead (like crash and makedumpfile
do) in order to identify non-VR kernel.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Jan Höppner
7fb3ee4478 gitignore: Add zipl md files
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
a95bad6c87 zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
Since memory chunks can overlap for vr-kernel dumps stored in elf
format (ngdump, zfcpdump), we need to consider this when converting to
s390 dump output format. For that sort DFI memory chunks by start
address and adjust dfo_s390 logic for identifying memory gaps.
Otherwise we might end up with bogus DFO memory chunks being created.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
147ff1bf49 cpuplugd: Halt cpu hotplugging on vertical polarization
On vertical polarization, kernel can be adjusting CPU capacities
dynamically, and cpuplugd can interfere this with hotplug operations
causing performance degradation. To prevent this, check if system has
switched its polarization state, and act accordingly.
If system is on vertical polarization when daemon starts, no CPU hotplug
action is triggered. If system changes to vertical polarization during
daemon runtime, revert cpuhotplug adjustments and stop further CPU
hotplug actions. If system switches back to horizontal polarization
during runtime of the daemon, start evaluating CPU hotplug rules and
trigger adjustments.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
c91d172c99 cpuplugd/cpu: Rework CPU management functions
Simplify the cpu management parts of cpuplugd code by introducing
functions from libutil and rework some logic to drop some assumptions
about how kernel assigns cpuids.
Right now cpuplugd assumes that the cpuids are always sequential and
there are no gaps in between, however kernel does not guarantee that.
Make cpuplugd compliant by traversing cpu sysfs entries instead.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
0e4992da3a zipl/src: prevent NULL pointer deref when preparing qcow2 images for IPL
This fixes c0f02d2f6 which results in problems when preparing qcow2
images for IPL:

zipl -V --blsdir /tmp/tmp.kdPooQjoBh/boot//loader/entries/ --config /
Program terminated with signal SIGFPE, Arithmetic exception.

Don't use pointer to not initialized struct disk_info after failed
auto-detection of disk parameters. Make the check that the file
locates on the disk in the form of a separate procedure.

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
41da0f0809 zipl/src: make disk type detecton fail
When detecting disk type, the function disk_get_info() is called.
It can fail for various reasons (e.g. when the logial target is not
eligible for boot record installation).

Once disk_get_info() fails, don't proceed with type detection.
Return error instead. When applicable, mark the dump job with
"is_ngdump" flag to avoid extra type detection calls.

Acked-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>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
f43789e16a zipl/src: fix bugs in SCSI dump installation
This fixes d6b702d57 which introduces a problem: SCSI dump
installation fails:

zipl -V -d /dev/mapper/mpathd1
Error: Invalid dump device: Could not read partition table

The reasons:
1) Wrong (logical) device is passed as a target base;
2) In case of 'source_script' the check to make sure that specified
   target is over a partition isn't applicable any more after zipl
   support of complex logical targets (e.g. mirrors).

The fixup passes the physical device as a target base (instead of
the logical one). Also the fixup removes invalid check from
check_dump_device_late() and instead adds a more generic check to
the helper script that data starts beyong the boot area.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Marc Hartmayer
136e5eed8c rustfmt: List experimental group_imports option
This option is experimental, but can still be useful.

While at it, sort the options alphabetically.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
e09753f2a3 chreipl_helper.device-mapper: complete device resolution process
This fixes 670bf3e8 which actually isn't an equivalent refactoring.
The generic dm-device resolution procedure was modified to not resolve
the topmost dm-device in the path. So that any calles who don't expect
it, should complete the resolutioin process by themselves. In case of
chreipl_helper such completion was missed. chreipl(8) utility doesn't
expect dm-devices at the output of chreipl_helper.device-mapper

Example:

NAME                     MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                        8:0    0   20G  0 disk
|-sda1                     8:1    0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /
sdb                        8:16   0   20G  0 disk
|-sdb1                     8:17   0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /

Expected result:
8:16

Actual result:
253:0

As a result, the chreipl(8) "node" option stopped working.
The fixup adds the completion.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Sertonix
fe2d240656 netboot/mk-s390image: Fix size when argument is a symlink
`du -b` by default returns the size of a symlink when it is passed a
symlink. Adding the `-L` option allows passing symlinks to mk-s390image
without resulting in unbootable image.

Signed-off-by: Sertonix <sertonix@posteo.net>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/176
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Frank Heimes
6fc450f696 (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
The .note.package [1] section is not used by the zipl/genprotimg bootloaders,
therefore discard them via linker script.

This fix solves the error:
 /usr/bin/ld: Heap section doesn't conform to the described memory layout
 collect2: error: ld returned 1 exit status
 make[4]: *** [Makefile:77: stage3a.elf] Error 1
 make[4]: Leaving directory '/<>/genprotimg/boot'
 make[3]: *** [Makefile:20: all-recursive] Error 1
 make[3]: Leaving directory '/<>/genprotimg'
 make[2]: *** [Makefile:56: genprotimg] Error 2

[1] https://systemd.io/ELF_PACKAGE_METADATA/

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/174
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/176
[seiden@linux.ibm.com: Add/edit fixes tags]
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:14:16 +02:00
Steffen Eiden
6a55d0c2e5 rust/pv: Lower most lints to warn
Lower the lint level to warn for the styling lints.
This avoids compile issues during packaging for newer tooling with
potential more lint findings.
Still deny compiling if a public symbol has no documentation.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/173
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0e69dc1262 zipl_helper.device-mapper: add support for 'raid' device-mapper target
Introduce target operations (struct target_ops);
For each supported device-mapper target implement
. check_target_status()
. get_target_data()

Add support for new 'raid' device-mapper target, which is now default
in LVM.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
3296d85e35 zipl/src: add support of md-mirrors
Add a script to process mirrored zipl targets managed by Linux "md"
driver (AKA "software mirrors")

. In the file zipl_helper.device-mapper.c implement two handlers
  identified by pairs (ZIPL_UTIL_ID, MD_DRIVER_ID) and
  (CHREIPL_UTIL_ID, MD_DRIVER_ID) for the helpers zipl_helper.md
  and chreipl_helper.md respectively

  . zipl_helper.md: prints sets of target parameters (one such set
    per mirror) for a specified logical zipl target managed by linux
    "md" driver.

  . chreipl_helper.md: for a specified logical zipl target managed
    by linux "md" driver prints a random disk from the set of disks
    participating in the mirrored setup.

. Add zipl_helper.md and chreipl_helper.md as symbolic links to
  zipl_helper.device-mapper

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0eeab96f0d zipl_helper.device-mapper: check status of "mirror" dm targets
For "mirror" device-mapper targets:

. Check status of all the mirrors;
. Return error if some mirror contain failures;
. Align the sample output properly

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
283a61dc2f zipl_helper.device-mapper: support multiple base disks
For "mirror" device-mapper targets:

. Don't assign a logical mirrored device as a zipl target base.
  Instead, add one more branch in complete_physical_device() and
  proceed (in that new branch) to the physical disk participating
  in the mirrored target. This approach allowes to handle
  heterogeneous mirrors properly;
. Provide a set of target parameters for each found physical disk
  by calling dm_dev_to_zipl_params() recursively;
. Don't allow "nested mirrors" by checking/updating the
  fail_on_mirror global;
. Remove the requirements on including block #0 to the mirrored
  device-mapper setup (no more actual);
. Update comments.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
670bf3e870 zipl: refactor zipl_helper.device-mapper
This is used by the next patches in the series to support mirror
setups not including boot sectors (e.g. mirrors over partitions).

. Rework the core procedure of device resolution (by walking along
  the device-mapper tree during logical device resolution) to be an
  explicit sequence of pairs (level-lookup, goto-parent-level);
. Add an "extended" device to keep a track of file system offset
  while ascending the device tree;
. Identify all possible results of a single level lookup;
. Rename target_entry to dmpath_entry;
. Make the main() function to look like a call of a handler
  identified by a pair (driver-id, util-id) and found by the name
  of the executable.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
9cfaac58ea zipl_helper.device-mapper: fix bug in get_physical_device()
Fix mistake in @fs_offset calculation.

Since any logical dm-device can be built of partitions, @fs_offset
must not decrease while ascending the "device tree" during the
procedure of dm-device resolution (which always starts at the
formatted logical device, for which @fs_offset is 0).

This bug was not reproducible earlier because of restricted
functionality in a combination with side-effects. The fixup is
required however by the next patches in the series implementing
support of mirrored targets by zipl tool

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
d6b702d579 zipl/src: add basic support for multiple target base disks
. Modify disk_get_info() to process multiple sets of target parameters
  provided by the helper script and store it in the array of "targets"
  of the structure job_target_data;
. Besides the logical device, maintain an array of physical base disks
  in the disk_info structure;
. Use the logical target device only to create bootmap (it is
  automatically mirrored by the respective linux driver (dm, or md)
  managing the mirrored target). In contrast, install bootstrap blocks
  to each physical base disk individually, bypassing that driver;
. Report in verbose mode on which base disks the bootstrap
  installation was performed;
. Use the following logic of setting @info->device (which is printed
  as "Device...:" in verbose mode):
  . source_auto   - the target base disk is set;
  . source_script - the target (logical) device is set;
  . source_user   - the device specified by user (via --targetbase
                    option), or config file is set.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Peter Oberparleiter
d9a9bd8dcf zdev: Add option to select IPL device
Add new command-line option --ipldev. When specified and IPL was done
from a supported device type, the IPL device is selected for the
requested tool operation.

Example to list IPL device information:

$ lszdev --ipldev

Example to create a persistent configuration for the IPL device:

$ chzdev --enable --persistent --ipldev

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Peter Oberparleiter
cad4e9e15b zdev: Add function for reading text files
Reduce code complexity by adding a utility function for reading text
files based on a variable path.

Note: chzdev/lszdev tools apply special path-handling via command line
option --base to allow redirecting hard-coded paths therefore libutil's
util_file functions cannot easily be used.

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Eduard Shishkin
c0f02d2f68 zipl/src: Fix problems when target parameters are specified by user
Steps to reproduce: Prepare some disk for IPL, specifying its
parameters via zipl "target options", and an image IMAGE_NAME
located on another disk. Don't specify "-a" option.

Actual result: Installation succeeded (resulting in unbootable setup)
Expected result: "Error: Could not add image file 'IMAGE_NAME': File
is not on target device"

The problem is in incorrect evaluation of device number (dev_t)
of the base disk where the image is located by the function
add_component_file_range() in case when target parameters are
specified by user.

Fixup: Retrieve info of the underlying disk without any user hints,
passing zeroed structure job_target_data

This is an improved version of fb0b6263d that was reverted by
63ff07ba3 afterwards. The shortcoming of the original ( fb0b6263d )
fix: it fails to prepare for IPL mounted qcow2 images.
The difference from the original fix: when making sure that boot
files are located on the target disk: in case of failed auto-detection
of disk parameters skip the check with warnings instead of aborting
the whole installation session.

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
5218c243f4 cpacfstats: add MSA 10 and MSA 11 counters
MSA 10 and MSA 11 introduce new function codes containing Full XTS
functions for KM instruction and HMAC functions for KMAC instruction.
Additional Full XTS and HMAC for PCKMO instruction is introduced.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
c364692e7a cpacfstats: white space fix in cpacfstats/cpacfstatsd.c
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Nihar Panda
41eb7d076f ziomon/ziorep_config: fix warning when multipath device is not there
Perl logs warning message if a variable is not initialized.
get_device_data() set mp_dev with multipath device for a scsi disk device.
mp_dev remain uninitialized if there is no multipath device.
This can happen if a scsi device is not managed by dm multipath driver.

Warning message:
"Use of uninitialized value in subroutine entry at /usr/sbin/ziorep_config line 136"

Fix it by skipping the code dealing with mp_dev and continue with next
scsi device in the loop.

To reproduce, remove a scsi device from dm multipath.
$multipathd -k'del path sdh'
Then run `ziorep_config -D`.

Signed-off-by: Nihar Panda <niharp@linux.ibm.com>
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Joern Siglen
1062a7cde6 dbginfo.sh: add network sockstat info
Add procfs files to collect network socket data.

Suggested-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:31:33 +02:00
Jan Höppner
54e5e99657 Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:58 +02:00
Jan Höppner
4c922b105b New release s390-tools-2.34.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:42 +02:00
Mikhail Zaslonko
4b19b9d950 zdump/dfi_s390: Get rid of device type check for s390_ext dump
Simplify ioctl error processing logic for "BLKSSZGET" operation.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
cee4bb4995 libkmipclient: Fix typo in debug message
Fix copy & paste error in debug message

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
c98d8e7629 libkmipclient: Remove superfluous break
A double break in a switch does not make any sense, remove it.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Joern Siglen
96084339f5 dbginfo.sh: update/add additional DASD collection
We changed lscss for more detailed output.
Adding use of dasdview for a detailed view on DASD storage.
This data will be collected in a separate file, as many DASDs might flood
the runtime.out
Also updated man pages as a new step is added

Reviewed-by: Stefan Hberland <sth@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Harald Freudenberger
f8d5b4b341 rust/pvapconfig: add dead_code pragmas to suppress warnings
The ap.rs code is already prepared for possible support
for CCA mode APQNs for the Secure Execution environment.
However, this patch marks these fields and structs with
pragma allow(dead_code) to prevent warnings during cargo
build of pvapconfig.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
5806c4e1f4 ap_tools/ap-check: implement get capabilities callout
Add a new action type 'capabilities' for the 'get' event.  This
will return a JSON list of events and actions that the callout
script recognizes and actually does something with.  It omits
events like 'notify' and actions like 'list' that ap-check
currently ignores.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
9d199e06cb ap_tools/ap-check: implement dynamic config during live modify
mdevctl introduces a new event type 'live' with action 'modify',
indicating that the specified configuration changes should be
made dynamically if possible.  Use this as a trigger to perform
dynamic configuration changes to the specified vfio-ap device
if it is active.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f7425a08d1 ap_tools/ap-check: refactor active config checking
Create a single routine to perform conflict analysis for a
given device against the active configuration.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f6a97902c3 libap: handle reading ap_config attribute
While unlikely, it is possible for a vfio-ap configuration JSON
to include the 'ap_config' attribute.  In this case, process it
by overwriting the current list of adapters, domains and control
domains for the associated vfio-ap device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
962af1a90e libap: add routines to generate masks for vfio_ap_device
Add routines to generate mask values for the adapters, domains and
control domains for a specified vfio_ap_device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
46dadc8cc4 libap: add routine to check for dynamic config support
For a given vfio-ap mdev, determine whether or not the device will
need dynamic config operations.  This boils down to whether or not
the device is currently active + whether or not the kernel is
detected to support dynamic config operations (via the
'ap_config' sysfs attribute).

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
9c8d117cc2 zdev: remove duplicate ap_node structure
There is already an identical vfio_ap_node defined in libap, use
that instead.  Also remove one awkard usage of struct ap_node in
libap.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Vineeth Vijayan
d7b3196286 zdev: fix warning about failed ATTR writes by udev
The qeth-udev-rule execution logs a warning as below in the journalfs.

Failed to write ATTR{/sys/bus/ccwgroup/drivers/qeth/group}, \
ignoring: Invalid argument

This occurs because the udev rule for qeth devices is triggered by
multiple ccw devices and can be invoked in parallel. This can lead to a
situation where each of the three parallel-running udev rules tries to
group the devices simultaneously. As a result, only the first rule
succeeds, while the others fail with an -EINVAL error because the CCW
devices have already been grouped.

To prevent this, schedule a new change uevent for the base device, which
will verify the sysfs before attempting the grouping. The change event is
triggered by all three devices, ensuring that the actual write to the
attribute occurs only once and only when the sysfs attribute is ready.

Hence the add events on different devices are serialized to change event
on the base device, which then prevent duplicate concurrent grouping
attempts.

Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-07-08 09:25:12 +02:00
Alexander Egorenkov
b6c30404bc zfcpdump: drop use of mmap() for /proc/vmcore
The function copy_table_entry_write() maps/unmaps /proc/vmcore for each
64kB of the file in order to write its content to a dump partition.
This requires a page allocation of order 2 in kernel (crst_table_alloc)
each time a mmap() syscall is performed and which cannot always be
fulfilled due to external memory fragmentation. And this in turn
results in a OOM kernel panic while writing /proc/vmcore content to
a dump partition. To make zfcpdump more robust in the face of such
problems with page allocations of order > 0, we use a simple file
read/write loop to transfer the content of /proc/vmcore to a dump
partition. This solution is less efficient (by not much) than the old
one with mmap() because it requires additional user space copy but
we trade off here efficiency for robustness which is more important
for zfcpdump.

We use a statically allocated buffer to read data into from /proc/vmcore
and write to a dump partition to avoid repeated use of the memory
mapping kernel path which would be required for a buffer allocated
dynamically at each entry of copy_table_entry_write().

Another possible and very convenient solution would be to use sendfile()
which would avoid any user space copies but, unfortunately, sendfile()
doesn't work with large /proc files.

Example of failed mmap() call for /proc/vmcore
==============================================

  [   26.568654] init invoked oom-killer: gfp_mask=0x40cc0(GFP_KERNEL|__GFP_COMP), order=2, oom_score_adj=0
  [   26.568665] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568668] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568669] Call Trace:
  [   26.568671]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568676]  [<000003ffe00f15c8>] dump_header+0x58/0x2d0
  [   26.568680]  [<000003ffe00f219a>] out_of_memory+0x252/0x348
  [   26.568683]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568686]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568688]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568693]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568696]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568698]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568701]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568703]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568705]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568707]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568709]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568711]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568713]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568715]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568716]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568718]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568720]  [<000003ffe03478b0>] system_call+0x70/0x98
  [   26.568724] Mem-Info:
  [   26.568725] active_anon:1 inactive_anon:12 isolated_anon:0
                  active_file:83590 inactive_file:93939 isolated_file:0
                  unevictable:201 dirty:17845 writeback:4
                  slab_reclaimable:4259 slab_unreclaimable:1482
                  mapped:174 shmem:0 pagetables:810
                  sec_pagetables:0 bounce:0
                  kernel_misc_reclaimable:0
                  free:2694 free_pcp:105 free_cma:0
  [   26.568729] Node 0 active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB isolated(anon):0kB isolated(file):0kB mapped:696kB dirty:71380kB writeback:16kB shmem:0kB writeback_tmp:0kB kernel_stack:544kB pagetables:3240kB sec_pagetables:0kB all_unreclaimable? no
  [   26.568732] DMA free:10776kB boost:0kB min:3496kB low:4368kB high:5240kB reserved_highatomic:0KB active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB writepending:71360kB present:786428kB managed:764664kB mlocked:0kB bounce:0kB free_pcp:420kB local_pcp:420kB free_cma:0kB
  [   26.568735] lowmem_reserve[]: 0 0 0
  [   26.568738] DMA: 1069*4kB (UH) 757*8kB (UH) 11*16kB (H) 6*32kB (H) 1*64kB (H) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 10764kB
  [   26.568747] 177773 total pagecache pages
  [   26.568748] 196607 pages RAM
  [   26.568748] 0 pages HighMem/MovableOnly
  [   26.568749] 5441 pages reserved
  [   26.568749] Tasks state (memory values in pages):
  [   26.568750] [  pid  ]   uid  tgid total_vm      rss rss_anon rss_file rss_shmem pgtables_bytes swapents oom_score_adj name
  [   26.568751] Out of memory and no killable processes...
  [   26.568752] Kernel panic - not syncing: System is deadlocked on memory
  [   26.568755] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568758] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568759] Call Trace:
  [   26.568760]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568763]  [<000003ffe001f14e>] panic+0x10e/0x2e8
  [   26.568765]  [<000003ffe00f21c8>] out_of_memory+0x280/0x348
  [   26.568768]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568771]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568773]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568776]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568779]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568781]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568784]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568787]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568789]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568791]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568793]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568795]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568797]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568799]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568801]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568803]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568805]  [<000003ffe03478b0>] system_call+0x70/0x98

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6d15850480 zdump: Use os_info data to convert dump vaddr to paddr
For vr-kernel dumps use the offsets stored in os_info entries for
virt to phys address conversion when dump virtual address is to be
read, (e.g. vmcoreinfo symbols) using similar method as implemented
in crash-utility.
It is mainly required for reading "init_uts_ns" symbol and, in case
of crashed kdump, "lowcore_ptr" symbol along with a pointers to the
lowcore of every CPU.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
858da9af57 zdump: Use os_info.h from include/boot
Get rid of duplicate os_info definitions in dfi_vmcoreinfo.c

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
a7373674bf include/boot/os_info: Add static assert for os_info size
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
613353cd33 zdump/dfi_elf: Support core dumps of vr-kernels
Support vmcore based dumps (ngdump, zfcpdump) with uncoupled physical and
virtual addresses. For that we just remove p_paddr != p_vaddr sanity check
for elf load headers.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Peter Oberparleiter
f6e932e0fd libutil: Make formatted meta-data configurable
Output generated using libutil's util_fmt_*() functions contains
meta-data such as hostname and time of invocation. When writing test
cases that compare expected and actual tool output, this run-time
variable information needs to be filtered out, resulting in increased
complexity.

To address this, add a global option to suppress meta-data output via
environment variable FMT_NOMETA. If set to '1', no meta-data will be
generated.

Example:

$ FMT_NOMETA=1 chpstat --format json

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7e31c425c9 rust/pv: Try again if first CRL-URI is invalid
The previous implementation did stop after the first download was
successful, even if it did not contain a CRL. This behavior renders a
second, third, ... link as backup location useless as the code ignores
them if the URI e.g. contains a error message. That results in not
having a CRL and probably a failed certificate verification.

Fix this by trying again if the download was successful but did not
contain a CRL

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6c4171b775 zdump/dfi_s390: Adjust device type check for s390_ext dump
In order to allow loop devices usage for DASD dump emulation in fvt-tests,
do not bail out on ZG_TYPE_DASD device type returned by zg_type() for
s390_ext dump.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Jan Höppner
0b0960254e s390-tools: Replace 'which' with built-in 'command -v'
There are still a few scripts using the 'which' command to determine
either the full path or the mere existence of an executable.
Some of these scripts might run in minimal environments where 'which' is
not available due to dependency restriction. 'which' is also considered
unreliable for historical implementation details.

Use the POSIX defined [1] built-in 'command -v' instead to reduce
package dependencies and improve reliability.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
4d2c9267c2 dumpconf: add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
The new parameter 'SCP_DATA' can be used to pass additional kernel cmdline
parameters to a stand-alone SCSI/NVMe/ECKD dumper for debugging purposes.

Configuration example
=====================

ON_PANIC=dump_reipl
DUMP_TYPE=fcp
DEVICE=0.0.4711
WWPN=0x5005076303004711
LUN=0x4711000000000000
BOOTPROG=0
BR_LBA=0
SCP_DATA="dump_debug=6 ignore_loglevel earlyprintk=sclp panic_print=3"

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
7ea0dfdc17 dumpconf: fix whitespace in sysconfig example for ECKD dump device
Make it conform with every other example.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
2d3aac1241 dumpconf: fix coding style of CheckDeviceString()
Make it conform with the naming style used for every other function in
this script.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
c7fd515790 zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
When dump is copied to the filesystem in s390 format, follow on
'zgetdump -i' can fail with ioctl error:

  # zgetdump /dev/dasdb1 -f s390 dump.s390
  Format Info:
      Source: s390_ext
      Target: s390

  Copying dump:
      00000001 / 00008192 MB
      00003688 / 00008192 MB
      00006646 / 00008192 MB
      00008192 / 00008192 MB
  Success: Dump has been copied

  # zgetdump -iVVVV dump.s390

  zgetdump: Operation "BLKSSZGET" failed on "dump.s390" (Inappropriate ioctl for device)

Call ioctl(BLKSSZGET) only for s390_ext dump format (dump can be
stored on DASD partition only, not on the filesystem). For s390 format
a blocksize is not required for dump processing since s390 dump data is
not compressed.

Fixes: 271b809495 ("zdump/dfi_s390: Support reading compressed s390_ext dumps")
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7a4ec55d77 rust/pvattest: Add short option for --arpk
pvattest-C had a -a option for --arpk which the Rust implementation
missed.
Add this short option.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Marc Hartmayer
63ff07ba38 Revert "zipl/src: Fix problems when target parameters are specified by user"
The commit fb0b6263d1 ("zipl/src: Fix problems when target parameters
are specified by user") breaks the case where the user has to provide
all target attributes via the zipl command line, because the target
device cannot be used to retrieve those attributes.

$ zipl -V --blsdir /tmp/tmp.xHmFUdgBCi/boot//loader/entries/ --config /tmp/tmp.dSv9MJ3svs
Looking for components in '/lib/s390-tools'
Using config file '/tmp/tmp.dSv9MJ3svs' (from command line)
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//50_normal.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//45_normal_swiotlb.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//40_pv.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//30_pv_reboot.conf'
Secure boot support: yes
Target device information
  Device..........................: 2b:00
  Device name.....................: nbd0 *)
  Device driver name..............: nbd
  Type............................: disk device
  Disk layout.....................: SCSI disk layout *)
  Geometry - start................: 2048 *)
  File system block size..........: 4096
  Physical block size.............: 512 *)
  Device size in physical blocks..: 2095071
  *) Data provided by user.
Building bootmap in '/tmp/tmp.xHmFUdgBCi/boot/'
Building menu 'zipl-automatic-menu'
Adding #1: IPL section 'Normal Guest' (default)
  initial ramdisk...: /tmp/tmp.xHmFUdgBCi/boot//ramdisk-s390x
  kernel image......: /tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x
zIPL environment block content:
Error: Could not add image file '/tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x': Could not get disk geometry

This reverts commit fb0b6263d1.

Acked-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Frank Heimes
26d7eed0aa zfcpdump: Do not save timestamps when compressing
Having timestamps in gzip leads to lintian warning
'package-contains-timestamped-gzip' and will harm reproducible builds.
Gzip option '-n' avoids saving original file name and especially timestamps
by default.

Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/169
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
[seiden@linux.ibm.com: Fix commit message]
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:13 +02:00
Frank Heimes
e0034eddbf s390-tools: Fix typos in code and man page files
Fix typos reported by (Debian) lintian.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/168
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:09 +02:00
Jan Höppner
0e3034c0f6 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
686262fdcd New release s390-tools-2.33.1
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
2379fd8a58 s390-tools: Fix release string
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Jan Höppner
3552a27ae6 s390-tools: Fix README.md
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
Steffen Eiden
39106ba760 Prepare for next release
Signed-off by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 17:54:42 +02:00
Steffen Eiden
f270ac99f0 New release s390-tools-2.33.0
Signed-off by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 17:53:57 +02:00
Marc Hartmayer
f83af8e076 rust: Generate shell (e.g. bash) completion scripts via build.rs for all tools
It might be handy to have shell completion support for the Rust PV
tools.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:25 +02:00
Marc Hartmayer
4d2c92f6d5 rust/pvapconfig: Fix expected out doc comment
error[E0753]: expected outer doc comment

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:21 +02:00
Steffen Eiden
503e241db1 rust: Improve code formatting
Do some formatting that are in experimental stage but improve the code
readability.

Use rustfmt with a nightly toolchain and enable:

format_code_in_doc_comments = true
reorder_impl_items = true
comment_width = 100
wrap_comments = true
normalize_comments = true

(see .rustfmt.toml)

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:17 +02:00
Steffen Eiden
dea5f80215 libpv: Remove unused code
Remove all the code just pvattest-C used from libpv.
z(get)dump is the only user as of now.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:14 +02:00
Steffen Eiden
c261db259b zdump: Use constant for CCK size
This will reduce code dependency to otherwise unused code in libpv.
This code will be removed with the next patch.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:10 +02:00
Steffen Eiden
c382e7ef44 Remove pvattest-C and switch to pvattest-Rust implementation
Removes the C implementation of pvattest.
Use the Rust implementation instead.

Closes: https://github.com/ibm-s390-linux/s390-tools/issues/164
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:06 +02:00
Steffen Eiden
16610a211f rust: pvattest-Rust
Add a CLI compatible Rust implementation of pvattest-C.
 - All (non-experimental) options are supported and work exactly as in
   the C implementation. For some options/parameters new variants are
   available.
 - `perform` now also accepts positional arguments, while keep accepting
   -i and -o  that was mandatory in the C implementation.
 - `version` may also be a command instead of an option now.
 - -V is deprecated
 - -v increases verbosity instead of showing the version
 - all experimental options are dropped

Acked-by: Qi Feng Huo <huoqif@cn.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:54:01 +02:00
Steffen Eiden
4d57ff046d rust: Prepare Cargo.toml for crates.io
Renames pv crate to s390_pv and pv_core to s390_pv_core. pv was already
taken on crates.io.

Bump the versions of all crates to 0.10.0. From now on we follow Semver
compatibility rules when it comes to updates. patch-level updates will
not introduce any backwards incompatible changes. For now all crates in
this directory will have the same version number. A version update may,
therefore, not add any new things.

Library users in this repository still use the non prefixed names and
rename the crate in the Cargo.toml. Doc-tests have to use the new name
however.

Add some Cargo metadata to the Cargo.toml.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:57 +02:00
Marc Hartmayer
4a76efe6d5 rust: Use AsRef<Path> and PathBuf in libraries
Use `AsRef<Path>` instead of `&Path`, &str, .... to be more versatile
and accept more input types. In addition, use `PathBuf` and `Path` for
paths instead of `String` and `str`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:47 +02:00
Steffen Eiden
87d43c7a32 rust/pv_*: Add more deny lints to pv and pv_core
Denies compiling if one of the following lints find something in pv or
pv_core:
    missing_docs,
    missing_debug_implementations,
    trivial_numeric_casts,
    unstable_features,
    unused_import_braces,
    unused_qualifications

Those lint force developers to avoid unnecessary code and providing
debuggability & documentation for each public symbol.

Fix the compile time error introduced with those lints.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:43 +02:00
Steffen Eiden
f383278a5a rust/pv: Fix styling issues
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:39 +02:00
Steffen Eiden
a9d4b1e1b9 rust/pv: Inline openssl_extensions sub-crate
crates.io does not like sub-crates in a crate. Unpack the
openssl-extensions sub-crate into a (private) module.

While at it, fix some styling issues.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:35 +02:00
Steffen Eiden
61c5d7d431 rust/pv: Attestation generation and verification support
Add functionality to generate Attestation Measurement requests.
Add functionality to verify Attestation Measurement responses.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:32 +02:00
Steffen Eiden
b7765993e2 rust/pv_core: Attestation support
Add functionality for:

* sending attestation requests to the uvdevice and retrieve the
  response
* create/read the attestation exchange format file format

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:27 +02:00
Steffen Eiden
e152b554f5 rust/pv: Add decrypt and HMAC function
Add a function to decrypt a block with aes_gcm.
Add functionality to perform HMAC operations.

Acked-by: Qi Feng Huo <huoqif@cn.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:21 +02:00
Steffen Eiden
c46a066827 rust/utils: Add Hexslice
Add a thin wrapper around [u8] to be able to represent an u8-slice as a
hex-string for Display and Serialize.

Acked-by: Qi Feng Huo <huoqif@cn.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:12 +02:00
Steffen Eiden
cf003379ac rust/pv_core: Remove !#[allow(unused)]
Remove !#[allow(unused)] in pv_core and fix all unused warnings from the
Rust compiler.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:07 +02:00
Steffen Eiden
7b94783cb7 rust/pv: More documentation
Improve the API documentation of the pv crate.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:53:03 +02:00
Steffen Eiden
38600bb4e2 rust/pv: Add conversion implementations
Add AsRef<[u8]> and TryFrom<Vec<u8>> implementations so that the tag
data can be converted into base64.
See: https://docs.rs/serde_with/latest/serde_with/base64/struct.Base64.html

While at it, fix some typos and simplify the tag extraction.

Suggested-by:  Qi Feng Huo <huoqif@cn.ibm.com>
Acked-by: Qi Feng Huo <huoqif@cn.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:56 +02:00
Marc Hartmayer
16875f7c6d rust/pv: Fix clippy finding
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:51 +02:00
Steffen Eiden
381fecfc44 rust: Refactoring and reduce API surface
Prepare pv & pv_core crates to be released on crates.io:
* Remove any unused API to stay flexible
* Remove utils dependency
* Move cli, tmpfile and version utilities to local utils crate
* Use the new utilities in the pv tools
* Rename Secret into Confidential to avoid confusion of Secret (now
  Confidential) and AddSecret requests.
* Move the uvsecret module out of the request module and change the name
  to secret.
* Cleanup dependencies
* Precise and correct minimal dependency versions
* Inline `Aes256Key::from_digest`

The cleanup ensures that the code also compiles with the dependencies
resolved to their minimal versions using:

$ cargo +nightly -Z minimal-versions update
$ cargo build

For more information refer to this blog post:
https://users.rust-lang.org/t/psa-please-specify-precise-dependency-versions-in-cargo-toml/71277/8

Signed-off-by: Marc Hartmayer <mhartmay@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:42 +02:00
Marc Hartmayer
5648b924d6 rust/pvsecret: verify.rs: fix clippy finding
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:38 +02:00
Steffen Eiden
636d2d571b rust/pvsecret: Update man files and help
Add subcommands in the man description. Add description for the help option.
Fix some minor wording issues.
Add the curve type  in the --user-data option of create.

Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:35 +02:00
Marc Hartmayer
d016ec129d pre-commit-config: exclude .key and .bin files
Modifying binaries or key material using pre-commit makes no sense.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:31 +02:00
Peter Oberparleiter
cb77faeae7 chpstat: add tool to display channel-path statistics
Add a new tool named chpstat that can be used to view channel-path
statistics such as utilization and I/O throughput, and to query and
control the status of the channel-path statistics function.

Note: Channel-path statistics are only available on systems running in
      an LPAR or DPM partition.

When run without further options, data for all channel-paths is
displayed repeatedly with a 5 second delay in table format.

Example output:

      CHANNEL-PATH       UTILIZATION(%)   READ(B/s)  WRITE(B/s)
  ID TYP CMG SHR SPEED  PART TOTAL  BUS  PART TOTAL  PART TOTAL
  1d  25   2   1     -  7.16  7.50 7.50  129M  129M  0.00  161K
  21  1b   2   1   32G  0.00  0.00 0.00  0.00  0.00  0.00  0.00
  34  1b   2   1   32G  0.00  0.00 0.00  0.00  0.00  0.00  0.00
  61  25   2   1     -  0.00  0.01 0.00  0.00 2.00K  0.00  307K
  63  25   2   1     -  0.00  0.01 0.00  0.00  0.00  0.00  381K
  bd  11   2   1   10G     -     -    - 529.8 532.1 616.3 616.3

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:27 +02:00
Peter Oberparleiter
38ea8fc3ee libutil: add output format helpers
Add helper functions for converting structured key-value data into
different formats such as JSON, text pairs, and CSV.

Using these functions the resulting output format can be dynamically
configured at run-time without the need to duplicate output-generating
code for each format type. Also format-specific requirements such as
quoting, indentation, and comma-placement are automatically taken care
of.

Basic API calling sequence:

 util_fmt_init()      => Select output format
 util_fmt_obj_start() => Start a new object or list
 util_fmt_pair()      => Emit a key-value pair
 util_fmt_obj_end()   => End the most recent object or list
 util_fmt_exit()      => Cleanup

Notes:
 - Supported data elements are objects, lists and key-value pairs
   (mappings)
 - Scalars are only supported as part of a mapping

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:23 +02:00
Peter Oberparleiter
d8e5bc07aa libutil: add function to concatenate a format string in place
Add function util_concatf() that appends the result of a format string
expansion to the end of an existing string while taking care of the
required memory allocations.

Usage example:

  char *str = NULL;

  util_concatf(&str, "list:");
  for (int i = 1; i <= 3; i++)
    util_concatf(&str, "%spart%d", (i > 1 ? "," : ""), i);
  printf("%s\n", str); /* list:part1,part2,part3 */

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:20 +02:00
Peter Oberparleiter
3b26f79143 libutil: add dynamic array helpers
Add helper macros to easily create, enlarge and append new elements to
dynamic arrays of arbitrary types.

Note: The use of dynamic arrays over lists may be preferable in some
cases to reduce complexity, and they may be required in cases where
elements need to be addressed directly by index.

Usage example:

  struct {
    int a;
    int b;
  } *array = NULL, element = { 1, 2 };
  unsigned int num = 0;

  util_add_array(&array, &num, element);
  printf("array[0].a=%d\n", array[0].a); /* array[0].a=1 */
  printf("array[0].b=%d\n", array[0].b); /* array[0].b=2 */

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:16 +02:00
Peter Oberparleiter
c366429e57 libutil: fix hexdump indentation
The current implementation of util_hexdump_grp() enforces a minimum
indentation of 1 space which may not be suitable for all users.

Fix this by allowing a true zero indentation level.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:13 +02:00
Peter Oberparleiter
8ed478ce46 libutil: enable record output without separator
The separator line emitted by util_rec functions may not be suitable for
all users. Fix this by making the hdr_sep parameter optional.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:09 +02:00
Peter Oberparleiter
a97a8f1cba libutil: fix util_file_write_* return code
By default, files opened via fopen are block-buffered. As a result,
I/O errors that occur during file write operations via util_file_write_*
are silently ignored because fputs() only buffers data while actual I/O
occurs during the flush operation that is part of the final fclose()
library call.

Fix this by indicating errors that occur during fclose() via the
util_file_write_* function return code.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:07 +02:00
Eduard Shishkin
fb0b6263d1 zipl/src: Fix problems when target parameters are specified by user
Steps to reproduce: Prepare some target disk for IPL, specifying
its parameters via zipl "target options", and an image IMAGE_NAME
located on another disk. Don't specify "-a" option.

Actual result: Installation succeeded (resulting in unbootable setup)
Expected result: "Error: Could not add image file 'IMAGE_NAME': File
is not on target device"

The problem is in incorrect evaluation of device number(dev_t) where
the image is located by the function add_component_file_range() in
case when target parameters are specified by user.

Fixup: Retrieve info of the underlying disk without any user hints,
passing zeroed structure job_target_data

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:52:03 +02:00
Eduard Shishkin
76aaf3d4a8 zipl/src: Fix problems when image is not on target SCSI
This patch fixes a bug in disk_get_info()
Steps to reproduce: Prepare a SCSI disk for IPL, specifying an image
("-i IMAGE_NAME") located on DASD and a target directory ("-t /mnt")
located on SCSI (dm). Don't specify "-a" option.

Actual result: Installation succeeded (resulting in unbootable setup!)
Expected result: "Error: Could not add image file 'IMAGE_NAME':
File is not on target device".

The problem is in incorrect evaluation of device number (dev_t) of
the device, where the image file is located, by the function
add_component_file_range(). To evaluate it, disk_get_info() is called
with the structure job_target_data (passed as the second argument)
previously completed by disk_get_info() called earlier to evaluate
parameters of the specified target device (SCSI dm) by the function
prepare_build_program_table_file(). Since the targetbase is already
set in the passed job_target_data (by the first call), in the second
call the source type is evaluated as "source_user", so the number of
the device where the image is located is calculated by the base SCSI
disk, which is incorrect.

Fixup: Rework disk_get_info(): introduce a dedicated function to
evaluate source type not depending on the job_target_data content.
Implement the core procedure as a switch by the evaluated source
type.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:59 +02:00
Eduard Shishkin
08232d29b9 zipl/src: Drop "bootmap_dir" field of struct install_info
Use "bootmap_dir" field of struct job_target_data instead,
thus avoid allocation/releasing additional resources.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:56 +02:00
Eduard Shishkin
cfaccc5fad zipl/src: Fix problems when image is not on target DASD
This patch fixes a bug in disk_get_info()
Steps to reproduce: Prepare a DASD disk for IPL, specifying an
image ("-i IMAGE_NAME") located on SCSI (dm) and a target directory
("-t /mnt") located on DASD. Don't specify "-a" option.

Actual result: "Run /lib/s390-tools//zipl_helper.device-mapper /mnt
Error: Could not retrieve device-mapper information for device
'dasda1'"
Expected result: "Run /lib/s390-tools//zipl_helper.device-mapper 253:4
Error: Could not add image file 'IMAGE_NAME': File is not on target
device"

The problem is in incorrect calculation by disk_get_info()
parameters for @device associated with the image file. Specifically,
@target->bootmap_dir is passed to the script, which is wrong.

Fixup: Get rid of bogus branching in disk_get_info() in case when
target parameters are evaluated in "source_script" mode. Always pass
major and minor of the @device (whose parameters to be calculated)
to the helper script.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:52 +02:00
Jan Höppner
7da5a6b9ed tunedasd: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:48 +02:00
Jan Höppner
7ed87bed8c tunedasd: Fix trailing whitespace
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:45 +02:00
Jan Höppner
46ec94d0ce zdsfs: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:42 +02:00
Jan Höppner
6bc0b023aa dasdstat: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:38 +02:00
Jan Höppner
13d673e0f7 dasdstat: Fix man page title
The man page title was incorrectly set to "LSDASD". Set the correct name
"DASDSTAT".

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:35 +02:00
Jan Höppner
c40c159173 lsdasd: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:32 +02:00
Jan Höppner
202ded5d11 tape390: Fix missing hyphen escapes in the man pages
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:28 +02:00
Jan Höppner
e3a698c382 tape390: Fix trailing whitespace in man pages
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:22 +02:00
Jan Höppner
3a60b4caa8 fdasd: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:19 +02:00
Jan Höppner
f57858b3a8 dasdview: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped. Fix whitespace damage
along the way.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:15 +02:00
Jan Höppner
9e430b9010 dasdinfo: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:10 +02:00
Jan Höppner
ad2a42ce9e dasdfmt: Fix missing hyphen escapes in the man page
Hyphens are converted by groff to a different unicode character leading
to failing command execution of copy-pasted options or examples.

Ensure that all hyphens are properly escaped.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:05 +02:00
Nikita Dubrovskii
1c32635b3a chreipl: Impove disk type detection when running under QEMU
Under QEMU user can attach disk with smth like:
```
  -device virtio-scsi-ccw,... -device scsi-hd,...
```
So virtio block device appears as '/dev/sda' instead of '/dev/vda'.
chreipl assumes all '/dev/sd*' disks as FCP disks, which is not a
case in such setup.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/154
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
Acked-by: Marc Hartmayer mhartmay@linux.ibm.com
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:51:00 +02:00
Nikita Dubrovskii
558594fddf ipl_tools/ccw: Introduce device_sysfs_path()
Add helper function to get device's real path under SYSFS_ROOT devices
hierarchy.

Github-ID: https://github.com/ibm-s390-linux/s390-tools/pull/154
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
[hoeppner@linux.ibm.com: Adapt commit message]
Acked-by: Marc Hartmayer mhartmay@linux.ibm.com
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:42 +02:00
Harald Freudenberger
c8879322b0 pvapconfig: Escape hyphens in man page correctly
Insert backslash(es) to escape the hyphens used
in the pvapconfig man page correctly.

Suggested-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:27 +02:00
Harald Freudenberger
d716c553c4 chzcrypt: Escape hyphens in man page correctly
Insert backslash(es) to escape the hyphens used
in the chzcrypt man page correctly.

Suggested-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:21 +02:00
Harald Freudenberger
ab35922161 lszcrypt: Escape hyphens in man page correctly
Insert backslash(es) to escape the hyphens used
in the lszcrypt man page correctly.

Suggested-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:18 +02:00
Matthew Rosato
474c6adf8f libap: use custom wait time for file locks
If many invocations of mdevctl occur simultaneously (as can happen with
libvirt) then waiting for 5-60 seconds per lock retry is simply too long.
Anticipating this possibility, retry more frequently but also attempt
significantly more retries than before.

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Marc Hartmayer <marc@linux.ibm.com>
Tested-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:15 +02:00
Matthew Rosato
f5f806af06 libutil/util_lockfile: allow for custom lock wait/retry time
The default values for repeated attempts at acquiring a file lock created
by util_lockfile are on the order of seconds.  Let's leave this the
default, but allow for a caller to specify smaller values by adding
cw (custom_wait) functions and by switching from using sleep to usleep.

Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:12 +02:00
Ingo Franzki
0a01719477 zcryptstats: Fix missing hyphen escapes in man pages
Ensure that all hyphens in command options and examples are escaped properly.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:08 +02:00
Ingo Franzki
07cd9143da zkey: Fix missing hyphen escapes in man pages
Ensure that all hyphens in command options and examples are escaped properly.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:04 +02:00
Mikhail Zaslonko
d064cb522f include/boot: Sync os_info.h with kernel version.
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:50:00 +02:00
Alexander Egorenkov
802c7db50e zfcpdump: fix hsa release for V!=R kernel
Since V!=R kernel introduction, HSA memory can be
contained in/spread over more than one ELF LOAD segment of
/proc/vmcore simultaneously. Therefore, the old HSA release logic is no
longer valid because it assumes that HSA memory is fully contained in
exactly one ELF LOAD segment of /proc/vmcore. This resulted in zfcpdump
releasing HSA memory too soon and by that making parts of /proc/vmcore
which cover HSA memory unreadable by user space. To correct this
problem on V!=R kernel, we need first to find all ELF LOAD segments
containing HSA memory, write those /proc/vmcore parts first and only then
release HSA memory. The new HSA release logic must be able to handle
both V!=R and V==R kernels to be backwards compatible.

====================
Tests of V!=R kernel
====================

Output of test run (KASLR on)
=============================

Writing dump:

TRACE: Read: /sys/kernel/debug/zcore/hsa:
TRACE: '2ffff000'

TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000001cb0000 p_paddr=0x00000002f1e30000 p_vaddr=0x000002c609044000
TRACE: ELF LOAD segment: p_offset=0x0000000001cb9000 p_filesz=0x0000000040000000 p_paddr=0x0000000000000000 p_vaddr=0x000001bd00000000
TRACE: ELF LOAD segment: p_offset=0x0000000041cb9000 p_filesz=0x0000000300000000 p_paddr=0x0000000100000000 p_vaddr=0x000001be00000000

TRACE: Write copy table entry 0: off=0x0000000001cb9000 size=0x000000002ffff000 hsa=1
TRACE: Write copy table entry 1: off=0x0000000000001000 size=0x0000000001cb8000 hsa=0
TRACE: Release HSA memory
TRACE: Write copy table entry 2: off=0x0000000031cb8000 size=0x0000000310001000 hsa=0
TRACE: Write copy table entry 3: off=0x0000000000000000 size=0x0000000000001000 hsa=0

Dump successful

Output of test run (KASLR off)
==============================

Writing dump:

TRACE: Read: /sys/kernel/debug/zcore/hsa:
TRACE: '2ffff000'

TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000001cb0000 p_paddr=0x0000000000c21000 p_vaddr=0x000003ffe0000000
TRACE: ELF LOAD segment: p_offset=0x0000000001cb9000 p_filesz=0x0000000040000000 p_paddr=0x0000000000000000 p_vaddr=0x000002f200000000
TRACE: ELF LOAD segment: p_offset=0x0000000041cb9000 p_filesz=0x0000000300000000 p_paddr=0x0000000100000000 p_vaddr=0x000002f300000000

TRACE: Write copy table entry 0: off=0x0000000000009000 size=0x0000000001cb0000 hsa=1
TRACE: Write copy table entry 1: off=0x0000000001cb9000 size=0x000000002ffff000 hsa=1
TRACE: Write copy table entry 2: off=0x0000000000001000 size=0x0000000000008000 hsa=0
TRACE: Release HSA memory
TRACE: Write copy table entry 3: off=0x0000000031cb8000 size=0x0000000310001000 hsa=0
TRACE: Write copy table entry 4: off=0x0000000000000000 size=0x0000000000001000 hsa=0

Dump successful

====================
Tests of V==R kernel
====================

Output of test run (KASLR on)
=============================

Writing dump:

TRACE: Read: /sys/kernel/debug/zcore/hsa:
TRACE: '2ffff000'

TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000000000000 p_paddr=0x0000000000000000 p_vaddr=0x0000000000000000
TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000040000000 p_paddr=0x0000000000000000 p_vaddr=0x0000000000000000
TRACE: ELF LOAD segment: p_offset=0x0000000040009000 p_filesz=0x0000000300000000 p_paddr=0x0000000100000000 p_vaddr=0x0000000100000000

TRACE: Write copy table entry 0: off=0x0000000000009000 size=0x000000002ffff000 hsa=1
TRACE: Write copy table entry 1: off=0x0000000000001000 size=0x0000000000008000 hsa=0
TRACE: Release HSA memory
TRACE: Write copy table entry 2: off=0x0000000030008000 size=0x0000000310001000 hsa=0
TRACE: Write copy table entry 3: off=0x0000000000000000 size=0x0000000000001000 hsa=0

Dump successful

Output of test run (KASLR off)
==============================

Writing dump:

TRACE: Read: /sys/kernel/debug/zcore/hsa:
TRACE: '2ffff000'

TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000000000000 p_paddr=0x0000000000000000 p_vaddr=0x0000000000000000
TRACE: ELF LOAD segment: p_offset=0x0000000000009000 p_filesz=0x0000000040000000 p_paddr=0x0000000000000000 p_vaddr=0x0000000000000000
TRACE: ELF LOAD segment: p_offset=0x0000000040009000 p_filesz=0x0000000300000000 p_paddr=0x0000000100000000 p_vaddr=0x0000000100000000

TRACE: Write copy table entry 0: off=0x0000000000009000 size=0x000000002ffff000 hsa=1
TRACE: Write copy table entry 1: off=0x0000000000001000 size=0x0000000000008000 hsa=0
TRACE: Release HSA memory
TRACE: Write copy table entry 2: off=0x0000000030008000 size=0x0000000310001000 hsa=0
TRACE: Write copy table entry 3: off=0x0000000000000000 size=0x0000000000001000 hsa=0

Dump successful

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:49:54 +02:00
Marc Hartmayer
0f87acc2b3 common.mak: Improve overall Makefile performance
Improve overall Makefile performance by dramatically reducing the number
of fork and exec system calls through the use of simply expanded
variables [1]. Before this change, a simple `make -C libutil` invocation
used over 4000 execs, after this change it was reduced to just over 300
execs.

[1] https://www.gnu.org/software/make/manual/html_node/Setting.html

Reported-by: Ingo Franzki <ifranzki@linux.ibm.com>
Tested-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-05-27 16:49:05 +02:00
Eduard Shishkin
998b61e5f3 dasdfmt: Change mode default
When formatting an ESE (thin-provisioned) ECKD DASD, dasdfmt(8)
defaults to the quick-format mode instead of full-format for normal
DASDs. This results in a significant performance impact during first
sequential write to each track, which may be unexpected for users.

To address this, change the default for dasdfmt to always use
full-format mode. Customers that require thin provisioning(*) still
override the default by specifying quick format explicitly using the
"-M" option.

Get rid of the related fallbacks; In case of unsuccessful space
release always fail. The customers that still require quick format can
proceed by specifying "--no-discard" option.

(*) Thin provisioning: while providing a large amount of logical
    space, zero amount of actual space is provisioned and then
    allocated on an on-demand basis.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Joern Siglen
c47071815b dbginfo.sh: use POSIX uname options
uname -i is not defined POSIX and will fail on some linux distributions

Reviewed-by: Michael Storzer <mstorzer@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Mikhail Zaslonko
0ed6c1ccde zfcpdump: Search for zero paddr vmcore load to identify HSA
Check for vmcore LOAD segment with zero paddr (instead of zero vaddr) to
identify HSA since physical and virtual addresses can be uncoupled on s390.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Vineeth Vijayan
d888a27f07 zconf/chp: add reference to zos document
The 'lschp' command's output contains a 'type' identifier column. For
information about each value of this identifier, provide the
reference to the z/OS public documentation in the manpage.

Suggested-by: Mike Storzer <MSTORZER@de.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
7c2ae3d2e8 rust/pvsecret: Streamline arch dependend code
Get rid of all arch barriers in main.rs. cmd.rs handles the arch
barriers for the individual commands. Simplifies main.rs & cmd.rs and
makes it easier to read and understand the code.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
c88a8b6130 rust/pvapconfig: Fix Cargo clippy findings
Fix findings from `cargo clippy --all-targets`. `warning: calls to
`push` immediately after creation` The findings were in test code only.

Also, replace a while loop with a function from Vec.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
32a0434bc3 rust/pv_core: Always report rc and rrc for an UV error
The (non-archiected) rrc helps to debug issues. Therefore report them
also in release builds.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
a2e556858a rust/pv_core: Remove unnecessary mirrored constants
They add no value and code outside the crate does not need those constants.
Reduces unnecessary constant duplication. Introduce an error for to
large Add-Secret requests and check for this to render those contsnts
fully unnecessary for the API.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
9eab43994b rust/pv: Remove internal BinGuestSecret struct
The BinGuestSecret type provides no benefits. The public GuestSecret
struct can handle everything. Therefore, move the two functions from bin
to the non-bin variant. While at it, use a struct to define the binary
structure instead of copy numbers to some positions in a Vec. This
simplifies the addition of further secret types.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
c53dfa9754 rust/pv: Use a SecretId struct instead of an array
This streamlines and unifies the use and (de)serialization of structs
using a secret id. As a bonus, the hidden `for_pv` module is not longer
needed.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
81a1e13f3b rust/pv: Provide default for UvCmd::cmd
Provides a default for the cmd function for an UvCmd. This is enabled by
requiring an associated constant for the IOCTL nr of the command.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
8f89234f1a rust/pv: Remove dangling file
The content of `pv/src/uvsecret/uvc.rs` was moved with
9b51b8b882 ("rust/pv: Refactor pv crate") to pv_core.
The content was unused, but the file was not deleted.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
d757dbfbff rust/pv: Introduce AesGcmResult type
Fix clippy waring `warning: very complex type used.` by introducing a
new struct containing the tuple, that was returned before.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
0d9a6e45fb rust/pv_core: Refractor secret list to own file
This makes the secret.rs file more readable.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
4d4666cff7 rust/README.md: Add pvapconfig to the tools section
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Steffen Eiden
46092add29 rust/pv_core: Fix lazy-static dev-dependency
During the remove of mockito, lazy_static dependency was accidentally
removed as well.
Fix this by adding lazy-static as dev dependency again.

Fixes: aba8900074 ("rust/pv_core: Remove mockito dependency")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 15:07:19 +02:00
Finn Callies
1655c39ded cpacfstats: add counter numbers to output
This adds the counter numbers to the corresponding counter names to the
cpacfstats output. This aims to ease using this tool with other related
tools which may use other names for the counters.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 14:37:52 +02:00
Vineeth Vijayan
a95dc09c6e zdev: add common header for chzdev generated tempfile too
All files created by chzdev feature a common header; however, this
header is absent in temporary files. It is necessary to incorporate
the consistent "Generated by chzdev" header into temporary files
generated by chzdev as well, so as to properly identify these files
via option --is-owner.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 14:37:52 +02:00
Vineeth Vijayan
f1f80a8a20 zdev: implement option to identify files created by zdev
Enhance the 'chzdev' tool by introducing a new option to discern
files created by 'zdev-tools.' The command usage is as follows:

$ chzdev --is-owner <file-name>

When executed, the command will return an exit code of 0 for all
files generated by zdev-tools. In the case of an unknown file, the
tool will return the exit code 'EXIT_UNKNOWN_FILE i.e 33.'

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 14:37:52 +02:00
Vineeth Vijayan
4c2bfb1d47 zdev: rename site.h to zdev.h
Add zdev-specific definitions into a lightweight header file. Rather
than creating a new one, transform the existing "site.h" into "zdev.h"
to house all generic zdev-specific definitions that needs to be shared
between chzdev, lszdev and zdev_id going forward.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 14:37:51 +02:00
Finn Callies
c0fc21efb3 cpacfstats: dynamically load PAI and CPUMF counter
Up until now cpacfstats assumes that on the running hardware either all
PAI and CPUMF are available or non at all.  Which counters are supported
may be hardware dependent and can vary in the future. With
this commit cpacfstats dynamically loads the counters from sysfs entries
in (/sys/devices/pai_crypto/events/) and (/sys/devices/cpum_cf/events/)
respectively.

Additionally cpacfstats has a new way of determining which PAI counters
are meant for kernel usage.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-04-26 14:37:51 +02:00
Steffen Eiden
93d3c44a1a Prepare for next release
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Steffen Eiden
9eea78b3ad New release s390-tools-2.32.0
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Steffen Eiden
0a3a556879 rust/Cargo.lock: Update curl-sys crate
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Steffen Eiden
aba8900074 rust/pv_core: Remove mockito dependency
With f6c6f0cc71 ("rust/pv/test: Code + Certificate refactoring")
no code uses mockito anymore, but it's dependency was not removed.

Remove the mockito dependency from the rust workspace.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-03 16:18:09 +02:00
Dan Horák
f5744b95db genprotimg: Fix build with OpenSSL 1.1
OpenSSL 1.1 seems to use a non-const parameter to X509_name_dup(), but
x509_armonk_locality_fixup() is passing a const there. The compile then
fails on "discards 'const' qualifier", when -Werror is used. Thus
resolve with a type-cast like in c2b_name().

Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/167
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Dan Horák
13d721afd3 libpv: Fix build with OpenSSL 1.1
OpenSSL 1.1 seems to use a non-const parameter to X509_name_dup(), but
x509_armonk_locality_fixup() is passing a const there. The compile then
fails on "discards 'const' qualifier", when -Werror is used. Thus
resolve with a type-cast like in pv_c2b_name().

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/167
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Eduard Shishkin
90a2e6d70e zipl/src: Fix leak of files
Fix leak of temporary files: if prepare_build_program_table_file()
is called in no dry-run mode and there was an error then the file
@filename will not be deleted in free_bootloader()).

Fix leak of renamed files as well as corruption of previously
created bootmap files with the same name in case of unsuccessful
IPL installation.

Add a special flag to keep a track of file's "temporary" state;
Base the cleanup decision on this flag instead of checking dry-run;
Release resources captured by prepare_bootloader() in the error path;
Move the final rename to be called only after successful installation.

                    Original logic:

prepare_bootloader_ipl():
prepare_bootloader_ngdump():

  always create temporary @filename
  if (!dry-run) rename @filename;
  install;
  cleanup: if (dry_run) drop @filename (*** LEAK ***)

prepare_bootloader_device():

  if (dry_run) create temporary @filename
  install, don't rename;
  cleanup: if (dry_run) drop @filename

                    New logic:

prepare_bootloader_ipl():
prepare_bootloader_ngdump():

  always create temporary @filename and set @tmp_filename_created;
  install;
  if (!dry_run) rename @filename and clear @tmp_filename_created;
  cleanup: if (@tmp_filename_created is set), drop @filename

prepare_bootloader_device():

  if (dry_run) create @filename and set @tmp_filename_created;
  install, don't rename;
  cleanup: if (@tmp_filename_created is set) drop @filename.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/165
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Marc Hartmayer
bc9f8a8100 genprotimg: Fix out-of-disk space handling
Convert the assertion to a GError since an out-of-disk-space situation
is a valid situation that should be handled.

ERROR:utils/crypto.c:1843:__encrypt_decrypt_bio: assertion failed: (num_bytes_written == out_len)
Bail out! ERROR:utils/crypto.c:1843:__encrypt_decrypt_bio: assertion failed: (num_bytes_written == out_len)

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-04-02 17:37:53 +02:00
Steffen Eiden
2b5e7b0491 pvattest: Fix root-ca parsing
The parser setup falsely set the argument type as filename array, but
code expected a single filename. Fixed by setting up the parser
correctly to expect a single file name.

Fixes: 3ab06d77fb ("pvattest: Create, perform, and verify attestation measurements")
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Steffen Eiden
d7c95265cd libpv: Support Armonk in IBM signing key subject
New IBM signing keys will have Armonk as locality in the subject.
Ensure that CRLs with Poughkeepsie as issuer locality are still
discovered if they are signed with the signing keys private key.
Also, drop the check for issuer/subject comparison and only rely on
validity period and cryptographic signatures.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
8751cfc409 genprotimg/samples/check_hostkeydoc: code formatting
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
01f96d30f6 genprotimg/samples/check_hostkeydoc: fix ShellCheck findings
Fix ShellCheck findings and two typos. White spaces in filenames are now
supported properly.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
fffbd93f12 genprotimg/samples/check_hostkeydoc: improve argument parsing
+ use `getopts` POSIX builtin instead of external program
+ improve error reporting
+ support white spaces in the script name

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
ddcfbdc8d2 genprotimg/samples/check_hostkeydoc: support Armonk in IBM signing key subject
Newer IBM signing keys use `Armonk` in their subject therefore add
support for it.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
173fd7cdca genprotimg/samples/check_hostkeydoc: set LC_ALL=C for the sort command
Set `LC_ALL=C` for the `sort` command to get a stable sort order. See
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html for
details on the effect of LC_* on `sort`. Adapt the default issuer
accordingly.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
d14e7593cc genprotimg: support Armonk in IBM signing key subject
New IBM signing certificates will have 'Armonk' as locality in the
subject. Make sure that certificate revocations lists (CRL) with
'Poughkeepsie' as issuer locality are still considered as valid as long
as they are signed with the IBM signing keys private key. In addition,
drop the check for 'issuer(HKD) == subject(HKSK)' as it doesn't improve
security. While at it, remove now unused functions and fix a memory leak
of @akid in `check_crl_issuer`.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Steffen Eiden
1a3d0b74f7 rust/pv: Support Armonk in IBM signing key subject
New IBM signing keys will have Armonk as locality in the subject.
Ensure that CRLs with Poughkeepsie as issuer locality are still
discovered if they are signed with the signing keys private key.
Also, drop the check for issuer/subject comparison and only rely on
validity period and cryptographic signatures.

Reviewed-by: Christoph Schlameuss <schlameuss@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Marc Hartmayer
f6c6f0cc71 rust/pv/test: Code + Certificate refactoring
* Get rid of Mockito
* create certs with AKID
* simplify things in the `create_certs.py` script

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Thomas Richter
966e67a252 cpumf/lscpumf: add support for machine type 3932
Add support for machine type 3932 and list the
CPU Measurement facility counter sets.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Joern Siglen
1c128c0d11 dbginfo.sh: dash compatible copy sequence
rewrite the copy of dbginfo.sh for dash compatibility

Reviewed-by: Mike Storzer <MSTORZER@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
VasiliyS
a3199d58db rust/pv_core: Fix UvDeviceInfo::get() method.
`ATTESTATION_NR` flag was not set properly in case the device
didn't support `Info` IOCTL call.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/163
Signed-off-by: Vasiliy Suvorov <vsuvorov@gmail.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-22 12:07:29 +01:00
Vineeth Vijayan
659483031e zdev: Rearrange the options alphabetically in man page
re-arrange options in zdev manpages in the alphabetical order.

Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:43 +01:00
Ingo Franzki
7dc2513205 zkey: Detect FIPS mode and generate PBKDF for luksFormat according to it
For LUKS2 volumes, zkey generates 'cryptsetup luksFormat' commands with
options '--pbkdf argon2i --pbkdf-memory 32 --pbkdf-force-iterations 4'
for low memory and time requirements. Using the default Argon2i options
might cause out-of-memory errors when multiple encrypted volumes are
unlocked automatically at boot through /etc/crypttab.

When the system runs in FIPS mode, which is indicated by file
/proc/sys/crypto/fips_enabled containing '1', the Argon2i password based
key derivation function might be disabled by a policy, and such
'cryptsetup luksFormat' commands might fail.

Generate '--pbkdf pbkdf2' instead if the system runs in FIPS mode.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:43 +01:00
Marc Hartmayer
0748d365a6 genprotimg/**/Makefile: Fix staged installs
Fix the support for staged installs. The Makefile variable `PKGDATADIR`
uses `DESTDIR` for all Makefile target, but actually it should only be
used for the `install*` and `uninstall*` targets. [1] Fix this by using
`DESTDIR` only for `install*` targets - uninstall* targets are not
supported by s390-tools.

Before this change, if `DESTDIR` was set for staged installs,
`genprotimg` has tried to find the bootloader binaries at the temporary
installation path `$DESTDIR$(TOOLS_DATADIR)/genprotimg/` instead of
`$(TOOLS_DATADIR)/genprotimg`.

[1] https://www.gnu.org/prep/standards/html_node/DESTDIR.html

Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:38 +01:00
Marc Hartmayer
94a404ed10 pvattest: Makefile: Remove unused variable and CFLAGS
Remove unused variables and unused compiler flags.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Thomas Richter
ef1799f31f s390-tools/libutil: Add machine type 3932
Add support for machine type 3932.
Print identical product name for machine types 8561 and 8562.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
47b0960cc7 zdump: Make ngdump_get_part_path() public
Make ngdump_get_part_path() public in order for unit-tests to access it.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
2288331a6f zipl: Clear CCW-type DASD dumper upon ldipl-dump tool installation
Clear CCW-type DASD standalone dumper (if installed on the DASD) upon
successful installation of the List-Directed ECKD dump tool on the same
device. This helps to avoid 'zgetdump -d' confusion and have only one
'active' dump tool per disk.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
23e9156f43 s390_dump.h: Add DF_S390_DUMPER_MAGIC_SIZE constant
Add DF_S390_DUMPER_MAGIC_SIZE constant to s390_dump.h.
Use it instead of hardcoded length when processing dumper magics
in zgetdump code.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
8f99e7c4ea zdump: Move DUMPER_MAGIC constants to include/dump/s390_dump.h
Move DUMPER_MAGIC constants from df_s390.h to the global header
include/dump/s390_dump.h in order to reuse it in zipl code.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
f3bcd94524 zdump: Add zgetdump -d support for ECKD ldipl-dump
Make 'zgetdump -d' to identify ldipl-dump tool (ngdump) installed on DASD
volume just like it does for NVMe ngdump.

Output sample:
-------------
Dump device info:
  Dump tool.........: Next Generation (NGDump) dump tool
  Version...........: 1
  Architecture......: s390x (64 bit)

Partition info:
  Partition number..: 2

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
a2f8b19c2a dumpconf: Update the man page and etc/sysconfig/dumpconf template
Update dumpconf man page with list-directed ECKD dump information (new
attributes and configuration example for ECKD LDIPL dump).
Update etc/sysconfig/dumpconf with list-directed ECKD dump configuration
example.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Mikhail Zaslonko
588d720517 dumpconf: Process br_chr and bootprog eckd attributes
- Write the following sysfs attributes for list-directed ECKD devices
  introducing setup_eckd_device() function.
    br_chr: location of boot record
    bootprog: boot program selector
- Remove redundant parameters from setup_ccw_device() and setup_fcp_device()
  functioins.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Ingo Franzki
cd822cb770 zkey: Fix convert command to accept only keys of type CCA-AESDATA
Reject conversion of other key types with a proper error message.
Also fix a typo in another error message of the convert command.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Ingo Franzki
b27b8e3cd3 zkey: Fix typos in error message
Use a colon instead of a semicolon in the message.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:34 +01:00
Steffen Maier
7a2c5dc980 zdev/dracut: Fix file mode of non-executable shell library zdev-lib.sh
Use similar `install` mode option in Makefile as in commit
9b2fb1d4d2 ("zdev: add helper to convert from dasd_mod.dasd to zdev
config").

Fixes: 73c46a3056 ("zdev/dracut: fix kdump by only activating required devices")
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-03-15 15:11:28 +01:00
Jan Höppner
d9e3763d1c Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-02-02 17:49:44 +01:00
372 changed files with 19510 additions and 12554 deletions

3
.gitignore vendored
View File

@@ -92,6 +92,7 @@ vmcp/vmcp
vmur/vmur
zconf/chp/chchp
zconf/chp/lschp
zconf/chp/chpstat/chpstat
zconf/css/lscss
zconf/qeth/lsqeth
zconf/scm/lsscm
@@ -123,9 +124,11 @@ zipl/boot/*.exec
zipl/boot/.loaders
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zipl/src/chreipl_helper.md
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/zipl_helper.device-mapper
zipl/src/zipl_helper.md
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup
zkey/detect-libcryptsetup.dep

View File

@@ -1,5 +1,5 @@
---
exclude: \.(crt|crl)$
exclude: \.(bin|crl|crt|key)$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0

View File

@@ -5,8 +5,9 @@ newline_style = "Unix"
# when they become stable.
#
# They are kept here since they are useful to run from time to time.
#format_code_in_doc_comments = true
#reorder_impl_items = true
#comment_width = 100
#wrap_comments = true
#format_code_in_doc_comments = true
#group_imports = "StdExternalCrate"
#normalize_comments = true
#reorder_impl_items = true
#wrap_comments = true

View File

@@ -1,6 +1,93 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.35.0 (2024-10-01)__
For Linux kernel version: 6.11
Add new tools / libraries:
Changes of existing tools:
- cpacfstats: Add support for FULL XTS (MSA 10) and HMAC (MSA 11) PAI counter
- cpuplugd: Make cpuplugd compatible with hiperdispatch
- dbginfo.sh: Add network sockstat info
- pvapconfig: s390x exclusive build
- zdev: Add option to select IPL device
- zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
- zipl: Add support of mirror devices
Bug Fixes:
- (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
- netboot/mk-s390image: Fix size when argument is a symlink
- ziorep_config: Fix warning message when multipath device is not there.
- zipl: Fix problems when target parameters are specified by user
- zipl: Fix segfault when creating device-based dumps with '--dry-run'
* __v2.34.0 (2024-08-01)__
For Linux kernel version: 6.10
Changes of existing tools:
- ap_tools/ap-check: Add support for vfio-ap dynamic configuration
- dbginfo.sh: Update/Add additional DASD data collection
- dumpconf: Add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
- libutil: Make formatted meta-data configurable
- s390-tools: Replace 'which' with built-in 'command -v'
- zdump/dfi_elf: Support core dumps of vr-kernels
Bug Fixes:
- chzdev: Fix warning about failed ATTR writes by udev
- rust/pv: Try again if first CRL-URI is invalid
- rust/pvattest: Add short option for --arpk
- zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
* __v2.33.1 (2024-05-28)__
For Linux kernel version: 6.9
Bug Fixes:
- s390-tools: Fix formatting and typos in README.md
- s390-tools: Fix release string
* __v2.33.0 (2024-05-27)__
For Linux kernel version: 6.9
Add new tools / libraries:
- chpstat: New tool for displaying channel path statistics
- libutil: Add output format helpers(util_fmt: JSON, JSON-SEQ, CSV, text pairs)
Changes of existing tools / libraries:
- chzdev: Add --is-owner to identify files created by zdev
- dasdfmt: Change default mode to always use full-format (Note: affects ESE DASD)
- libap: Significantly reduce delay time between file lock retries
- pvattest: Rewrite from C to Rust
- pvattest: Support additional data & user-data
- rust/pv: Support for Attestation
Bug Fixes:
- chreipl: Improve disk type detection when running under QEMU
- dbginfo.sh: Use POSIX option with uname
- s390-tools: Fix missing hyphen escapes in the man page for many tools
- zipl/src: Fix bugs in disk_get_info() reproducible in corner cases
* __v2.32.0 (2024-04-03)__
For Linux kernel version: 6.8
Changes of existing tools:
- cpumf/lscpumf: add support for machine type 3932
- genprotimg, pvattest, and pvsecret accept IBM signing key with Armonk as
subject locality
- zdump/zipl: Support for List-Directed dump from ECKD DASD
- zkey: Detect FIPS mode and generate PBKDF for luksFormat according to it
Bug Fixes:
- dbginfo.sh: dash compatible copy sequence
- rust/pv_core: Fix UvDeviceInfo::get() method
- zipl/src: Fix leak of files if run with a broken configuration
- zkey: Fix convert command to accept only keys of type CCA-AESDATA
* __v2.31.0 (2024-02-02)__
For Linux kernel version: 6.7

View File

@@ -15,12 +15,12 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools pvattest \
rust
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust
else
BASELIB_DIRS =
LIB_DIRS = libpv
TOOL_DIRS = genprotimg pvattest rust
TOOL_DIRS = genprotimg rust
endif
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)

View File

@@ -19,6 +19,12 @@ Package contents
all s390-tools that are written in rust and require external crates.
Disable the compilation of all tools in `rust/` using HAVE_CARGO=0
See the `rust/README.md` for Details
- pvattest:
Create, perform, and verify IBM Secure Execution attestation measurements.
- pvapconfig:
Automatic configure APQNs within an SE KVM guest
- pvsecret:
Manage secrets for IBM Secure Execution guests
* dasdfmt:
Low-level format ECKD DASDs with the classical Linux disk layout or the new
@@ -38,9 +44,6 @@ Package contents
* genprotimg:
Create a protected virtualization image.
* pvattest:
Create, perform, and verify protected virtualization attestation measurements.
* udev rules:
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
- 57-osasnmpd.rules: udev rules for osasnmpd.
@@ -360,12 +363,11 @@ the different tools are provided:
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
* pvattest:
* rust/pvattest:
For building pvattest you need OpenSSL version 1.1.1 or newer
installed (openssl-devel.rpm). Also required is glib2.56 or newer
(glib2-devel.rpm) and libcurl.
installed (openssl-devel.rpm). Also required is cargo and libcurl.
Tip: you may skip the pvattest build by adding
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_GLIB2=0`.
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_CARGO=0`.
The runtime requirements are: openssl-libs (>= 1.1.1) and
glib2.56 or newer.

View File

@@ -15,6 +15,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <json-c/json.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -27,21 +28,33 @@
#include "ap-check.h"
/* The supported mdevctl callout version */
#define MDEVCTL_CAP_VERSION 2
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
{MDEVCTL_ACTION_DEFINE, "define"},
{MDEVCTL_ACTION_LIST, "list"},
{MDEVCTL_ACTION_MODIFY, "modify"},
{MDEVCTL_ACTION_START, "start"},
{MDEVCTL_ACTION_STOP, "stop"},
{MDEVCTL_ACTION_TYPES, "types"},
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"},
{MDEVCTL_ACTION_CAPABILITIES, "capabilities"}
/*
* Note: the following actions are known to exist but currently ignored:
* {MDEVCTL_ACTION_LIST, "list"},
* {MDEVCTL_ACTION_TYPES, "types"}
*/
};
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
{MDEVCTL_EVENT_PRE, "pre"},
{MDEVCTL_EVENT_POST, "post"},
{MDEVCTL_EVENT_GET, "get"}
{MDEVCTL_EVENT_GET, "get"},
{MDEVCTL_EVENT_LIVE, "live"}
/*
* Note: the following events are known to exist but currently ignored:
* {MDEVCTL_EVENT_NOTIFY, "notify"},
*/
};
/*
@@ -596,6 +609,94 @@ out:
return rc;
}
static int ap_check_active(struct ap_check_anchor *anc)
{
int rc, rc2;
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
return -1;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
return rc;
}
static int ap_do_dynamic_config(struct ap_check_anchor *anc)
{
char *adapters, *domains, *controls, *path, *attr;
int asize, dsize, csize, size;
int rc = 0;
FILE *f;
adapters = vfio_ap_device_get_adapter_mask(anc->dev, &asize);
domains = vfio_ap_device_get_domain_mask(anc->dev, &dsize);
controls = vfio_ap_device_get_control_mask(anc->dev, &csize);
if (!adapters || !domains || !controls) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
/*
* The 'ap_config' command takes a comma-delimited list of the 3 masks
* combined. Each mask size includes a terminating character, two of
* which will be replaced by commas and the final replaced by a
* newline, which ap_config seems to require at the end of the input.
* Add one to ensure room for a null termination.
*/
size = asize + dsize + csize + 1;
attr = util_zalloc(size);
/* Use the 3 masks to generate a 'ap_config' command */
rc = snprintf(attr, size, "%s,%s,%s\n", adapters, domains, controls);
if (rc < size - 1) {
fprintf(stderr, "Error creating ap_config command\n");
rc = -1;
goto out;
}
/* Apply the new configuration to the active device */
path = path_get_vfio_ap_attr(anc->uuid, "ap_config");
f = fopen(path, "w");
if (!f) {
fprintf(stderr, "Error opening ap_config\n");
rc = -1;
goto out;
}
rc = fputs(attr, f);
fclose(f);
if (rc == EOF)
fprintf(stderr, "Error writing to ap_config\n");
else
rc = 0;
out:
if (!adapters)
free(adapters);
if (!domains)
free(domains);
if (!controls)
free(controls);
if (!path)
free(path);
if (!attr)
free(attr);
return rc;
}
/*
* Determine if defining the specified device is a valid operation.
* mdevctl can reach us for a DEFINE under the following circumstances:
@@ -647,6 +748,50 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
return ap_check_changes(anc);
}
/*
* Determine if modifying the active device is a valid operation.
* This is similar to STARTing a device, in that the requested modifications
* cannot conflict with the active configuration. LIVE MODIFY can only be
* handled if the ap_config attribute is available in the vfio-ap driver.
*/
static int ap_check_handle_live_modify(struct ap_check_anchor *anc)
{
int rc;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
return -1;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
return -1;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
return -1;
}
if (!vfio_ap_need_dynamic_config(anc->dev)) {
fprintf(stderr, "vfio-ap module does not support ap_config for live modification");
return -1;
}
/* Check if the new configuration would cause conflicts */
rc = ap_check_active(anc);
if (rc)
return rc;
/* Attempt to perform the dynamic configuration */
rc = ap_do_dynamic_config(anc);
return rc;
}
/*
* Determine if starting the specified device is a valid operation.
* mdevctl can reach us for a START under the following circumstances:
@@ -665,7 +810,7 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
*/
static int ap_check_handle_start(struct ap_check_anchor *anc)
{
int rc = 0, rc2;
int rc = 0;
/* Can only start a device if vfio_ap is built-in or loaded */
if (!util_path_is_dir(VFIO_AP_PATH)) {
@@ -694,20 +839,7 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
goto out;
}
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
rc = -1;
goto out;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
rc = ap_check_active(anc);
/* If successful, lock must remain held until post callout */
if (rc == 0)
@@ -886,6 +1018,122 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
return 0;
}
/*
* If the target 'attr' is in the 's' array, add it to the 't' array.
*/
static void json_add_attr(json_object *t, json_object *s, const char *attr)
{
size_t vlen, alen = strlen(attr);
const char *val;
json_object *o;
int i, num;
num = json_object_array_length(s);
for (i = 0; i < num; i++) {
o = json_object_array_get_idx(s, i);
val = json_object_get_string(o);
vlen = strlen(val);
if (alen == vlen && strncasecmp(attr, val, alen) == 0) {
json_object_array_add(t, json_object_new_string(val));
return;
}
}
}
/*
* Generate a JSON-formatted list of capability information that this script
* supports and return it to the caller via stdout. An example of what the
* output should look like (without the newlines):
* {
* "supports": {
* "version": 2,
* "actions": ["define",
* "modify",
* "start",
* "stop",
* "undefine",
* "attributes",
* "capabilities"],
* "events": ["pre",
* "post",
* "get",
* "live"]
* }
* }
*/
static int ap_check_handle_get_capabilities(void)
{
json_object *root, *csup, *cver, *cact, *cev, *cap, *caps, *o;
int i, rc = 0;
root = json_object_from_fd(STDIN_FILENO);
if (!root) {
fprintf(stderr, "No capabilities provided\n");
return -1;
}
if (!json_object_object_get_ex(root, "provides", &csup)) {
fprintf(stderr, "No supported capabilities provided\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "version", &cver)) {
fprintf(stderr, "No version provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "actions", &cact)) {
fprintf(stderr, "No actions provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "events", &cev)) {
fprintf(stderr, "No events provided in capabilities\n");
rc = -1;
goto out;
}
/*
* Advertise the subset of supported capabilities from the list
* provided on stdin.
*/
cap = json_object_new_object();
caps = json_object_new_object();
json_object_object_add(cap, "supports", caps);
/*
* Currently we always advertise a fixed version, but we may need to
* revisit this if we increase MDEVCTL_CAP_VERSION in the future (e.g.
* how to handle ap-check having a greater supported version than
* what mdevctl reports)
*/
o = json_object_new_int(MDEVCTL_CAP_VERSION);
json_object_object_add(caps, "version", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++)
json_add_attr(o, cact, mdevctl_action_table[i].action);
json_object_object_add(caps, "actions", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++)
json_add_attr(o, cev, mdevctl_event_table[i].event);
json_object_object_add(caps, "events", o);
/* Return supported capabilities JSON on stdout */
printf("%s\n", json_object_to_json_string(cap));
json_object_put(cap);
out:
json_object_put(root);
return rc;
}
/*
* Determine which mdevctl action is being checked and handle accordingly.
*/
@@ -911,8 +1159,6 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_UNDEFINE:
rc = ap_check_handle_undefine(anc);
break;
case MDEVCTL_ACTION_LIST:
case MDEVCTL_ACTION_TYPES:
default:
/* Ignore some actions including unknown ones */
break;
@@ -937,6 +1183,19 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_ATTRIBUTES:
rc = ap_check_handle_get_attributes(anc);
break;
case MDEVCTL_ACTION_CAPABILITIES:
rc = ap_check_handle_get_capabilities();
break;
default:
/* Ignore some actions including unknown ones */
break;
}
break;
case MDEVCTL_EVENT_LIVE:
switch (anc->action) {
case MDEVCTL_ACTION_MODIFY:
rc = ap_check_handle_live_modify(anc);
break;
default:
/* Ignore some actions including unknown ones */
break;

View File

@@ -24,6 +24,7 @@ enum mdevctl_action_id {
MDEVCTL_ACTION_TYPES,
MDEVCTL_ACTION_UNDEFINE,
MDEVCTL_ACTION_ATTRIBUTES,
MDEVCTL_ACTION_CAPABILITIES,
/* UNKNOWN must always be the last in the list */
MDEVCTL_ACTION_UNKNOWN,
};
@@ -38,6 +39,7 @@ enum mdevctl_event_id {
MDEVCTL_EVENT_PRE = 0,
MDEVCTL_EVENT_POST,
MDEVCTL_EVENT_GET,
MDEVCTL_EVENT_LIVE,
MDEVCTL_EVENT_UNKNOWN,
};
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN

View File

@@ -951,7 +951,7 @@ static void set_record_extension(struct file *f, int *record, off_t addr,
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
f->record_scan_state != RSS_DATA_BLOCK_EXT)
DIE("%s: interal error\n", __func__);
DIE("%s: internal error\n", __func__);
BUG(*record >= f->fst->nr_records);

View File

@@ -31,11 +31,11 @@ endif
# Global definitions
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 31
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
VERSION := 2
RELEASE := 35
PATCHLEVEL := 0
DISTRELEASE := build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
export S390_TOOLS_RELEASE
reldir = $(subst $(realpath $(dir $(filter %common.mak,$(MAKEFILE_LIST))))/,,$(CURDIR))
@@ -293,8 +293,8 @@ INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
$(SOINSTALLDIR) $(USRLIBDIR)
OWNER = $(shell id -un)
GROUP = $(shell id -gn)
OWNER := $(shell id -un)
GROUP := $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR USRLIBDIR USRLIB64DIR MANDIR OWNER GROUP
# Special defines for zfcpdump

View File

@@ -21,10 +21,11 @@ ALL_CPPFLAGS += -DVERSION=$(VERSION)
all: check_dep cpacfstats cpacfstatsd
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o cpacfstats_common.o \
$(rootdir)/libutil/libutil.a
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
cpacfstats: cpacfstats.o stats_sock.o
cpacfstats: cpacfstats.o stats_sock.o cpacfstats_common.o
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
install: all

View File

@@ -55,168 +55,6 @@ static const char *const counter_str[] = {
[PAI_KERNEL] = "pai_kernel"
};
/* Strings for the pai counter details. Note that this is 0-based
* while PoP is 1-based.
*/
static const char *const pai_str[] = {
[ 0] = "KM DES",
[ 1] = "KM 2key TDES",
[ 2] = "KM TDES",
[ 3] = "KM DES protected key",
[ 4] = "KM 2key TDES protected key",
[ 5] = "KM TDES protected key",
[ 6] = "KM AES 128bit",
[ 7] = "KM AES 192bit",
[ 8] = "KM AES 256bit",
[ 9] = "KM AES 128bit protected key",
[ 10] = "KM AES 192bit protected key",
[ 11] = "KM AES 256bit protected key",
[ 12] = "KM AES-XTS 128bit",
[ 13] = "KM AES-XTS 256bit",
[ 14] = "KM AES-XTS 128bit protected key",
[ 15] = "KM AES-XTS 256bit protected key",
[ 16] = "KMC DES",
[ 17] = "KMC 2key TDES",
[ 18] = "KMC TDES",
[ 19] = "KMC DES protected key",
[ 20] = "KMC 2key TDES protected key",
[ 21] = "KMC TDES protected key",
[ 22] = "KMC AES 128bit",
[ 23] = "KMC AES 192bit",
[ 24] = "KMC AES 256bit",
[ 25] = "KMC AES 128bit protected key",
[ 26] = "KMC AES 192bit protected key",
[ 27] = "KMC AES 256bit protected key",
[ 28] = "KMC PRNG",
[ 29] = "KMA AES 128bit",
[ 30] = "KMA AES 192bit",
[ 31] = "KMA AES 256bit",
[ 32] = "KMA AES 128bit protected key",
[ 33] = "KMA AES 192bit protected key",
[ 34] = "KMA AES 256bit protected key",
[ 35] = "KMF DES",
[ 36] = "KMF 2key TDES",
[ 37] = "KMF TDES",
[ 38] = "KMF DES protected key",
[ 39] = "KMF 2key TDES protected key",
[ 40] = "KMF TDES protected key",
[ 41] = "KMF AES 128bit",
[ 42] = "KMF AES 192bit",
[ 43] = "KMF AES 256bit",
[ 44] = "KMF AES 128bit protected key",
[ 45] = "KMF AES 192bit protected key",
[ 46] = "KMF AES 256bit protected key",
[ 47] = "KMCTR DES",
[ 48] = "KMCTR 2key TDES",
[ 49] = "KMCTR TDES",
[ 50] = "KMCTR DES protected key",
[ 51] = "KMCTR 2key TDES protected key",
[ 52] = "KMCTR TDES protected key",
[ 53] = "KMCTR AES 128bit",
[ 54] = "KMCTR AES 192bit",
[ 55] = "KMCTR AES 256bit",
[ 56] = "KMCTR AES 128bit protected key",
[ 57] = "KMCTR AES 192bit protected key",
[ 58] = "KMCTR AES 256bit protected key",
[ 59] = "KMO DES",
[ 60] = "KMO 2key TDES",
[ 61] = "KMO TDES",
[ 62] = "KMO DES protected key",
[ 63] = "KMO 2key TDES protected key",
[ 64] = "KMO TDES protected key",
[ 65] = "KMO AES 128bit",
[ 66] = "KMO AES 192bit",
[ 67] = "KMO AES 256bit",
[ 68] = "KMO AES 128bit protected key",
[ 69] = "KMO AES 192bit protected key",
[ 70] = "KMO AES 256bit protected key",
[ 71] = "KIMD SHA1",
[ 72] = "KIMD SHA256",
[ 73] = "KIMD SHA512",
[ 74] = "KIMD SHA3-224",
[ 75] = "KIMD SHA3-256",
[ 76] = "KIMD SHA3-384",
[ 77] = "KIMD SHA3-512",
[ 78] = "KIMD SHAKE 128",
[ 79] = "KIMD SHAKE 256",
[ 80] = "KIMD GHASH",
[ 81] = "KLMD SHA1",
[ 82] = "KLMD SHA256",
[ 83] = "KLMD SHA512",
[ 84] = "KLMD SHA3-224",
[ 85] = "KLMD SHA3-256",
[ 86] = "KLMD SHA3-384",
[ 87] = "KLMD SHA3-512",
[ 88] = "KLMD SHAKE 128",
[ 89] = "KLMD SHAKE 256",
[ 90] = "KMAC DES",
[ 91] = "KMAC 2key TDES",
[ 92] = "KMAC TDES",
[ 93] = "KMAC DES protected key",
[ 94] = "KMAC 2key TDES protected key",
[ 95] = "KMAC TDES protected key",
[ 96] = "KMAC AES 128bit",
[ 97] = "KMAC AES 192bit",
[ 98] = "KMAC AES 256bit",
[ 99] = "KMAC AES 128bit protected key",
[100] = "KMAC AES 192bit protected key",
[101] = "KMAC AES 256bit protected key",
[102] = "PCC Last Block CMAC DES",
[103] = "PCC Last Block CMAC 2key TDES",
[104] = "PCC Last Block CMAC TDES",
[105] = "PCC Last Block CMAC DES protected key",
[106] = "PCC Last Block CMAC 2key TDES protected key",
[107] = "PCC Last Block CMAC TDES protected key",
[108] = "PCC Last Block CMAC AES 128bit",
[109] = "PCC Last Block CMAC AES 192bit",
[110] = "PCC Last Block CMAC AES 256bit",
[111] = "PCC Last Block CMAC AES 128bit protected key",
[112] = "PCC Last Block CMAC AES 192bit protected key",
[113] = "PCC Last Block CMAC AES 256bit protected key",
[114] = "PCC XTS Parameter AES 128bit",
[115] = "PCC XTS Parameter AES 256bit",
[116] = "PCC XTS Parameter AES 128bit protected key",
[117] = "PCC XTS Parameter AES 256bit protected key",
[118] = "PCC Scalar Mult P256",
[119] = "PCC Scalar Mult P384",
[120] = "PCC Scalar Mult P521",
[121] = "PCC Scalar Mult Ed25519",
[122] = "PCC Scalar Mult Ed448",
[123] = "PCC Scalar Mult X25519",
[124] = "PCC Scalar Mult X448",
[125] = "PRNO SHA512 DRNG",
[126] = "PRNO TRNG Query Ratio",
[127] = "PRNO TRNG",
[128] = "KDSA ECDSA Verify P256",
[129] = "KDSA ECDSA Verify P384",
[130] = "KDSA ECDSA Verify P521",
[131] = "KDSA ECDSA Sign P256",
[132] = "KDSA ECDSA Sign P384",
[133] = "KDSA ECDSA Sign P521",
[134] = "KDSA ECDSA Sign P256 protected key",
[135] = "KDSA ECDSA Sign P384 protected key",
[136] = "KDSA ECDSA Sign P521 protected key",
[137] = "KDSA EdDSA Verify Ed25519",
[138] = "KDSA EdDSA Verify Ed448",
[139] = "KDSA EdDSA Sign Ed25519",
[140] = "KDSA EdDSA Sign Ed448",
[141] = "KDSA EdDSA Sign Ed25519 protected key",
[142] = "KDSA EdDSA Sign Ed448 protected key",
[143] = "PCKMO DES",
[144] = "PCKMO 2key TDES",
[145] = "PCKMO TDES",
[146] = "PCKMO AES 128bit",
[147] = "PCKMO AES 192bit",
[148] = "PCKMO AES 256bit",
[149] = "PCKMO ECC P256",
[150] = "PCKMO ECC P384",
[151] = "PCKMO ECC P521",
[152] = "PCKMO ECC Ed25519",
[153] = "PCKMO ECC Ed448",
[154] = "Reserved 1",
[155] = "Reserved 2"
};
static int paiprintnonzero;
@@ -275,7 +113,8 @@ static void json_print_virtual_counter_answer(int s, int ctr,
int state, uint64_t value)
{
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
uint64_t i, paivalue = 0;
unsigned int maxnum;
const char *space;
switch (ctr) {
@@ -288,11 +127,11 @@ static void json_print_virtual_counter_answer(int s, int ctr,
printf("\"value\":%d}", !!value);
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
maxnum = get_num_user_space_ctrs();
space = "user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
maxnum = MAX_NUM_PAI;
space = "kernel";
break;
default:
@@ -304,7 +143,7 @@ static void json_print_virtual_counter_answer(int s, int ctr,
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
eprint("Expected %lu counter space for %s, but got %lu\n",
maxnum, space, value);
exit(EXIT_FAILURE);
}
@@ -315,18 +154,18 @@ static void json_print_virtual_counter_answer(int s, int ctr,
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL) {
if (paictr > MAX_NUM_PAI) {
eprint("Pai counter number too big: %d\n", paictr);
} else {
printjsonsep();
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
pai_str[paictr], space, paictr + 1);
get_ctr_name(paictr), space, paictr + 1);
if (paistate < 0) {
printf("\"error\":%d}", paistate);
/* Protocol does not send further counters. */
return;
}
printf("\"value\":%"PRIu64"}", paivalue);
printf("\"value\":%lu}", paivalue);
}
}
}
@@ -341,7 +180,8 @@ static void print_virtual_counter_answer(int s,
[UNSUPPORTED] = "unsupported"
};
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
uint64_t i, paivalue = 0;
unsigned int maxnum;
const char *ctrstr;
switch (ctr) {
@@ -350,11 +190,11 @@ static void print_virtual_counter_answer(int s,
printf(" hotplug detected\n");
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
maxnum = get_num_user_space_ctrs();
ctrstr = "pai_user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
maxnum = MAX_NUM_PAI;
ctrstr = "pai_kernel";
break;
default:
@@ -372,7 +212,7 @@ static void print_virtual_counter_answer(int s,
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
eprint("Expected %lu counters for %s, but got %lu\n",
maxnum, ctrstr, value);
exit(EXIT_FAILURE);
}
@@ -383,10 +223,11 @@ static void print_virtual_counter_answer(int s,
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL)
if (paictr > MAX_NUM_PAI)
eprint("Pai counter number too big: %d\n", paictr);
else if (!paiprintnonzero || paivalue > 0)
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
printf(" (%3d) %-45s: %lu\n", paictr + 1,
get_ctr_name(paictr), paivalue);
}
}
@@ -402,7 +243,7 @@ static void print_answer(int s, int ctr, int state, uint64_t value)
else if (state == UNSUPPORTED)
printf(" %s counter: unsupported\n", counter_str[ctr]);
else
printf(" %s counter: %"PRIu64"\n", counter_str[ctr], value);
printf(" %s counter: %lu\n", counter_str[ctr], value);
}
@@ -417,7 +258,7 @@ static void json_print_answer(int s, int ctr, int state, uint64_t value)
} else if (state == ENABLED) {
printjsonsep();
printf("{\"counter\":\"%s\",", counter_str[ctr]);
printf("\"value\":%"PRIu64"}", value);
printf("\"value\":%lu}", value);
}
}

View File

@@ -20,12 +20,22 @@
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
/*
* Number of PAI counters for user space. This excludes PCKMO since
* this instruction is privileged.
* Number of PAI counters. Contains all counters regardless of kernel or user
* space
*/
#define NUM_PAI_USER 143
/* Number of PAI counters for kernel space. Contains all counters. */
#define NUM_PAI_KERNEL 156
#define MAX_NUM_PAI 172
/*
* This is the sysfs directory from which cpacfstatsd daemon application loads
* the available PAI counters
*/
#define SYSFS_PAI_COUNTER "/sys/bus/event_source/devices/pai_crypto/events/"
/*
* Note that this is the first kernel only counter in the 1-based list of the
* architecture and NOT from the 0-based list in the cpacfstats code!
*/
#define FIRST_KERNEL_ONLY_COUNTER 144
int eprint(const char *format, ...);
@@ -67,6 +77,12 @@ enum state_e {
UNSUPPORTED
};
enum counter_type {
SUPPRESS_COUNTER = 0,
KERNEL_AND_USER_COUNTER,
KERNEL_ONLY_COUNTER,
};
/*
* query send from client to daemon
* Consist of:
@@ -122,15 +138,23 @@ int recv_msg(int sfd, struct msg *m, int timeout);
/* perf_crypto.c */
int perf_init(void);
int perf_init(unsigned int *supported_counters);
void perf_stop(void);
void perf_close(void);
int perf_enable_ctr(enum ctr_e ctr);
int perf_disable_ctr(enum ctr_e ctr);
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value);
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
int perf_enable_ctr(enum ctr_e ctr, unsigned int *supported_counters);
int perf_disable_ctr(enum ctr_e ctr, unsigned int *supported_counters);
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
*supported_counters);
int perf_read_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
*supported_counters);
int perf_ecc_supported(void);
int perf_ctr_state(enum ctr_e ctr);
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
/* cpacfstats_common.c */
enum counter_type is_user_space(unsigned int ctr);
const char *get_ctr_name(unsigned int ctr);
unsigned int get_num_user_space_ctrs(void);
#endif

View File

@@ -0,0 +1,253 @@
/* SPDX-License-Identifier: MIT */
/*
* cpacfstats_common.c - shared code by daemon and client
*
* Copyright IBM Corp. 2024
*/
#include <stdint.h>
#include <stdlib.h>
#include "cpacfstats.h"
struct pai_counter {
const char *str;
const unsigned int counter_type;
};
/*
* Strings for the pai counter details.
* Integer indicating if kernel space is needed (0 for user, KERNEL_ONLY_COUNTER for kernel)
* Note that this is 0-based while PoP is 1-based.
*
* When adding new items to this list add the counter number in the pai_idx
* list in cpacfstatsd.c and increase the number of total counters in
* cpacfstats.h.
*/
const struct pai_counter pai[] = {
[ 0] = {"KM DES", KERNEL_AND_USER_COUNTER},
[ 1] = {"KM 2key TDES", KERNEL_AND_USER_COUNTER},
[ 2] = {"KM TDES", KERNEL_AND_USER_COUNTER},
[ 3] = {"KM DES protected key", KERNEL_AND_USER_COUNTER},
[ 4] = {"KM 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 5] = {"KM TDES protected key", KERNEL_AND_USER_COUNTER},
[ 6] = {"KM AES 128bit", KERNEL_AND_USER_COUNTER},
[ 7] = {"KM AES 192bit", KERNEL_AND_USER_COUNTER},
[ 8] = {"KM AES 256bit", KERNEL_AND_USER_COUNTER},
[ 9] = {"KM AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 10] = {"KM AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 11] = {"KM AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 12] = {"KM AES-XTS 128bit", KERNEL_AND_USER_COUNTER},
[ 13] = {"KM AES-XTS 256bit", KERNEL_AND_USER_COUNTER},
[ 14] = {"KM AES-XTS 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 15] = {"KM AES-XTS 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 16] = {"KMC DES", KERNEL_AND_USER_COUNTER},
[ 17] = {"KMC 2key TDES", KERNEL_AND_USER_COUNTER},
[ 18] = {"KMC TDES", KERNEL_AND_USER_COUNTER},
[ 19] = {"KMC DES protected key", KERNEL_AND_USER_COUNTER},
[ 20] = {"KMC 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 21] = {"KMC TDES protected key", KERNEL_AND_USER_COUNTER},
[ 22] = {"KMC AES 128bit", KERNEL_AND_USER_COUNTER},
[ 23] = {"KMC AES 192bit", KERNEL_AND_USER_COUNTER},
[ 24] = {"KMC AES 256bit", KERNEL_AND_USER_COUNTER},
[ 25] = {"KMC AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 26] = {"KMC AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 27] = {"KMC AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 28] = {"KMC PRNG", KERNEL_AND_USER_COUNTER},
[ 29] = {"KMA AES 128bit", KERNEL_AND_USER_COUNTER},
[ 30] = {"KMA AES 192bit", KERNEL_AND_USER_COUNTER},
[ 31] = {"KMA AES 256bit", KERNEL_AND_USER_COUNTER},
[ 32] = {"KMA AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 33] = {"KMA AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 34] = {"KMA AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 35] = {"KMF DES", KERNEL_AND_USER_COUNTER},
[ 36] = {"KMF 2key TDES", KERNEL_AND_USER_COUNTER},
[ 37] = {"KMF TDES", KERNEL_AND_USER_COUNTER},
[ 38] = {"KMF DES protected key", KERNEL_AND_USER_COUNTER},
[ 39] = {"KMF 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 40] = {"KMF TDES protected key", KERNEL_AND_USER_COUNTER},
[ 41] = {"KMF AES 128bit", KERNEL_AND_USER_COUNTER},
[ 42] = {"KMF AES 192bit", KERNEL_AND_USER_COUNTER},
[ 43] = {"KMF AES 256bit", KERNEL_AND_USER_COUNTER},
[ 44] = {"KMF AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 45] = {"KMF AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 46] = {"KMF AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 47] = {"KMCTR DES", KERNEL_AND_USER_COUNTER},
[ 48] = {"KMCTR 2key TDES", KERNEL_AND_USER_COUNTER},
[ 49] = {"KMCTR TDES", KERNEL_AND_USER_COUNTER},
[ 50] = {"KMCTR DES protected key", KERNEL_AND_USER_COUNTER},
[ 51] = {"KMCTR 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 52] = {"KMCTR TDES protected key", KERNEL_AND_USER_COUNTER},
[ 53] = {"KMCTR AES 128bit", KERNEL_AND_USER_COUNTER},
[ 54] = {"KMCTR AES 192bit", KERNEL_AND_USER_COUNTER},
[ 55] = {"KMCTR AES 256bit", KERNEL_AND_USER_COUNTER},
[ 56] = {"KMCTR AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 57] = {"KMCTR AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 58] = {"KMCTR AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 59] = {"KMO DES", KERNEL_AND_USER_COUNTER},
[ 60] = {"KMO 2key TDES", KERNEL_AND_USER_COUNTER},
[ 61] = {"KMO TDES", KERNEL_AND_USER_COUNTER},
[ 62] = {"KMO DES protected key", KERNEL_AND_USER_COUNTER},
[ 63] = {"KMO 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 64] = {"KMO TDES protected key", KERNEL_AND_USER_COUNTER},
[ 65] = {"KMO AES 128bit", KERNEL_AND_USER_COUNTER},
[ 66] = {"KMO AES 192bit", KERNEL_AND_USER_COUNTER},
[ 67] = {"KMO AES 256bit", KERNEL_AND_USER_COUNTER},
[ 68] = {"KMO AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[ 69] = {"KMO AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[ 70] = {"KMO AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[ 71] = {"KIMD SHA1", KERNEL_AND_USER_COUNTER},
[ 72] = {"KIMD SHA256", KERNEL_AND_USER_COUNTER},
[ 73] = {"KIMD SHA512", KERNEL_AND_USER_COUNTER},
[ 74] = {"KIMD SHA3-224", KERNEL_AND_USER_COUNTER},
[ 75] = {"KIMD SHA3-256", KERNEL_AND_USER_COUNTER},
[ 76] = {"KIMD SHA3-384", KERNEL_AND_USER_COUNTER},
[ 77] = {"KIMD SHA3-512", KERNEL_AND_USER_COUNTER},
[ 78] = {"KIMD SHAKE 128", KERNEL_AND_USER_COUNTER},
[ 79] = {"KIMD SHAKE 256", KERNEL_AND_USER_COUNTER},
[ 80] = {"KIMD GHASH", KERNEL_AND_USER_COUNTER},
[ 81] = {"KLMD SHA1", KERNEL_AND_USER_COUNTER},
[ 82] = {"KLMD SHA256", KERNEL_AND_USER_COUNTER},
[ 83] = {"KLMD SHA512", KERNEL_AND_USER_COUNTER},
[ 84] = {"KLMD SHA3-224", KERNEL_AND_USER_COUNTER},
[ 85] = {"KLMD SHA3-256", KERNEL_AND_USER_COUNTER},
[ 86] = {"KLMD SHA3-384", KERNEL_AND_USER_COUNTER},
[ 87] = {"KLMD SHA3-512", KERNEL_AND_USER_COUNTER},
[ 88] = {"KLMD SHAKE 128", KERNEL_AND_USER_COUNTER},
[ 89] = {"KLMD SHAKE 256", KERNEL_AND_USER_COUNTER},
[ 90] = {"KMAC DES", KERNEL_AND_USER_COUNTER},
[ 91] = {"KMAC 2key TDES", KERNEL_AND_USER_COUNTER},
[ 92] = {"KMAC TDES", KERNEL_AND_USER_COUNTER},
[ 93] = {"KMAC DES protected key", KERNEL_AND_USER_COUNTER},
[ 94] = {"KMAC 2key TDES protected key", KERNEL_AND_USER_COUNTER},
[ 95] = {"KMAC TDES protected key", KERNEL_AND_USER_COUNTER},
[ 96] = {"KMAC AES 128bit", KERNEL_AND_USER_COUNTER},
[ 97] = {"KMAC AES 192bit", KERNEL_AND_USER_COUNTER},
[ 98] = {"KMAC AES 256bit", KERNEL_AND_USER_COUNTER},
[ 99] = {"KMAC AES 128bit protected key", KERNEL_AND_USER_COUNTER},
[100] = {"KMAC AES 192bit protected key", KERNEL_AND_USER_COUNTER},
[101] = {"KMAC AES 256bit protected key", KERNEL_AND_USER_COUNTER},
[102] = {"PCC Last Block CMAC DES", KERNEL_AND_USER_COUNTER},
[103] = {"PCC Last Block CMAC 2key TDES", KERNEL_AND_USER_COUNTER},
[104] = {"PCC Last Block CMAC TDES", KERNEL_AND_USER_COUNTER},
[105] = {"PCC Last Block CMAC DES protected key",
KERNEL_AND_USER_COUNTER},
[106] = {"PCC Last Block CMAC 2key TDES protected key",
KERNEL_AND_USER_COUNTER},
[107] = {"PCC Last Block CMAC TDES protected key",
KERNEL_AND_USER_COUNTER},
[108] = {"PCC Last Block CMAC AES 128bit", KERNEL_AND_USER_COUNTER},
[109] = {"PCC Last Block CMAC AES 192bit", KERNEL_AND_USER_COUNTER},
[110] = {"PCC Last Block CMAC AES 256bit", KERNEL_AND_USER_COUNTER},
[111] = {"PCC Last Block CMAC AES 128bit protected key",
KERNEL_AND_USER_COUNTER},
[112] = {"PCC Last Block CMAC AES 192bit protected key",
KERNEL_AND_USER_COUNTER},
[113] = {"PCC Last Block CMAC AES 256bit protected key",
KERNEL_AND_USER_COUNTER},
[114] = {"PCC XTS Parameter AES 128bit", KERNEL_AND_USER_COUNTER},
[115] = {"PCC XTS Parameter AES 256bit", KERNEL_AND_USER_COUNTER},
[116] = {"PCC XTS Parameter AES 128bit protected key",
KERNEL_AND_USER_COUNTER},
[117] = {"PCC XTS Parameter AES 256bit protected key",
KERNEL_AND_USER_COUNTER},
[118] = {"PCC Scalar Mult P256", KERNEL_AND_USER_COUNTER},
[119] = {"PCC Scalar Mult P384", KERNEL_AND_USER_COUNTER},
[120] = {"PCC Scalar Mult P521", KERNEL_AND_USER_COUNTER},
[121] = {"PCC Scalar Mult Ed25519", KERNEL_AND_USER_COUNTER},
[122] = {"PCC Scalar Mult Ed448", KERNEL_AND_USER_COUNTER},
[123] = {"PCC Scalar Mult X25519", KERNEL_AND_USER_COUNTER},
[124] = {"PCC Scalar Mult X448", KERNEL_AND_USER_COUNTER},
[125] = {"PRNO SHA512 DRNG", KERNEL_AND_USER_COUNTER},
[126] = {"PRNO TRNG Query Ratio", KERNEL_AND_USER_COUNTER},
[127] = {"PRNO TRNG", KERNEL_AND_USER_COUNTER},
[128] = {"KDSA ECDSA Verify P256", KERNEL_AND_USER_COUNTER},
[129] = {"KDSA ECDSA Verify P384", KERNEL_AND_USER_COUNTER},
[130] = {"KDSA ECDSA Verify P521", KERNEL_AND_USER_COUNTER},
[131] = {"KDSA ECDSA Sign P256", KERNEL_AND_USER_COUNTER},
[132] = {"KDSA ECDSA Sign P384", KERNEL_AND_USER_COUNTER},
[133] = {"KDSA ECDSA Sign P521", KERNEL_AND_USER_COUNTER},
[134] = {"KDSA ECDSA Sign P256 protected key",
KERNEL_AND_USER_COUNTER},
[135] = {"KDSA ECDSA Sign P384 protected key",
KERNEL_AND_USER_COUNTER},
[136] = {"KDSA ECDSA Sign P521 protected key",
KERNEL_AND_USER_COUNTER},
[137] = {"KDSA EdDSA Verify Ed25519", KERNEL_AND_USER_COUNTER},
[138] = {"KDSA EdDSA Verify Ed448", KERNEL_AND_USER_COUNTER},
[139] = {"KDSA EdDSA Sign Ed25519", KERNEL_AND_USER_COUNTER},
[140] = {"KDSA EdDSA Sign Ed448", KERNEL_AND_USER_COUNTER},
[141] = {"KDSA EdDSA Sign Ed25519 protected key",
KERNEL_AND_USER_COUNTER},
[142] = {"KDSA EdDSA Sign Ed448 protected key",
KERNEL_AND_USER_COUNTER},
[143] = {"PCKMO DES", KERNEL_ONLY_COUNTER},
[144] = {"PCKMO 2key TDES", KERNEL_ONLY_COUNTER},
[145] = {"PCKMO TDES", KERNEL_ONLY_COUNTER},
[146] = {"PCKMO AES 128bit", KERNEL_ONLY_COUNTER},
[147] = {"PCKMO AES 192bit", KERNEL_ONLY_COUNTER},
[148] = {"PCKMO AES 256bit", KERNEL_ONLY_COUNTER},
[149] = {"PCKMO ECC P256", KERNEL_ONLY_COUNTER},
[150] = {"PCKMO ECC P384", KERNEL_ONLY_COUNTER},
[151] = {"PCKMO ECC P521", KERNEL_ONLY_COUNTER},
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER},
[156] = {"KM AES-XTS (full) 128bit", KERNEL_AND_USER_COUNTER},
[157] = {"KM AES-XTS (full) 256bit", KERNEL_AND_USER_COUNTER},
[158] = {"KM AES-XTS (full) 128bit protected key",
KERNEL_AND_USER_COUNTER},
[159] = {"KM AES-XTS (full) 256bit protected key",
KERNEL_AND_USER_COUNTER},
[160] = {"KMAC HMAC SHA 224", KERNEL_AND_USER_COUNTER},
[161] = {"KMAC HMAC SHA 256", KERNEL_AND_USER_COUNTER},
[162] = {"KMAC HMAC SHA 384", KERNEL_AND_USER_COUNTER},
[163] = {"KMAC HMAC SHA 512", KERNEL_AND_USER_COUNTER},
[164] = {"KMAC HMAC SHA 224 protected key", KERNEL_AND_USER_COUNTER},
[165] = {"KMAC HMAC SHA 256 protected key", KERNEL_AND_USER_COUNTER},
[166] = {"KMAC HMAC SHA 384 protected key", KERNEL_AND_USER_COUNTER},
[167] = {"KMAC HMAC SHA 512 protected key", KERNEL_AND_USER_COUNTER},
[168] = {"PCKMO HMAC 512 protected key", KERNEL_ONLY_COUNTER},
[169] = {"PCKMO HMAC 1024 protected key", KERNEL_ONLY_COUNTER},
[170] = {"PCKMO AES-XTS 128bit double key protected key",
KERNEL_ONLY_COUNTER},
[171] = {"PCKMO AES-XTS 256bit double key protected key",
KERNEL_ONLY_COUNTER}
};
/*
* Returns counter_type of pai_counter struct
*
* SUPPRESS_COUNTER
* KERNEL_AND_USER_COUNTER
* KERNEL_ONLY_COUNTER
*/
enum counter_type is_user_space(unsigned int ctr)
{
if (ctr >= MAX_NUM_PAI)
return SUPPRESS_COUNTER;
return pai[ctr].counter_type;
}
const char *get_ctr_name(unsigned int ctr)
{
if (ctr >= MAX_NUM_PAI)
return NULL;
return pai[ctr].str;
}
/*
* Returns number of PAI counters for which no kernel space is needed
*/
unsigned int get_num_user_space_ctrs(void)
{
unsigned int counter = 0;
unsigned int i;
for (i = 0; i < MAX_NUM_PAI; i++) {
if (is_user_space(i) == KERNEL_AND_USER_COUNTER)
counter++;
}
return counter;
}

View File

@@ -24,12 +24,54 @@
#include <sys/stat.h>
#include <syslog.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <limits.h>
#include "lib/zt_common.h"
#include "lib/util_file.h"
#include "cpacfstats.h"
static volatile int stopsig;
/*
* This list contains the counter numbers sorted by instruction
*/
static const unsigned int pai_idx[] = {
// KM
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 156, 157, 158,
159,
// KMC
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
// KMA
29, 30, 31, 32, 33, 34,
// KMF
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
// KMCTR
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
// KMO
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
// KIMD
71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
// KLMD
81, 82, 83, 84, 85, 86, 87, 88, 89,
// KMAC
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 160, 161, 162, 163,
164, 165, 166, 167,
// PCC
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
// PRNO
125, 126, 127,
// KDSA
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142,
// PCKMO
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 168, 169, 170, 171,
// Reserved
154, 155
};
static const char *const name = "cpacfstatsd";
static const char *const usage =
@@ -68,7 +110,6 @@ static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
return rc;
}
static int send_answer(int s, int ctr, int state, uint64_t value)
{
struct msg m;
@@ -84,7 +125,6 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
}
/*
* Print according to protocol for PAI:
* - first the state and the number of PAI counters that follow
@@ -93,34 +133,34 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
* Note that the PAI counters are 0-based, not 1 based as in PoP!
* Sending ends with the first error.
*/
static int do_send_pai(int s, int user)
static int do_send_pai(int s, int user, unsigned int *counter)
{
int ctr, state, i, maxctr, rc = 0;
int ctr, state, i, rc = 0;
unsigned int current_ctr;
uint64_t value;
if (user) {
ctr = PAI_USER;
maxctr = NUM_PAI_USER;
} else {
ctr = PAI_KERNEL;
maxctr = NUM_PAI_KERNEL;
}
ctr = user ? PAI_USER : PAI_KERNEL;
state = perf_ctr_state(ctr);
if (state != ENABLED)
return rc;
for (i = 0; i < maxctr; ++i) {
rc = perf_read_pai_ctr(i, user, &value);
for (i = 0; i < MAX_NUM_PAI; ++i) {
current_ctr = pai_idx[i];
if ((user && is_user_space(current_ctr) != KERNEL_AND_USER_COUNTER) ||
(!user && is_user_space(current_ctr) == SUPPRESS_COUNTER) ||
counter[current_ctr] != 1)
continue;
rc = perf_read_pai_ctr(current_ctr, user, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
send_answer(s, current_ctr, rc, 0);
break;
}
send_answer(s, i, state, value);
send_answer(s, current_ctr, state, value);
}
return rc;
}
static int do_enable(int s, enum ctr_e ctr)
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
uint64_t value = 0;
int i, rc = 0;
@@ -132,7 +172,7 @@ static int do_enable(int s, enum ctr_e ctr)
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == DISABLED) {
rc = perf_enable_ctr(i);
rc = perf_enable_ctr(i, supported_counters);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
@@ -140,7 +180,7 @@ static int do_enable(int s, enum ctr_e ctr)
state = ENABLED;
}
if (state != UNSUPPORTED) {
rc = perf_read_ctr(i, &value);
rc = perf_read_ctr(i, &value, supported_counters);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
@@ -148,20 +188,19 @@ static int do_enable(int s, enum ctr_e ctr)
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
rc = do_send_pai(s, 1, supported_counters);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
rc = do_send_pai(s, 0, supported_counters);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int do_disable(int s, enum ctr_e ctr)
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0;
uint64_t value;
@@ -171,7 +210,7 @@ static int do_disable(int s, enum ctr_e ctr)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (perf_ctr_state(i) == ENABLED) {
rc = perf_disable_ctr(i);
rc = perf_disable_ctr(i, supported_counters);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
@@ -181,14 +220,13 @@ static int do_disable(int s, enum ctr_e ctr)
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int do_reset(int s, enum ctr_e ctr)
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
uint64_t value;
@@ -199,7 +237,7 @@ static int do_reset(int s, enum ctr_e ctr)
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == ENABLED) {
rc = perf_reset_ctr(i, &value);
rc = perf_reset_ctr(i, &value, supported_counters);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
@@ -207,20 +245,19 @@ static int do_reset(int s, enum ctr_e ctr)
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
rc = do_send_pai(s, 1, supported_counters);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
rc = do_send_pai(s, 0, supported_counters);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int do_print(int s, enum ctr_e ctr)
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
uint64_t value = 0;
@@ -231,7 +268,7 @@ static int do_print(int s, enum ctr_e ctr)
if (i == (int) ctr || ctr == ALL_COUNTER) {
state = perf_ctr_state(i);
if (state == ENABLED) {
rc = perf_read_ctr(i, &value);
rc = perf_read_ctr(i, &value, supported_counters);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
@@ -239,19 +276,18 @@ static int do_print(int s, enum ctr_e ctr)
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
rc = do_send_pai(s, 1, supported_counters);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
rc = do_send_pai(s, 0, supported_counters);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int become_daemon(int *startup_pipe)
{
int child_initialized = 0, fd;
@@ -344,7 +380,6 @@ static int become_daemon(int *startup_pipe)
return 0;
}
static void remove_sock(void)
{
remove(SOCKET_FILE);
@@ -406,14 +441,12 @@ static void remove_pidfile(void)
remove(PID_FILE);
}
void signalhandler(int sig)
{
perf_stop();
stopsig = sig;
}
int eprint(const char *format, ...)
{
char buf[512];
@@ -435,10 +468,44 @@ int eprint(const char *format, ...)
return n;
}
/*
* returns -1 on error
* returns X where X is the found counters in dir
*
* the supplied array supported_counters[] is filled in this function with the
* available PAI counters found in SYSFS_PAI_COUNTER
*/
static void supported_functions(unsigned int supported_counters[])
{
const char *dir = SYSFS_PAI_COUNTER;
struct dirent *dp = NULL;
char filepath[PATH_MAX];
unsigned int num;
DIR *dfd = NULL;
dfd = opendir(dir);
if (dfd == NULL)
return;
while ((dp = readdir(dfd)) != NULL) {
if ((strcmp(dp->d_name, ".") != 0) &&
(strcmp(dp->d_name, "..") != 0)) {
snprintf(filepath, sizeof(filepath), "%s%s", dir, dp->d_name);
if (util_file_read_va(filepath, "event=0x10%x", &num) != 1)
continue;
if (num > 0 && num <= MAX_NUM_PAI)
supported_counters[num - 1] = 1;
}
}
closedir(dfd);
return;
}
int main(int argc, char *argv[])
{
int rc, sfd, foreground = 0, startup_pipe = -1, initialized = 0;
unsigned int supported_counters[MAX_NUM_PAI] = { 0 };
struct sigaction act;
if (argc > 1) {
@@ -485,7 +552,9 @@ int main(int argc, char *argv[])
}
}
if (perf_init() != 0) {
supported_functions(supported_counters);
if (perf_init(supported_counters) != 0) {
eprint("Couldn't initialize perf lib\n");
goto error;
}
@@ -548,13 +617,13 @@ int main(int argc, char *argv[])
}
if (cmd == ENABLE)
rc = do_enable(s, ctr);
rc = do_enable(s, ctr, supported_counters);
else if (cmd == DISABLE)
rc = do_disable(s, ctr);
rc = do_disable(s, ctr, supported_counters);
else if (cmd == RESET)
rc = do_reset(s, ctr);
rc = do_reset(s, ctr, supported_counters);
else if (cmd == PRINT)
rc = do_print(s, ctr);
rc = do_print(s, ctr, supported_counters);
else {
eprint("Received unknown command %d, ignoring\n",
(int) cmd);

View File

@@ -52,8 +52,8 @@ static struct pmf_data {
struct percpucounter {
int ctr_fds[ALL_COUNTER];
int pai_user[NUM_PAI_USER];
int pai_kernel[NUM_PAI_KERNEL];
int pai_user[MAX_NUM_PAI];
int pai_kernel[MAX_NUM_PAI];
unsigned int cpunum;
struct percpucounter *next;
};
@@ -84,10 +84,10 @@ static struct percpucounter *allocpercpucounter(unsigned int cpunum)
for (i = 0; i < ALL_COUNTER; ++i)
ppc->ctr_fds[i] = -1;
for (i = 0; i < NUM_PAI_USER; ++i)
for (i = 0; i < MAX_NUM_PAI; ++i) {
ppc->pai_user[i] = -1;
for (i = 0; i < NUM_PAI_KERNEL; ++i)
ppc->pai_kernel[i] = -1;
}
ppc->cpunum = cpunum;
ppc->next = NULL;
}
@@ -100,10 +100,10 @@ static void freepercpucounter(struct percpucounter *pcpu)
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
for (i = 0; i < MAX_NUM_PAI; ++i) {
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
}
free(pcpu);
}
@@ -225,7 +225,7 @@ static int perf_event_encode(int *pmutype, int *eventid,
return 0;
}
static int activatecpu(unsigned int cpu)
static int activatecpu(unsigned int cpu, unsigned int *supported_counters)
{
struct perf_event_attr pfm_event;
struct percpucounter *ppc;
@@ -273,7 +273,10 @@ static int activatecpu(unsigned int cpu)
(ctr_state[PAI_USER] == UNSUPPORTED) ==
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
if (ctr_state[PAI_USER] != UNSUPPORTED) {
for (i = 1; i <= NUM_PAI_USER; ++i) {
for (i = 1; i <= MAX_NUM_PAI; ++i) {
if (is_user_space(i - 1) != KERNEL_AND_USER_COUNTER ||
supported_counters[i - 1] != 1)
continue;
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
@@ -307,7 +310,14 @@ static int activatecpu(unsigned int cpu)
ppc->pai_kernel[i - 1] = fd;
}
}
for (; i <= NUM_PAI_KERNEL; ++i) {
/*
* i can start at the index of the first PAI counter
* for which kernel space is needed
*/
for (i = FIRST_KERNEL_ONLY_COUNTER; i <= MAX_NUM_PAI; ++i) {
if (is_user_space(i - 1) == SUPPRESS_COUNTER ||
supported_counters[i - 1] != 1)
continue;
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
@@ -348,10 +358,10 @@ static void deactivatecpu(unsigned int cpunum)
if (pcpu != NULL) {
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
for (i = 0; i < MAX_NUM_PAI; ++i) {
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
}
free(pcpu);
if (enabledcounter)
hotplugdetected = 1;
@@ -359,7 +369,7 @@ static void deactivatecpu(unsigned int cpunum)
pthread_mutex_unlock(&rootmux);
}
static int addallcpus(void)
static int addallcpus(unsigned int *supported_counters)
{
unsigned int start, end;
int scanned, rc = 0;
@@ -379,7 +389,7 @@ static int addallcpus(void)
if (scanned == 1)
end = start;
for (; start <= end; ++start) {
if (activatecpu(start)) {
if (activatecpu(start, supported_counters)) {
rc = -1;
goto out;
}
@@ -409,7 +419,7 @@ static int perf_load_counter_data(void)
return res;
}
static void *hotplughandler(void *UNUSED(unused))
static void *hotplughandler(void *supported_counters)
{
struct udev *hotplug;
struct udev_monitor *monitor;
@@ -452,7 +462,7 @@ static void *hotplughandler(void *UNUSED(unused))
path = udev_device_get_devpath(dev);
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
continue;
if (on && activatecpu(cpunum))
if (on && activatecpu(cpunum, (unsigned int *) supported_counters))
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
if (off)
deactivatecpu(cpunum);
@@ -462,11 +472,18 @@ static void *hotplughandler(void *UNUSED(unused))
return NULL;
}
int perf_init(void)
int perf_init(unsigned int *supported_counters)
{
int ecc_supported, i, num;
static const char *cpum_cf[] = {
"DEA_FUNCTIONS",
"AES_FUNCTIONS",
"SHA_FUNCTIONS",
"PRNG_FUNCTIONS",
"ECC_FUNCTION_COUNT"
};
unsigned long maxfd;
struct rlimit rlim;
int i, num;
FILE *f;
/* initialize performance monitoring library */
@@ -478,16 +495,18 @@ int perf_init(void)
/* We currently support all cpumf counters plus two virtual
* counters for PAI. */
num = ALL_COUNTER + 2;
/* Check if ECC is supported on current hardware */
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
if (!cpumf_authorized()) {
for (i = 0; i < ALL_COUNTER; ++i)
ctr_state[i] = UNSUPPORTED;
num -= ALL_COUNTER;
} else if (!ecc_supported) {
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
--num;
} else {
for (i = 0; i < ALL_COUNTER; i++) {
if (!perf_counter_supported("cpum_cf", cpum_cf[i])) {
ctr_state[i] = UNSUPPORTED;
num--;
}
}
}
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
@@ -523,11 +542,12 @@ int perf_init(void)
return -1;
}
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
if (pthread_create(&hotplugthread, NULL, hotplughandler,
supported_counters)) {
eprint("Failed to start hotplug handler thread\n");
return -1;
}
return addallcpus();
return addallcpus(supported_counters);
}
@@ -552,11 +572,14 @@ void perf_close(void)
}
static int enable_array(int *arr, int size)
static int enable_array(int *arr, int user, unsigned int *supported_counters)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
for (i = 0; i < MAX_NUM_PAI; ++i) {
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
continue;
ec = ioctl(arr[i], PERF_EVENT_IOC_ENABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
@@ -568,14 +591,14 @@ static int enable_array(int *arr, int size)
}
int perf_enable_ctr(enum ctr_e ctr)
int perf_enable_ctr(enum ctr_e ctr, unsigned int *supported_counters)
{
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_enable_ctr(ctr);
rc = perf_enable_ctr(ctr, supported_counters);
if (rc != 0)
return rc;
}
@@ -593,7 +616,7 @@ int perf_enable_ctr(enum ctr_e ctr)
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
ec = enable_array(pcpu->pai_user, 1, supported_counters);
if (ec < 0)
rc = -1;
}
@@ -602,7 +625,7 @@ int perf_enable_ctr(enum ctr_e ctr)
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
ec = enable_array(pcpu->pai_kernel, 0, supported_counters);
if (ec < 0)
rc = -1;
}
@@ -617,11 +640,14 @@ int perf_enable_ctr(enum ctr_e ctr)
}
static int disable_array(int *arr, int size)
static int disable_array(int *arr, int user, unsigned int *supported_counters)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
for (i = 0; i < MAX_NUM_PAI; ++i) {
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
continue;
ec = ioctl(arr[i], PERF_EVENT_IOC_DISABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
@@ -633,14 +659,14 @@ static int disable_array(int *arr, int size)
}
int perf_disable_ctr(enum ctr_e ctr)
int perf_disable_ctr(enum ctr_e ctr, unsigned int *supported_counters)
{
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_disable_ctr(ctr);
rc = perf_disable_ctr(ctr, supported_counters);
if (rc != 0)
return rc;
}
@@ -660,7 +686,7 @@ int perf_disable_ctr(enum ctr_e ctr)
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
ec = disable_array(pcpu->pai_user, 1, supported_counters);
if (ec < 0)
rc = -1;
}
@@ -671,7 +697,7 @@ int perf_disable_ctr(enum ctr_e ctr)
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
ec = disable_array(pcpu->pai_kernel, 0, supported_counters);
if (ec < 0)
rc = -1;
}
@@ -688,11 +714,14 @@ int perf_disable_ctr(enum ctr_e ctr)
}
static int reset_array(int *arr, int size)
static int reset_array(int *arr, int user, unsigned int *supported_counters)
{
int ec, rc = 0, i;
for (i = 0; i < size; ++i) {
for (i = 0; i < MAX_NUM_PAI; ++i) {
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
continue;
ec = ioctl(arr[i], PERF_EVENT_IOC_RESET, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
@@ -704,14 +733,15 @@ static int reset_array(int *arr, int size)
}
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
*supported_counters)
{
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_reset_ctr(ctr, value);
rc = perf_reset_ctr(ctr, value, supported_counters);
if (rc != 0)
return rc;
}
@@ -727,14 +757,14 @@ int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
ec = reset_array(pcpu->pai_user, 1, supported_counters);
if (ec < 0)
rc = -1;
}
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
ec = reset_array(pcpu->pai_kernel, 0, supported_counters);
if (ec < 0)
rc = -1;
}
@@ -743,12 +773,13 @@ int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
rc = -1;
}
if (rc == 0)
rc = perf_read_ctr(ctr, value);
rc = perf_read_ctr(ctr, value, supported_counters);
return rc;
}
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
int perf_read_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
*supported_counters)
{
struct percpucounter *pcpu;
int ec, rc = 0;
@@ -761,11 +792,26 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
return 0;
}
if (ctr == PAI_USER) {
*value = NUM_PAI_USER;
int c = 0;
for (int i = 0; i < MAX_NUM_PAI; i++) {
if (is_user_space(i) == KERNEL_AND_USER_COUNTER &&
supported_counters[i] == 1)
c++;
}
*value = c;
return 0;
}
if (ctr == PAI_KERNEL) {
*value = NUM_PAI_KERNEL;
int c = 0;
for (int i = 0; i < MAX_NUM_PAI; i++) {
if (supported_counters[i] == 1)
c++;
}
*value = c;
return 0;
}
if (ctr >= ALL_COUNTER)
@@ -802,14 +848,15 @@ int perf_ctr_state(enum ctr_e ctr) {
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
{
struct percpucounter *pcpu;
unsigned int maxctr;
int *arr, ec, rc = 0;
uint64_t val;
*value = 0;
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
if (ctrnum >= maxctr)
if (is_user_space(ctrnum) == SUPPRESS_COUNTER ||
(user && is_user_space(ctrnum) == KERNEL_ONLY_COUNTER))
return -1;
foreachcpu(pcpu) {
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
ec = read(arr[ctrnum], &val, sizeof(val));

View File

@@ -3473,6 +3473,7 @@ static struct counters *get_counter(int ctrset, size_t *len)
read_ccerror(cp, *len);
break;
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
cp = cpumcf_z16_counters;
*len = ARRAY_SIZE(cpumcf_z16_counters);
}

View File

@@ -4,9 +4,11 @@ all: cpuplugd
LDLIBS += -lm
libs = $(rootdir)/libutil/libutil.a
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
cpuplugd: $(OBJECTS)
cpuplugd: $(OBJECTS) $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
clean:

View File

@@ -204,6 +204,45 @@ void parse_configfile(char *file)
fclose(filp);
}
void apply_cpu_config(void)
{
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below ");
cpuplugd_debug("the minimum and will be increased.\n");
while (get_num_online_cpus() < cfg.cpu_min) {
if (hotplug_one_cpu())
break;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum");
cpuplugd_debug(" and will be decreased.\n");
while (get_num_online_cpus() > cfg.cpu_max) {
if (hotunplug_one_cpu())
break;
}
}
if (cfg.cpu_min > get_numcpus()) {
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_debug("The minimum amount of cpus is above the ");
cpuplugd_debug("number of available cpus.\n");
cpuplugd_exit("Detected %d available cpus\n", get_numcpus());
}
if (get_num_online_cpus() < cfg.cpu_min) {
cpuplugd_debug("Failed to set the number of online cpus to ");
cpuplugd_debug("the minimum. ");
cpuplugd_exit("Aborting.\n");
}
}
/*
* Check if the required settings are found in the configuration file.
* "Autodetect" if cpu and/or memory hotplug configuration entries
@@ -211,7 +250,6 @@ void parse_configfile(char *file)
*/
void check_config()
{
int cpuid;
int lpar_status;
lpar_status = check_lpar();
@@ -262,60 +300,23 @@ void check_config()
/*
* Save the number of online cpus and the cmm_pagesize at startup,
* so that we can enable exactly the same amount when the daemon ends
*
* Don't adjust cpus if system is on vertical polarization
*/
if (cpu) {
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below "
"the minimum and will be increased.\n");
cpuid = 0;
while (get_num_online_cpus() < cfg.cpu_min &&
cpuid < get_numcpus()) {
if (is_online(cpuid) == 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpuid);
hotplug(cpuid);
cpuid++;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum"
" and will be decreased.\n");
cpuid = 0;
while (get_num_online_cpus() > cfg.cpu_max &&
cpuid < get_numcpus()) {
if (is_online(cpuid) != 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpuid);
hotunplug(cpuid);
cpuid++;
}
}
if (cfg.cpu_min > get_numcpus())
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_exit("The minimum amount of cpus is above "
"the number of available cpus.\n"
"Detected %d available cpus\n",
get_numcpus());
if (get_num_online_cpus() < cfg.cpu_min)
cpuplugd_exit("Failed to set the number of online "
"cpus to the minimum. Aborting.\n");
saved_polarization = get_polarization();
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
if (saved_polarization < 0) {
cpuplugd_debug("Daemon couldn't determine system polarization\n");
cpuplugd_debug("Starting without evaluating cpu rules\n");
} else if (saved_polarization == PLR_VERTICAL) {
cpuplugd_debug("Daemon started with vertical polarization.\n");
cpuplugd_debug("Cpu adjustments won't be made until system ");
cpuplugd_debug("is in horizontal polarization\n");
} else if (saved_polarization == PLR_HORIZONTAL &&
cpu == 1) {
apply_cpu_config();
}
if (memory == 1) {
/*

View File

@@ -12,217 +12,241 @@
#include <limits.h>
#include "cpuplugd.h"
#define NUM_BASE (10)
#define CPU_OFFLINE (0)
#define CPU_ONLINE (1)
#define CPU_DECONFIGURED (0)
#define CPU_CONFIGURED (1)
#define CPU_LIST_LEN (4096)
/*
* Return overall number of available cpus. This does not necessarily
* mean that those are currently online
*/
int get_numcpus()
static int get_sysfs_attribute_cpu_count(char *path)
{
int i;
char path[PATH_MAX];
int number = 0;
char cpu_list[CPU_LIST_LEN];
int number, start, end;
char *sub_list;
for (i = 0; ; i++) {
/* check whether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
if (access(path, R_OK) == 0)
if (util_file_read_line(cpu_list, sizeof(cpu_list), path))
cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno));
number = 0;
sub_list = strtok(cpu_list, ",");
while (sub_list) {
if (strchr(sub_list, '-')) {
if (sscanf(sub_list, "%d-%d", &start, &end) != 2)
cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list);
number += (end - start) + 1;
} else {
number++;
else
break;
}
sub_list = strtok(NULL, ",");
}
return number;
}
/*
* Return number of online cpus
* get_numcpus() - return number of present cpus by sysfs'
* cpu/present attribute.
* This number represents the total number of usable cpus,
* this includes offline or deconfigured cpus as well.
*/
int get_num_online_cpus()
int get_numcpus(void)
{
FILE *filp;
int i;
char path[PATH_MAX];
int status = 0;
int value_of_onlinefile, rc;
int number;
char *path;
for (i = 0; i < get_numcpus(); i++) {
/* check wether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
if (access(path, R_OK) != 0) {
status++;
continue;
}
filp = fopen(path, "r");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: "
"%s\n", strerror(errno));
else {
rc = fscanf(filp, "%d", &value_of_onlinefile);
if (rc != 1)
cpuplugd_exit("Cannot read cpu online file: "
"%s\n", strerror(errno));
if (value_of_onlinefile == 1)
status++;
}
fclose(filp);
path = util_path_sysfs("devices/system/cpu/present");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of present cpus (%d) <= 0\n", number);
return number;
}
/*
* get_num_online_cpus() - return number of online cpus
* by parsing sysfs cpu/online attribute
*/
int get_num_online_cpus(void)
{
int number;
char *path;
path = util_path_sysfs("devices/system/cpu/online");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of online cpus (%d) <= 0\n", number);
return number;
}
/*
* get_polarization() - return system polarization
*/
int get_polarization(void)
{
int polarization;
char *path;
path = util_path_sysfs("devices/system/cpu/dispatching");
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
polarization = -1;
cpuplugd_debug("failed to read system polarization\n");
}
free(path);
return polarization;
}
/*
* is_cpu_hotpluggable() - check if cpuhotplug operations are supported
* for the given cpu.
*/
static int is_cpu_hotpluggable(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_path_exists(path);
free(path);
return rc;
}
/*
* hotplug() - perform cpu hotplug on given cpuid
*/
static int hotplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to enable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* hotunplug() - perform cpu hotunplug on given cpuid
*/
static int hotunplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to disable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* get_cpu_attribute() - get a certain cpu's selected attribute
*/
static int get_cpu_attribute(int cpuid, char *attribute)
{
int status;
char *path;
path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute);
if (util_file_read_i(&status, NUM_BASE, path) < 0) {
status = -1;
cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid);
}
free(path);
return status;
}
/*
* Enable a certain cpu
* hotplug_one_cpu() - perform hotplugging on the first available cpu
*/
int hotplug(int cpuid)
int hotplug_one_cpu(void)
{
FILE *filp;
char path[PATH_MAX];
int status, rc;
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fprintf(filp, "1");
fclose(filp);
/*
* check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &status);
if (rc != 1)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fclose(filp);
if (status == 1) {
cpuplugd_debug("cpu with id %d enabled\n", cpuid);
return 1;
} else {
cpuplugd_debug("failed to enable cpu with id %d\n",
cpuid);
return -1;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) {
cpuplugd_debug("cpu%d will be enabled", cpuid);
rc = hotplug(cpuid);
}
}
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
return -1;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Disable a certain cpu
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
*/
int hotunplug(int cpuid)
int hotunplug_one_cpu(void)
{
FILE *filp;
int state, rc;
int retval = -1;
char path[PATH_MAX];
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
state = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
fprintf(filp, "0");
fclose(filp);
/*
* Check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc != 1)
cpuplugd_error("Failed to disable cpu with id %d\n",
cpuid);
fclose(filp);
if (state == 0)
return 1;
}
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
return retval;
}
/*
* Check if a certain cpu is currently online
*/
int is_online(int cpuid)
{
FILE *filp;
int state;
int retval, rc;
char path[PATH_MAX];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) {
cpuplugd_debug("cpu%d will be disabled\n", cpuid);
rc = hotunplug(cpuid);
}
fclose(filp);
} else {
retval = 1;
}
return retval;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
*/
void reactivate_cpus()
void reactivate_cpus(void)
{
/*
* Only enable the number of cpus which where
* available at daemon startup time
*/
int cpuid, nc;
struct dirent **cpu_dir;
int cpuid, nc, count, i;
char *path;
cpuid = 0;
/* suppress verbose messages on exit */
debug = 0;
/*
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
/*
* Only enable the number of cpus which where available at
* daemon startup time by checking num_cpu_start.
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
if (num_cpu_start == 0)
return;
while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) {
nc = 0;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (nc != num_cpu_start); i++) {
nc = get_num_online_cpus();
if (nc == num_cpu_start)
return;
if (nc > num_cpu_start && is_online(cpuid) == 1)
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (nc > num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_ONLINE)
hotunplug(cpuid);
if (nc < num_cpu_start && is_online(cpuid) == 0)
if (nc < num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
hotplug(cpuid);
cpuid++;
}
util_scandir_free(cpu_dir, count);
free(path);
}
/*
* In kernels > 2.6.24 cpus can be deconfigured. The following functions is used
* to check if a certain cpus is in a deconfigured state.
*/
int cpu_is_configured(int cpuid)
{
FILE *filp;
int retval, state, rc;
char path[4096];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
}
fclose(filp);
}
return retval;
}

View File

@@ -23,6 +23,9 @@
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_path.h"
#include "lib/util_file.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#define NAME "cpuplugd"
@@ -35,6 +38,8 @@
#define MAX_VARNAME 128
#define MAX_LINESIZE 2048
#define CPUSTATS 10
#define PLR_HORIZONTAL 0
#define PLR_VERTICAL 1
/*
* Precedence of C operators
@@ -173,9 +178,11 @@ extern unsigned int history_max;
extern unsigned int history_current;
extern struct symbol_names sym_names[];
extern unsigned int sym_names_count;
extern int saved_polarization;
int get_numcpus();
int get_num_online_cpus();
int get_polarization(void);
void get_loadavg_runnable(double *loadavg, double *runnable);
void clean_up();
void reactivate_cpus();
@@ -190,9 +197,8 @@ void proc_cpu_read(char *procinfo);
unsigned long proc_read_size(char *path);
char *get_var_rvalue(char *var_name);
void cleanup_cmm(void);
int hotplug(int cpuid);
int hotunplug(int cpuid);
int is_online(int cpuid);
int hotplug_one_cpu(void);
int hotunplug_one_cpu(void);
long get_cmmpages_size();
void parse_options(int argc, char **argv);
void check_if_started_twice();
@@ -202,9 +208,9 @@ void reload_daemon(void);
int daemonize(void);
int check_cmmfiles(void);
void check_config();
void apply_cpu_config(void);
void set_cmm_pages(long size);
int check_lpar();
int cpu_is_configured(int cpuid);
void setup_history(void);

View File

@@ -149,6 +149,8 @@ void clean_up()
cpuplugd_info("terminated\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();
@@ -163,6 +165,8 @@ void kill_daemon(int UNUSED(a))
cpuplugd_info("shutting down\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();

View File

@@ -54,12 +54,12 @@ struct config cfg = {
.hotunplug = NULL,
};
int num_cpu_start, memory, cpu, reload_pending;
long cmm_pagesize_start;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
char *meminfo, *vmstat, *cpustat, *varinfo;
double *timestamps;
unsigned int history_max, history_current, history_prev, sym_names_count;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
int num_cpu_start, memory, cpu, reload_pending, saved_polarization;
char *meminfo, *vmstat, *cpustat, *varinfo;
long cmm_pagesize_start;
double *timestamps;
static struct symbols symbols;
static jmp_buf jmpenv;
@@ -77,8 +77,29 @@ static void eval_cpu_rules(void)
{
double diffs[CPUSTATS], diffs_total, percent_factor;
char *procinfo_current, *procinfo_prev;
int cpu, nr_cpus, on_off;
int nr_cpus, on_off, polarization;
polarization = get_polarization();
if (polarization < 0) {
cpuplugd_debug("couldn't determine system polarization\n");
cpuplugd_debug("skipping cpu rule evaluation\n");
return;
}
if (saved_polarization != polarization) {
saved_polarization = polarization;
if (polarization == PLR_VERTICAL) {
/* revert cpu hotplug adjustments after switching from horizontal */
reactivate_cpus();
} else if (polarization == PLR_HORIZONTAL) {
/* reapply cpu config after switching from vertical */
apply_cpu_config();
}
}
if (polarization == PLR_VERTICAL) {
cpuplugd_debug("system is running vertical polarization\n");
cpuplugd_debug("cpuplugd won't make cpu adjustments\n");
return;
}
nr_cpus = get_numcpus();
procinfo_current = cpustat + history_current * cpustat_size;
procinfo_prev = cpustat + history_prev * cpustat_size;
@@ -157,7 +178,6 @@ static void eval_cpu_rules(void)
printf("\n");
printf("---------------------------------------------\n");
}
on_off = 0;
/* Evaluate the hotplug rule */
if (eval_term(cfg.hotplug, &symbols))
@@ -172,40 +192,16 @@ static void eval_cpu_rules(void)
cpuplugd_debug("maximum cpu limit is reached\n");
return;
}
/* try to find a offline cpu */
for (cpu = 0; cpu < nr_cpus; cpu++)
if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
break;
if (cpu < nr_cpus) {
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpu);
if (hotplug(cpu) == -1)
cpuplugd_debug("unable to find a cpu which "
"can be enabled\n");
} else {
/*
* In case we tried to enable a cpu but this failed.
* This is the case if a cpu is deconfigured
*/
cpuplugd_debug("unable to find a cpu which can "
"be enabled\n");
}
if (hotplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be enabled\n");
} else if (on_off < 0) {
/* check cpu nr limit */
if (symbols.onumcpus <= cfg.cpu_min) {
cpuplugd_debug("minimum cpu limit is reached\n");
return;
}
/* try to find a online cpu */
for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
if (is_online(cpu) != 0)
break;
}
if (cpu > 0) {
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpu);
hotunplug(cpu);
}
if (hotunplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be disabled\n");
}
}

View File

@@ -22,6 +22,9 @@ of active CPUs are reset to the values they had before the cpuplugd was started.
This program can be used to control the number of CPUs for Linux on z/VM
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
to Linux on z/VM only.
The cpuplugd daemon stops any CPU hot-plug operations when the system switches
to vertical polarization, thus avoiding possible performance penalties.
.
.SH OPTIONS
.TP

View File

@@ -7,11 +7,11 @@
dasdfmt \- formatting of DASD (ECKD) disk drives.
.SH SYNOPSIS
\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-P] [-m \fIstep\fR]
\fBdasdfmt\fR [\-h] [\-t] [\-v] [\-y] [\-p] [\-P] [\-m \fIstep\fR]
.br
[-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR]
[\-r \fIcylinder\fR] [\-b \fIblksize\fR] [\-l \fIvolser\fR] [\-d \fIlayout\fR]
.br
[-L] [-V] [-F] [-k] [-C] [-M \fImode\fR] \fIdevice\fR
[\-L] [\-V] [\-F] [\-k] [\-C] [\-M \fImode\fR] \fIdevice\fR
.SH DESCRIPTION
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
@@ -26,26 +26,26 @@ Any device node created by udev for kernel 2.6 can be used
.SH OPTIONS
.TP
\fB-h\fR or \fB--help\fR
\fB\-h\fR or \fB\-\-help\fR
Print usage and exit.
.TP
\fB-t\fR or \fB--test\fR
\fB\-t\fR or \fB\-\-test\fR
Disables any modification of the disk drive.
.br
\fBdasdfmt\fR just prints
out, what it \fBwould\fR do.
.TP
\fB-v\fR
\fB\-v\fR
Increases verbosity.
.TP
\fB-y\fR
\fB\-y\fR
Start formatting without further user-confirmation.
.TP
\fB--norecordzero\fR
\fB\-\-norecordzero\fR
Remove permission for subsystem to format write record zero.
.br
This is an expert option: Per default in recent dasd drivers, subsystems are
@@ -54,32 +54,32 @@ to remove this permission.
.br
.TP
\fB-L\fR or \fB--no_label\fR
\fB\-L\fR or \fB\-\-no_label\fR
Omit the writing of a disk label after formatting.
.br
This makes only sense for the 'ldl' disk layout.
.br
The '-L' option has to be specified after the '-d ldl' option.
The '\-L' option has to be specified after the '\-d ldl' option.
.br
e.g. dasdfmt -d ldl -L /dev/...
e.g. dasdfmt \-d ldl \-L /dev/...
.TP
\fB-V\fR or \fB--version\fR
\fB\-V\fR or \fB\-\-version\fR
Print version number and exit.
.TP
\fB-F\fR or \fB--force\fR
\fB\-F\fR or \fB\-\-force\fR
Formats the device without performing sanity checking.
.TP
\fB-C\fR or \fB--check_host_count\fR
\fB\-C\fR or \fB\-\-check_host_count\fR
Force dasdfmt to check the host access open count to ensure the device
is not online on another operating system instance
.TP
\fB-d\fR \fIlayout\fR or \fB--disk_layout\fR=\fIlayout\fR
\fB\-d\fR \fIlayout\fR or \fB\-\-disk_layout\fR=\fIlayout\fR
Formats the device with compatible disk layout or linux disk layout.
\fIlayout\fR is either \fIcdl\fR for the compatible disk layout
(default) or \fIldl\fR for the linux disk layout.
@@ -95,39 +95,39 @@ Do not use this option if you are using a 3270 console,
running in background or redirecting the output to a file.
.TP
\fB-P\fR or \fB--percentage\fR
\fB\-P\fR or \fB\-\-percentage\fR
Print one line for each formatted cylinder showing the number of the
cylinder and percentage of formatting process.
Intended to be used by higher level interfaces.
.TP
\fB-m\fR \fIstep\fR or \fB--hashmarks\fR=\fIstep\fR
\fB\-m\fR \fIstep\fR or \fB\-\-hashmarks\fR=\fIstep\fR
Print a hashmark every \fIstep\fR cylinders. The value \fIstep\fR has to be within range [1,1000], otherwise it will be set to the default, which is 10.
.br
You can use this option to see the progress of formatting in case you
are not able to use the progress bar option -p, e.g. with a 3270
are not able to use the progress bar option \-p, e.g. with a 3270
terminal.
.br
The value will be at least as big as the -r or --requestsize value.
The value will be at least as big as the \-r or \-\-requestsize value.
.br
.TP
\fB-M\fR \fImode\fR or \fB--mode\fR=\fImode\fR
\fB\-M\fR \fImode\fR or \fB\-\-mode\fR=\fImode\fR
Specify the \fImode\fR to be used to format the device. Valid modes are:
.RS
.IP full
Format the entire disk with the specified blocksize. (default)
.IP quick
Format the first two tracks and write label and partition information. Use this
option only if you are sure that the target DASD already contains a regular
format with the specified blocksize. A blocksize can optionally be specified
using \fB-b\fR (\fB--blocksize\fR).
Format the first two tracks and write label and partition information.
.br
For thin-provisioned DASD ESE volumes, quick is the default mode. A full space
release then precedes the formatting step. If this space release fails, dasdfmt
falls back to a full-format mode. Formatting stops if the space release fails
and quick mode was specified explicitly using \fB-M\fR. Specify the
\fB--no-discard\fR option to omit the space release.
Use this option for DASD ESE volumes to take the benefits of thin provisioning.
In this case, a full space release precedes the formatting step. If this space
release fails, then the formatting also fails. Specify the \fB\-\-no\-discard\fR
option to omit the space release.
.br
For non-ESE volumes use this option only if you are sure that the target DASD
already contains a regular format with the specified blocksize. A blocksize can
optionally be specified using \fB\-b\fR (\fB\-\-blocksize\fR).
.IP expand
Format all unformatted tracks at the end of the target DASD. This mode assumes
@@ -135,20 +135,20 @@ that tracks at the beginning of the DASD volume have already been correctly
formatted, while a consecutive set of tracks at the end are unformatted. You can
use this mode to make added space available for Linux use after dynamically
increasing the size of a DASD volume. A blocksize can optionally be specified
using \fB-b\fR (\fB--blocksize\fR).
using \fB\-b\fR (\fB\-\-blocksize\fR).
.RE
.TP
\fB--check\fR
\fB\-\-check\fR
Perform a complete format check on a DASD volume. A blocksize can be specified
with \fB-b\fR (\fB--blocksize\fR).
with \fB\-b\fR (\fB\-\-blocksize\fR).
.TP
\fB--no-discard\fR
\fB\-\-no\-discard\fR
Omit a full space release when formatting a thin-provisioned DASD ESE volume.
.TP
\fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR
\fB\-r\fR \fIcylindercount\fR or \fB\-\-requestsize\fR=\fIcylindercount\fR
Number of cylinders to be processed in one formatting step.
The value must be an integer in the range 1 - 255.
.br
@@ -158,19 +158,19 @@ devices, counting the base device and all alias devices.
.br
.TP
\fB-b\fR \fIblksize\fR or \fB--blocksize\fR=\fIblksize\fR
\fB\-b\fR \fIblksize\fR or \fB\-\-blocksize\fR=\fIblksize\fR
Specify blocksize to be used. \fIblksize\fR must be a positive integer
and always be a power of two. The recommended blocksize is 4096 bytes.
.TP
\fB-l\fR \fIvolser\fR or \fB--label\fR=\fIvolser\fR
\fB\-l\fR \fIvolser\fR or \fB\-\-label\fR=\fIvolser\fR
Specify the volume serial number or volume identifier to be written
to disk after formatting. If no label is specified, a sensible default
is used. \fIvolser\fR is interpreted as ASCII string and is automatically
converted to uppercase and then to EBCDIC.
.br
e.g. -l LNX001 or --label=DASD01
e.g. \-l LNX001 or \-\-label=DASD01
.br
The \fIvolser\fR identifies by serial number the volume. A volume serial
@@ -192,11 +192,11 @@ NOTE: Try to avoid using special characters in the volume serial. This may cause
In case you really have to use special characters, make sure you are using quotes. In addition there is a special handling for the '$' sign. Please specify it using '\\$' if necessary.
.br
e.g. -l 'a@b\\$c#' to get A@B$C#
e.g. \-l 'a@b\\$c#' to get A@B$C#
.br
.TP
\fB-k\fR or \fB--keep_volser\fR
\fB\-k\fR or \fB\-\-keep_volser\fR
Keeps the Volume Serial Number when writing the Volume Label. This is useful if
the volume already has a Serial Number that should not be overwritten.
.br

View File

@@ -1230,7 +1230,7 @@ static void dasdfmt_find_start(unsigned int cylinders, unsigned int heads,
format_params->start_unit = first;
}
static int dasdfmt_release_space(void)
static void dasdfmt_release_space(void)
{
format_data_t r = {
.start_unit = 0,
@@ -1240,21 +1240,12 @@ static int dasdfmt_release_space(void)
int err = 0;
if (!g.ese || g.no_discard)
return 0;
return;
printf("Releasing space for the entire device...\n");
err = dasd_release_space(g.dev_node, &r);
/*
* Warn or Error on failing RAS depending on QUICK mode set explicitly or automatically
*/
if (err && !g.mode_specified) {
warnx("Could not release space. Falling back to full format.");
return 1;
} else if (err && g.mode_specified) {
if (err)
error("Could not release space: %s", strerror(err));
}
return 0;
}
static void dasdfmt_prepare_and_format(unsigned int cylinders, unsigned int heads,
@@ -1454,12 +1445,8 @@ static void do_format_dasd(volume_label_t *vlabel, format_data_t *p,
dasdfmt_prepare_and_format(cylinders, heads, p);
break;
case QUICK:
if (dasdfmt_release_space()) {
p->stop_unit = (cylinders * heads) - 1;
dasdfmt_prepare_and_format(cylinders, heads, p);
} else {
dasdfmt_quick_format(cylinders, heads, p);
}
dasdfmt_release_space();
dasdfmt_quick_format(cylinders, heads, p);
break;
case EXPAND:
dasdfmt_expand_format(cylinders, heads, p);
@@ -1491,7 +1478,7 @@ static void eval_format_mode(void)
}
if (!g.mode_specified)
mode = g.ese ? QUICK : FULL;
mode = FULL;
}
/*

View File

@@ -7,28 +7,28 @@
.B "dasdinfo "
\- tool to read unique id from s390 DASD device
.SH SYNOPSIS
.BI "dasdinfo [-a] [-l] [-u] [-x] [-e] {-i " <busid>
.BI "| -b " <blockdev>
.BI " | -d " <devnode>
.BI "dasdinfo [\-a] [\-l] [\-u] [\-x] [\-e] {\-i " <busid>
.BI "| \-b " <blockdev>
.BI " | \-d " <devnode>
.BI "}"
.sp
.BI "dasdinfo [-h] [-v]"
.BI "dasdinfo [\-h] [\-v]"
.SH DESCRIPTION
.B dasdinfo
.B dasdinfo
displays specific information about a specified DASD device.
It is normally called from a udev rule, to provide udev with a unique id string and
additional information (type, serial) for an S390 DASD drive. Udev can use this
information to create symlinks in /dev/disk/by-id and /dev/disk/by-label
information to create symlinks in /dev/disk/by\-id and /dev/disk/by\-label
to the real device node.
.SH OPTIONS
.TP
.BI "-a|--all"
.BI "\-a|\-\-all"
Same as -u -x -l
.TP
.BI "-x|--extended-uid"
.BI "\-x|\-\-extended\-uid"
Print DASD uid
This option prints the full uid of the DASD. When z/VM provides two
@@ -42,13 +42,13 @@ For z/VM: VM support for the hypervisor injected Special Node Element
Qualifier (SNEQ) (or hypervisor injected self-description data) is
available by applying the PTFs for VM APAR VM64273 on z/VM 5.2.0 and higher.
.TP
.BI "-u|--uid"
.BI "\-u|\-\-uid"
Print DASD uid without z/VM minidisk token
z/VM may provide an additional token that can be used to distinguish
between different minidisks (see --extended-uid option). To remain
between different minidisks (see \-\-extended\-uid option). To remain
compatible with systems that were installed on older Linux or z/VM
levels, the -u option will print the uid excluding any z/VM-provided
levels, the \-u option will print the uid excluding any z/VM-provided
minidisk token.
For example, if the extended uid is
@@ -57,35 +57,35 @@ uid is IBM.75000000092461.e900.10. If the extended uid contains no
minidisk token, e.g. in an LPAR environment, then both uids are the
same.
.TP
.BI "-l|--label"
.BI "\-l|\-\-label"
Print DASD volume label (volser).
.TP
.BI "-i|--busid " <busid>
.BI "\-i|\-\-busid " <busid>
Use the bus ID as input parameter, e.g. 0.0.e910.
.TP
.BI "-b|--block " <blockdev>
.BI "\-b|\-\-block " <blockdev>
Use the block device name as input parameter, e.g. dasdb.
.TP
.BI "-d|--devnode " <devnode>
.BI "\-d|\-\-devnode " <devnode>
Use a device node as input parameter, e.g. /dev/dasdb.
.TP
.BI "-e|--export"
.BI "\-e|\-\-export"
Print all values (ID_BUS, ID_TYPE, ID_SERIAL).
.TP
.BI "-h|--help"
.BI "\-h|\-\-help"
Print usage text.
.TP
.BI "-v|--version"
.BI "\-v|\-\-version"
Print version number.
.SH EXAMPLES
dasdinfo -u -i 0.0.e910
dasdinfo \-u \-i 0.0.e910
dasdinfo -u -b dasdb
dasdinfo \-u \-b dasdb
dasdinfo -u -d /dev/dasdb
dasdinfo \-u \-d /dev/dasdb
All three examples should return the same unique ID for
All three examples should return the same unique ID for
the same DASD device, e.g. IBM.75000000092461.e900.10.
In case this uid is not available, dasdinfo will return

View File

@@ -7,21 +7,21 @@
dasdview \- Display DASD and VTOC information and dump the content of a DASD
to the console.
.SH SYNOPSIS
\fBdasdview\fR [-h] [-v]
\fBdasdview\fR [\-h] [\-v]
.br
[-b \fIbegin\fR] [-s \fIsize\fR] [-1|-2]
[\-b \fIbegin\fR] [\-s \fIsize\fR] [\-1|\-2]
.br
[-i] [-x] [-j] [-c]
[\-i] [\-x] [\-j] [\-c]
.br
[-l] [-t {\fIinfo\fR|\fIf1\fR|\fIf3\fR|\fIf4\fR|\fIf5\fR|\fIf7\fR|\fIf8\fR|\fIf9\fR}]
[\-l] [\-t {\fIinfo\fR|\fIf1\fR|\fIf3\fR|\fIf4\fR|\fIf5\fR|\fIf7\fR|\fIf8\fR|\fIf9\fR}]
.br
\fIdevice\fR
.SH DESCRIPTION
\fBdasdview\fR prints you some useful information of your disks to the console.
You can display a disk dump by specifying start point and offset and you can
You can display a disk dump by specifying start point and offset and you can
print the volume label and VTOC entries.
The \fIdevice\fR is the node of the device (e.g. '/dev/dasda').
Any device node created by udev for kernel 2.6 can be used
Any device node created by udev for kernel 2.6 can be used
(e.g. '/dev/dasd/0.0.b100/disc').
DASD devices in raw_track_access mode are supported and detected
@@ -29,30 +29,30 @@ automatically. When in raw_track_access mode, the same basic
functions are available as in the regular mode, but the output may
have a slightly different layout:
.IP \(bu 2
The disk dump functions (\fB-b\fR and \fB-s\fR) print the count,
The disk dump functions (\fB\-b\fR and \fB\-s\fR) print the count,
key and data information for the whole track, and not just the
contents of the data areas.
.IP \(bu 2
The VTOC listing (\fB-t\fR) print all specified DSCBs in the same
The VTOC listing (\fB\-t\fR) print all specified DSCBs in the same
format as in the regular mode, but in the sequence as they appear in
the VTOC. The \fB-t info\fR overview contains more details for each
the VTOC. The \fB\-t info\fR overview contains more details for each
data set than in the regular mode, to support the larger variety of
data set layouts.
.SH OPTIONS
.TP
\fB-h\fR or \fB--help\fR
\fB\-h\fR or \fB\-\-help\fR
Print usage and exit.
.TP
\fB-v\fR or \fB--version\fR
\fB\-v\fR or \fB\-\-version\fR
Print version number and exit.
.TP
\fB-b\fR \fIbegin\fR or \fB--begin=\fR\fIbegin\fR
Print a disk dump to the console, starting with \fIbegin\fR. The content of
the disk will be displayed in hexadecimal numbers, ASCII text and EBCDIC text.
If no size is specified dasdview will take the default size. The variable
\fB\-b\fR \fIbegin\fR or \fB\-\-begin=\fR\fIbegin\fR
Print a disk dump to the console, starting with \fIbegin\fR. The content of
the disk will be displayed in hexadecimal numbers, ASCII text and EBCDIC text.
If no size is specified dasdview will take the default size. The variable
\fIbegin\fR can be specified in one of the following ways:
.br
@@ -63,10 +63,10 @@ The default for \fIbegin\fR is \fI0\fR.
.br
\fBNote 1:\fR dasdview will show you the content of your disk using the DASD
driver. If this driver decides to hide or add some parts of the disk, you have
to live with it. This happens for example with the first two tracks of a
cdl-formatted disk. In this case the DASD driver fills up shorter blocks with
zeros to have a constant blocksize. And all applications, including dasdview,
driver. If this driver decides to hide or add some parts of the disk, you have
to live with it. This happens for example with the first two tracks of a
cdl-formatted disk. In this case the DASD driver fills up shorter blocks with
zeros to have a constant blocksize. And all applications, including dasdview,
believe it.
.br
\fBNote 2:\fR In raw_track_access mode \fIbegin\fR must be aligned to
@@ -76,24 +76,24 @@ cylinder as starting point.
examples:
.br
-b 32 --> start printing at Byte 32
\-b 32 --> start printing at Byte 32
.br
-b 32k --> start printing at kByte 32
\-b 32k --> start printing at kByte 32
.br
-b 32m --> start printing at MByte 32
\-b 32m --> start printing at MByte 32
.br
-b 32b --> start printing at block 32
\-b 32b --> start printing at block 32
.br
-b 32t --> start printing at track 32
\-b 32t --> start printing at track 32
.br
-b 32c --> start printing at cylinder 32
\-b 32c --> start printing at cylinder 32
.TP
\fB-s\fR \fIsize\fR or \fB--size=\fR\fIsize\fR
Print a disk dump to the console, starting with \fIbegin\fR, specified with
the \fB-b\fR option and size \fIsize\fR. The content of the disk will be
displayed in hexadecimal numbers, ASCII text and EBCDIC text. If no start
value is specified dasdview will take the default start value. The variable
\fB\-s\fR \fIsize\fR or \fB\-\-size=\fR\fIsize\fR
Print a disk dump to the console, starting with \fIbegin\fR, specified with
the \fB\-b\fR option and size \fIsize\fR. The content of the disk will be
displayed in hexadecimal numbers, ASCII text and EBCDIC text. If no start
value is specified dasdview will take the default start value. The variable
\fIsize\fR can be specified in one of the following ways:
.br
@@ -111,76 +111,76 @@ in raw_track_access mode.
examples:
.br
-s 16 --> use a 16 Byte size
\-s 16 --> use a 16 Byte size
.br
-s 16k --> use a 16 kByte size
\-s 16k --> use a 16 kByte size
.br
-s 16m --> use a 16 MByte size
\-s 16m --> use a 16 MByte size
.br
-s 16b --> use a 16 block size
\-s 16b --> use a 16 block size
.br
-s 16t --> use a 16 track size
\-s 16t --> use a 16 track size
.br
-s 16c --> use a 16 cylinder size
\-s 16c --> use a 16 cylinder size
.TP
\fB-1\fR
This option tells dasdview to print the disk dump using format 1. This means
you will get 16 Bytes per line in hex, ascii and ebcdic. There is no line
\fB\-1\fR
This option tells dasdview to print the disk dump using format 1. This means
you will get 16 Bytes per line in hex, ascii and ebcdic. There is no line
number.
.br
The \fB-1\fR option makes only sense with the \fB-b\fR and/or the \fB-s\fR
options.
The \fB\-1\fR option makes only sense with the \fB\-b\fR and/or the \fB\-s\fR
options.
.br
This is the default.
.TP
\fB-2\fR
This option tells dasdview to print the disk dump using format 2. This means
you will get 8 Bytes per line in hex, ascii and ebcdic. And in addition a line
\fB\-2\fR
This option tells dasdview to print the disk dump using format 2. This means
you will get 8 Bytes per line in hex, ascii and ebcdic. And in addition a line
number and a decimal and hexadecimal byte count will be printed.
.br
The \fB-2\fR option makes only sense with the \fB-b\fR and/or the \fB-s\fR
The \fB\-2\fR option makes only sense with the \fB\-b\fR and/or the \fB\-s\fR
options. In raw_track_access mode this format is not supported and the
option will be ignored.
.TP
\fB-i\fR or \fB--info\fR
\fB\-i\fR or \fB\-\-info\fR
Print some useful information (e.g. device node/number/type or geometry data).
When running dasdview on a kernel 2.6 based distribution the busid
When running dasdview on a kernel 2.6 based distribution the busid
is printed instead of the device number.
.TP
\fB-x\fR or \fB--extended\fR
\fB\-x\fR or \fB\-\-extended\fR
Print some more DASD information (e.g. open count, subchannel identifier).
.TP
\fB-j\fR or \fB--volser\fR
\fB\-j\fR or \fB\-\-volser\fR
Print volume serial number (volume identifier).
.TP
\fB-l\fR or \fB--label\fR
\fB\-l\fR or \fB\-\-label\fR
Print the volume label.
.TP
\fB-c\fR or \fB--characteristic\fR
\fB\-c\fR or \fB\-\-characteristic\fR
Print some information about the device e.g. if it is encrypted.
.TP
\fB-t\fR \fIspec\fR or \fB--vtoc=\fR\fIspec\fR
\fB\-t\fR \fIspec\fR or \fB\-\-vtoc=\fR\fIspec\fR
Print the VTOC (table of content) or single VTOC entries to the console.
\fIspec\fR can be one of the following strings:
.br
\fIinfo\fR:
\fIinfo\fR:
.br
Gives you a VTOC overview. You will see what other S/390 or zSeries operating
Gives you a VTOC overview. You will see what other S/390 or zSeries operating
systems would see (e.g. data set names and sizes).
.br
\fIf1\fR:
.br
Print the content of all format 1 DSCBs.
Print the content of all format 1 DSCBs.
.br
\fIf3\fR:
@@ -188,17 +188,17 @@ Print the content of all format 1 DSCBs.
Print the content of all format 3 DSCBs.
.br
\fIf4\fR:
\fIf4\fR:
.br
Print the content of the format 4 DSCB.
.br
\fIf5\fR:
\fIf5\fR:
.br
Print the content of the format 5 DSCB.
.br
\fIf7\fR:
\fIf7\fR:
.br
Print the content of the format 7 DSCB.
.br
@@ -213,6 +213,6 @@ Print the content of all format 8 DSCBs.
Print the content of all format 9 DSCBs.
.br
\fIall\fR:
\fIall\fR:
.br
Print the content of all DSCBs.
Print the content of all DSCBs.

View File

@@ -28,6 +28,15 @@
# DEVICE=0.0.4e13
# DELAY_MINUTES=5
#
# Dump on ECKD device (DASD)
#
# ON_PANIC=dump
# DUMP_TYPE=eckd
# DEVICE=0.0.1004
# BOOTPROG=0
# BR_CHR=auto
#
# Dump on fcp device (SCSI Disk)
#

View File

@@ -8,16 +8,16 @@ fdasd \- partitioning tool.
.SH SYNOPSIS
interactive mode:
.br
\fBfdasd\fR [-s] [-r] [-C] \fIdevice\fR
\fBfdasd\fR [\-s] [\-r] [\-C] \fIdevice\fR
.br
command line mode:
.br
\fBfdasd\fR [-s] [-r] [-C] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR}
\fBfdasd\fR [\-s] [\-r] [\-C] {\-a[\-k|\-l \fIvolser\fR]|\-i|\-p|\-c \fIconf_file\fR}
[-f \fI[type,blocksize]\fR] \fIdevice\fR
.br
help:
.br
\fBfdasd\fR {-h|-v}
\fBfdasd\fR {\-h|\-v}
.SH DESCRIPTION
\fBfdasd\fR writes a partition table to a cdl (compatible disk layout)
formatted DASD, in the form of
@@ -30,35 +30,35 @@ will use it, otherwise it asks to write a new one.
\fBfdasd\fR can result in loss of data.
.SH OPTIONS
.TP
\fB-h\fR or \fB--help\fR
\fB\-h\fR or \fB\-\-help\fR
Print usage information, then exit.
.TP
\fB-v\fR or \fB--version\fR
\fB\-v\fR or \fB\-\-version\fR
Print version information, then exit.
.TP
\fB-s\fR or \fB--silent\fR
\fB\-s\fR or \fB\-\-silent\fR
Suppress messages in non-interactive mode.
.TP
\fB-r\fR or \fB--verbose\fR
\fB\-r\fR or \fB\-\-verbose\fR
Provide more verbose output.
.TP
\fB-a\fR or \fB--auto\fR
\fB\-a\fR or \fB\-\-auto\fR
Automatically create a partition using the entire disk in non-interactive
mode.
.TP
\fB-k\fR or \fB--keep_volser\fR
\fB\-k\fR or \fB\-\-keep_volser\fR
Keeps the Volume Serial Number when writing the Volume Label.
.br
This is useful if the volume already has a Serial Number that should not be
overwritten. This option is only applicable in non-interactive mode.
.TP
\fB-l\fR \fIvolser\fR or \fB--label\fR \fIvolser\fR
\fB\-l\fR \fIvolser\fR or \fB\-\-label\fR \fIvolser\fR
Specify the volume serial.
.br
\fIvolser\fR is interpreted as ASCII string and is automatically converted to
@@ -82,14 +82,14 @@ quotes. In addition there is a special handling for the '$' sign.
Please specify it using '\\$' if necessary.
.br
e.g. -l 'a@b\\$c#' to get A@B$C#
e.g. \-l 'a@b\\$c#' to get A@B$C#
.br
Omitting this parameter causes fdasd to ask for it in case it is needed.
.br
.TP
\fB-c\fR \fIconf_file\fR or \fB--config\fR \fIconf_file\fR
\fB\-c\fR \fIconf_file\fR or \fB\-\-config\fR \fIconf_file\fR
Use this option to create multiple partitions according to
specifications in a configuration file, \fIconf_file\fR.
.br
@@ -124,37 +124,37 @@ partitions that use the entire disk:
.br
.TP
\fB-i\fR or \fB--volser\fR
\fB\-i\fR or \fB\-\-volser\fR
Print the volume serial, then exit.
.TP
\fB-p\fR or \fB--table\fR
\fB\-p\fR or \fB\-\-table\fR
Print partition table, then exit.
.br
In combination with the -s option fdasd will display a short version of the
In combination with the \-s option fdasd will display a short version of the
partition table.
.TP
\fB-C\fR or \fB--check_host_count\fR
\fB\-C\fR or \fB\-\-check_host_count\fR
Force fdasd to check the host access open count to ensure the device
is not online on another operating system instance
.TP
\fB-f\fR \fI[type,blocksize]\fR or \fB--force\fR \fI[type,blocksize]\fR
\fB\-f\fR \fI[type,blocksize]\fR or \fB\-\-force\fR \fI[type,blocksize]\fR
Force fdasd to work on non DASD devices.
.br
If fdasd is to be used on a block device that is neither a native DASD
nor exposes the proper disk geometry of a DASD of type 3390,
then the --force option can be used to assume the geometry of a
then the \-\-force option can be used to assume the geometry of a
given device type. The default device type is 3390 and the default
block size is 4096. An optional argument of <device type>,<blocksize>
can be used to specify type and blocksize explicitly. For example:
-f
\-f
has the same effect as
-f3390,4096 or --force=3390,4096
\-f3390,4096 or \-\-force=3390,4096
Valid device types are: 3390, 3380, 9345
.br

View File

@@ -3,7 +3,7 @@ include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
PKGDATADIR := "$(TOOLS_DATADIR)/genprotimg"
TESTS :=
SUBDIRS := boot src man
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
@@ -11,8 +11,8 @@ RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
all: all-recursive
install: install-recursive
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(PKGDATADIR)"
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(DESTDIR)$(PKGDATADIR)"
clean: clean-recursive

View File

@@ -7,7 +7,7 @@ DEBUG_FILES := $(addsuffix .debug,$(FILES))
ifeq ($(HOST_ARCH),s390x)
ZIPL_DIR := $(rootdir)/zipl
ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot
PKGDATADIR := $(DESTDIR)$(TOOLS_DATADIR)/genprotimg
PKGDATADIR := $(TOOLS_DATADIR)/genprotimg
INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include
INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS))
@@ -86,9 +86,9 @@ stage3b.elf: head.o $(ZIPL_OBJS)
@chmod a-x $@
install: stage3a.bin stage3b_reloc.bin
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3a.bin "$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3b_reloc.bin "$(PKGDATADIR)"
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3a.bin "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 stage3b_reloc.bin "$(DESTDIR)$(PKGDATADIR)"
else
# Don't generate the dependency files (see `common.mak` for the

View File

@@ -93,5 +93,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -79,5 +79,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -15,5 +15,6 @@ SECTIONS
*(.eh_frame)
*(.interp)
*(.note.GNU-stack)
*(.note.package)
}
}

View File

@@ -4,7 +4,7 @@
#
# Sample script to verify that a host key document is genuine by
# verifying the issuer, the validity date and the signature.
# Optionally verify the full trust chain using a CA certficate.
# Optionally verify the full trust chain using a CA certificate.
#
# Sample invocation:
#
@@ -15,31 +15,33 @@
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
# Allocate temporary files
ISSUER_PUBKEY_FILE=$(mktemp)
SIGNATURE_FILE=$(mktemp)
BODY_FILE=$(mktemp)
ISSUER_DN_FILE=$(mktemp)
SUBJECT_DN_FILE=$(mktemp)
DEF_ISSUER_DN_FILE=$(mktemp)
DEF_ISSUER_ARMONK_DN_FILE=$(mktemp)
DEF_ISSUER_POUGHKEEPSIE_DN_FILE=$(mktemp)
CANONICAL_ISSUER_DN_FILE=$(mktemp)
CRL_SERIAL_FILE=$(mktemp)
# Cleanup on exit
cleanup()
{
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
rm -f "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" \
"$ISSUER_DN_FILE" "$SUBJECT_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" \
"$CANONICAL_ISSUER_DN_FILE" "$CRL_SERIAL_FILE"
}
trap cleanup EXIT
# Enhanced error checking for bash
if [ -n "${BASH}" ]
then
if [ -n "${BASH}" ]; then
# shellcheck disable=SC3040
set -o posix
# shellcheck disable=SC3040
set -o pipefail
# shellcheck disable=SC3040
set -o nounset
fi
set -e
@@ -47,8 +49,8 @@ set -e
# Usage
usage()
{
cat <<-EOF
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
cat <<-EOF
Usage: $(basename "$1") [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
Verify an IBM Secure Execution host key document against
a signing key.
@@ -71,8 +73,7 @@ check_verify_chain()
{
# Verify certificate chain in case a CA certificate file/bundle
# was specified on the command line.
if [ $# = 1 ]
then
if [ -z "$2" ]; then
cat >&2 <<-EOF
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
No CA certificate specified! Skipping trust chain verification.
@@ -80,37 +81,37 @@ Make sure that '$1' is a valid certificate.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
EOF
else
openssl verify -crl_download -crl_check $2 &&
openssl verify -crl_download -crl_check -untrusted $2 $1 ||
exit 1
openssl verify -crl_download -crl_check "$2" &&
openssl verify -crl_download -crl_check -untrusted "$2" "$1" ||
exit 1
fi
}
extract_pubkey()
{
openssl x509 -in $1 -pubkey -noout > $2
openssl x509 -in "$1" -pubkey -noout >"$2"
}
extract_signature()
{
# Assuming that the last field is the signature
SIGOFFSET=$(openssl asn1parse -in $1 | tail -1 | cut -d : -f 1)
SIGOFFSET=$(openssl asn1parse -in "$1" | tail -1 | cut -d : -f 1)
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
}
extract_body()
{
# Assuming that the first field is the full cert body
SIGOFFSET=$(openssl asn1parse -in $1 | head -2 | tail -1 | cut -d : -f 1)
SIGOFFSET=$(openssl asn1parse -in "$1" | head -2 | tail -1 | cut -d : -f 1)
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
openssl asn1parse -in "$1" -out "$2" -strparse "$SIGOFFSET" -noout
}
verify_signature()
{
# Assuming that the signature algorithm is SHA512 with RSA
openssl sha512 -verify $1 -signature $2 $3
openssl sha512 -verify "$1" -signature "$2" "$3"
}
canonical_dn()
@@ -120,18 +121,30 @@ canonical_dn()
DNTYPE=$3
OUTPUT=$4
openssl $OBJTYPE -in $OBJ -$DNTYPE -noout -nameopt multiline \
| sort | grep -v $DNTYPE= > $OUTPUT
openssl "$OBJTYPE" -in "$OBJ" -"$DNTYPE" -noout -nameopt multiline |
LC_ALL=C sort | grep -v "$DNTYPE"= >"$OUTPUT"
}
default_issuer()
default_issuer_armonk()
{
cat <<-EOF
commonName = International Business Machines Corporation
countryName = US
localityName = Armonk
organizationName = International Business Machines Corporation
organizationalUnitName = Key Signing Service
stateOrProvinceName = New York
EOF
}
default_issuer_pougkeepsie()
{
cat <<-EOF
commonName = International Business Machines Corporation
countryName = US
localityName = Poughkeepsie
organizationalUnitName = Key Signing Service
organizationName = International Business Machines Corporation
organizationalUnitName = Key Signing Service
stateOrProvinceName = New York
EOF
}
@@ -141,42 +154,37 @@ EOF
# stripping off the prefix
verify_default_issuer()
{
default_issuer > $DEF_ISSUER_DN_FILE
default_issuer_pougkeepsie >"$DEF_ISSUER_POUGHKEEPSIE_DN_FILE"
default_issuer_armonk >"$DEF_ISSUER_ARMONK_DN_FILE"
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
"$ISSUER_DN_FILE" >"$CANONICAL_ISSUER_DN_FILE"
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
then
if ! {
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_POUGHKEEPSIE_DN_FILE" ||
diff "$CANONICAL_ISSUER_DN_FILE" "$DEF_ISSUER_ARMONK_DN_FILE"
} >/dev/null 2>&1; then
echo Incorrect default issuer >&2 && exit 1
fi
}
verify_issuer_files()
{
if [ $1 -eq 1 ]
then
verify_default_issuer
fi
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
then
echo Issuer verification OK
else
echo Issuer verification failed >&2 && exit 1
if [ "$1" -eq 1 ]; then
verify_default_issuer
fi
}
cert_time()
{
DATE=$(openssl x509 -in $1 -$2 -noout | sed "s/^.*=//")
DATE=$(openssl x509 -in "$1" -"$2" -noout | sed "s/^.*=//")
date -d "$DATE" +%s
}
crl_time()
{
DATE=$(openssl crl -in $1 -$2 -noout | sed "s/^.*=//")
DATE=$(openssl crl -in "$1" -"$2" -noout | sed "s/^.*=//")
date -d "$DATE" +%s
}
@@ -188,8 +196,7 @@ verify_dates()
MSG="${3:-Certificate}"
NOW=$(date +%s)
if [ $START -le $NOW -a $NOW -le $END ]
then
if [ "$START" -le "$NOW" ] && [ "$NOW" -le "$END" ]; then
echo "${MSG} dates are OK"
else
echo "${MSG} date verification failed" >&2 && exit 1
@@ -198,22 +205,21 @@ verify_dates()
crl_serials()
{
openssl crl -in $1 -text -noout | \
grep "Serial Number" > $CRL_SERIAL_FILE
openssl crl -in "$1" -text -noout |
grep "Serial Number" >"$CRL_SERIAL_FILE"
}
check_serial()
{
CERT_SERIAL=$(openssl x509 -in $1 -noout -serial | cut -d = -f 2)
CERT_SERIAL=$(openssl x509 -in "$1" -noout -serial | cut -d = -f 2)
grep -q $CERT_SERIAL $CRL_SERIAL_FILE
grep -q "$CERT_SERIAL" "$CRL_SERIAL_FILE"
}
check_file()
{
[ $# = 0 ] ||
[ -e "$1" ] ||
(echo "File '$1' not found" >&2 && exit 1)
(echo "File '$1' not found" >&2 && exit 1)
}
# check args
@@ -221,28 +227,25 @@ CRL_FILE=
CA_FILE=
CHECK_DEFAULT_ISSUER=1
args=$(getopt -qu "dr:c:h" $*)
if [ $? = 0 ]
then
set -- $args
while [ $1 != "" ]
do
case $1 in
-d) CHECK_DEFAULT_ISSUER=0; shift;;
-r) CRL_FILE=$2; shift 2;;
-c) CA_FILE=$2; shift 2;;
-h) usage $0; exit 0;;
--) shift; break;;
esac
done
else
usage $0 >&2
exit 1
fi
while getopts 'dr:c:h' opt; do
case $opt in
d) CHECK_DEFAULT_ISSUER=0 ;;
r) CRL_FILE=$OPTARG ;;
c) CA_FILE=$OPTARG ;;
h)
usage "$0"
exit 0
;;
?)
usage "$0"
exit 1
;;
esac
done
shift "$((OPTIND - 1))"
if [ $# -ne 2 ]
then
usage $0 >&2
if [ $# -ne 2 ]; then
usage "$0" >&2
exit 1
fi
@@ -250,51 +253,51 @@ HKD_FILE=$1
HKSK_FILE=$2
# Check whether all specified files exist
check_file $HKD_FILE
check_file $HKSK_FILE
check_file $CA_FILE
check_file $CRL_FILE
check_file "$HKD_FILE"
check_file "$HKSK_FILE"
# CA and CRL are optional arguments
[ -n "$CA_FILE" ] && check_file "$CA_FILE"
[ -n "$CRL_FILE" ] && check_file "$CRL_FILE"
# Check trust chain
check_verify_chain $HKSK_FILE $CA_FILE
check_verify_chain "$HKSK_FILE" "$CA_FILE"
# Verify host key document signature
echo -n "Checking host key document signature: "
extract_pubkey $HKSK_FILE $ISSUER_PUBKEY_FILE &&
extract_signature $HKD_FILE $SIGNATURE_FILE &&
extract_body $HKD_FILE $BODY_FILE &&
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
exit 1
printf "Checking host key document signature: "
extract_pubkey "$HKSK_FILE" "$ISSUER_PUBKEY_FILE" &&
extract_signature "$HKD_FILE" "$SIGNATURE_FILE" &&
extract_body "$HKD_FILE" "$BODY_FILE" &&
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
exit 1
# Verify the issuer
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
canonical_dn x509 "$HKD_FILE" issuer "$ISSUER_DN_FILE"
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
verify_issuer_files $CHECK_DEFAULT_ISSUER
# Verify dates
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
verify_dates "$(cert_time "$HKD_FILE" startdate)" "$(cert_time "$HKD_FILE" enddate)"
# Check CRL if specified
if [ -n "$CRL_FILE" ]
then
echo -n "Checking CRL signature: "
extract_signature $CRL_FILE $SIGNATURE_FILE &&
extract_body $CRL_FILE $BODY_FILE &&
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
exit 1
if [ -n "$CRL_FILE" ]; then
printf "Checking CRL signature: "
extract_signature "$CRL_FILE" "$SIGNATURE_FILE" &&
extract_body "$CRL_FILE" "$BODY_FILE" &&
verify_signature "$ISSUER_PUBKEY_FILE" "$SIGNATURE_FILE" "$BODY_FILE" ||
exit 1
echo -n "CRL "
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
printf "CRL "
canonical_dn crl "$CRL_FILE" issuer "$ISSUER_DN_FILE"
canonical_dn x509 "$HKSK_FILE" subject "$SUBJECT_DN_FILE"
verify_issuer_files $CHECK_DEFAULT_ISSUER
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
verify_dates "$(crl_time "$CRL_FILE" lastupdate)" "$(crl_time "$CRL_FILE" nextupdate)" 'CRL'
crl_serials $CRL_FILE
check_serial $HKD_FILE &&
echo "Certificate is revoked, do not use it anymore!" >&2 &&
exit 1
crl_serials "$CRL_FILE"
check_serial "$HKD_FILE" &&
echo "Certificate is revoked, do not use it anymore!" >&2 &&
exit 1
fi
# We made it
echo All checks reqested for \'$HKD_FILE\' were successful
echo All checks requested for \'"$HKD_FILE"\' were successful

View File

@@ -3,7 +3,7 @@ include ../../common.mak
bin_PROGRAM = genprotimg
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
PKGDATADIR ?= "$(TOOLS_DATADIR)/genprotimg"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
TOP_SRCDIR := $(SRC_DIR)/../
ROOT_DIR = $(TOP_SRC_DIR)/../../

View File

@@ -17,7 +17,8 @@
/* IBM signing key subject */
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"

View File

@@ -664,62 +664,9 @@ static gboolean x509_name_data_by_nid_equal(X509_NAME *name, gint nid,
return memcmp(data, y, data_len) == 0;
}
static gboolean own_X509_NAME_ENTRY_equal(const X509_NAME_ENTRY *x,
const X509_NAME_ENTRY *y)
{
const ASN1_OBJECT *x_obj = X509_NAME_ENTRY_get_object(x);
const ASN1_STRING *x_data = X509_NAME_ENTRY_get_data(x);
const ASN1_OBJECT *y_obj = X509_NAME_ENTRY_get_object(y);
const ASN1_STRING *y_data = X509_NAME_ENTRY_get_data(y);
gint x_len = ASN1_STRING_length(x_data);
gint y_len = ASN1_STRING_length(y_data);
if (x_len < 0 || x_len != y_len)
return FALSE;
/* ASN1_STRING_cmp(x_data, y_data) == 0 doesn't work because it also
* compares the type, which is sometimes different.
*/
return OBJ_cmp(x_obj, y_obj) == 0 &&
memcmp(ASN1_STRING_get0_data(x_data),
ASN1_STRING_get0_data(y_data),
(unsigned long)x_len) == 0;
}
static gboolean own_X509_NAME_equal(const X509_NAME *x, const X509_NAME *y)
{
gint x_count = X509_NAME_entry_count(x);
gint y_count = X509_NAME_entry_count(y);
if (x != y && (!x || !y))
return FALSE;
if (x_count != y_count)
return FALSE;
for (gint i = 0; i < x_count; i++) {
const X509_NAME_ENTRY *entry_i = X509_NAME_get_entry(x, i);
gboolean entry_found = FALSE;
for (gint j = 0; j < y_count; j++) {
const X509_NAME_ENTRY *entry_j =
X509_NAME_get_entry(y, j);
if (own_X509_NAME_ENTRY_equal(entry_i, entry_j)) {
entry_found = TRUE;
break;
}
}
if (!entry_found)
return FALSE;
}
return TRUE;
}
/* Checks whether the subject of @cert is a IBM signing key subject. For this we
* must check that the subject is equal to: 'C = US, ST = New York, L =
* Poughkeepsie, O = International Business Machines Corporation, CN =
* Poughkeepsie or Armonk, O = International Business Machines Corporation, CN =
* International Business Machines Corporation' and the organization unit (OUT)
* must end with the suffix ' Key Signing Service'.
*/
@@ -743,8 +690,10 @@ static gboolean has_ibm_signing_subject(X509 *cert)
PV_IBM_Z_SUBJECT_STATE))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME))
if (!(x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) ||
x509_name_data_by_nid_equal(subject, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK)))
return FALSE;
if (!x509_name_data_by_nid_equal(subject, NID_organizationName,
@@ -806,6 +755,39 @@ static X509_NAME *x509_name_reorder_attributes(const X509_NAME *name, const gint
return g_steal_pointer(&ret);
}
/** Replace locality 'Armonk' with 'Pougkeepsie'. If Armonk was not set return
* `NULL`.
*/
static X509_NAME *x509_armonk_locality_fixup(const X509_NAME *name)
{
g_autoptr(X509_NAME) ret = NULL;
int pos;
/* Check if ``L=Armonk`` */
if (!x509_name_data_by_nid_equal((X509_NAME *)name, NID_localityName,
PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK))
return NULL;
ret = X509_NAME_dup((X509_NAME *)name);
if (!ret)
g_abort();
pos = X509_NAME_get_index_by_NID(ret, NID_localityName, -1);
if (pos == -1)
return NULL;
X509_NAME_ENTRY_free(X509_NAME_delete_entry(ret, pos));
/* Create a new name entry at the same position as before */
if (X509_NAME_add_entry_by_NID(
ret, NID_localityName, MBSTRING_UTF8,
(const unsigned char *)&PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE,
sizeof(PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE) - 1, pos, 0) != 1)
return NULL;
return g_steal_pointer(&ret);
}
/* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
* ordered. The problem is that our certificates are not consistent in the order
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
@@ -828,24 +810,10 @@ X509_NAME *c2b_name(const X509_NAME *name)
return X509_NAME_dup((X509_NAME *)name);
}
/* Verify that: subject(issuer) == issuer(crl) and SKID(issuer) == AKID(crl) */
/* Verify that SKID(issuer) == AKID(crl) if available */
static gint check_crl_issuer(X509_CRL *crl, X509 *issuer, GError **err)
{
const X509_NAME *crl_issuer = X509_CRL_get_issuer(crl);
const X509_NAME *issuer_subject = X509_get_subject_name(issuer);
AUTHORITY_KEYID *akid = NULL;
if (!own_X509_NAME_equal(issuer_subject, crl_issuer)) {
g_autofree char *issuer_subject_str = X509_NAME_oneline(issuer_subject,
NULL, 0);
g_autofree char *crl_issuer_str = X509_NAME_oneline(crl_issuer, NULL, 0);
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
_("issuer mismatch:\n%s\n%s"),
issuer_subject_str, crl_issuer_str);
return -1;
}
g_autoptr(AUTHORITY_KEYID) akid = NULL;
/* If AKID(@crl) is specified it must match with SKID(@issuer) */
akid = X509_CRL_get_ext_d2i(crl, NID_authority_key_identifier, NULL, NULL);
@@ -881,7 +849,6 @@ gint check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
return -1;
}
/* check that the @crl issuer matches with the subject name of @cert*/
if (check_crl_issuer(crl, cert, err) < 0)
return -1;
@@ -910,6 +877,60 @@ gint check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
return 0;
}
/* This function contains work-arounds for some known subject(CRT)<->issuer(CRL)
* issues.
*/
static STACK_OF_X509_CRL *quirk_X509_STORE_ctx_get1_crls(X509_STORE_CTX *ctx,
const X509_NAME *subject, GError **err)
{
g_autoptr(X509_NAME) fixed_subject = NULL;
g_autoptr(STACK_OF_X509_CRL) ret = NULL;
ret = Pv_X509_STORE_CTX_get1_crls(ctx, subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the mismatch between issuer name of the * IBM
* signing CRLs and the IBM signing key subject name. Locality name has
* changed from Poughkeepsie to Armonk.
*/
fixed_subject = x509_armonk_locality_fixup(subject);
/* Was the locality replaced? */
if (fixed_subject) {
X509_NAME *tmp;
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
/* Workaround to fix the ordering mismatch between issuer name
* of the IBM signing CRLs and the IBM signing key subject name.
*/
tmp = fixed_subject;
fixed_subject = c2b_name(fixed_subject);
X509_NAME_free(tmp);
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
X509_NAME_free(fixed_subject);
fixed_subject = NULL;
}
/* Workaround to fix the ordering mismatch between issuer name of the
* IBM signing CRLs and the IBM signing key subject name.
*/
fixed_subject = c2b_name(subject);
sk_X509_CRL_free(ret);
ret = Pv_X509_STORE_CTX_get1_crls(ctx, fixed_subject);
if (ret && sk_X509_CRL_num(ret) > 0)
return g_steal_pointer(&ret);
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_CRL, _("no CRL found"));
return NULL;
}
/* Given a certificate @cert try to find valid revocation lists in @ctx. If no
* valid CRL was found NULL is returned.
*/
@@ -927,20 +948,9 @@ STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
return NULL;
}
ret = X509_STORE_CTX_get1_crls(ctx, subject);
if (!ret) {
/* Workaround to fix the mismatch between issuer name of the
* IBM Z signing CRLs and the IBM Z signing key subject name.
*/
g_autoptr(X509_NAME) broken_subject = c2b_name(subject);
ret = X509_STORE_CTX_get1_crls(ctx, broken_subject);
if (!ret) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_CRL,
_("no CRL found"));
return NULL;
}
}
ret = quirk_X509_STORE_ctx_get1_crls(ctx, subject, err);
if (!ret)
return NULL;
/* Filter out non-valid CRLs for @cert */
for (gint i = 0; i < sk_X509_CRL_num(ret); i++) {
@@ -1328,32 +1338,14 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
/* It's almost the same as X509_check_issed from OpenSSL does except that we
* don't check the key usage of the potential issuer. This means we check:
* 1. issuer_name(cert) == subject_name(issuer)
* 2. Check whether the akid(cert) (if available) matches the issuer skid
* 3. Check that the cert algrithm matches the subject algorithm
* 4. Verify the signature of certificate @cert is using the public key of
* 1. Check whether the akid(cert) (if available) matches the issuer skid
* 2. Check that the cert algrithm matches the subject algorithm
* 3. Verify the signature of certificate @cert is using the public key of
* @issuer.
*/
static gint check_host_key_issued(X509 *cert, X509 *issuer, GError **err)
{
const X509_NAME *issuer_subject = X509_get_subject_name(issuer);
const X509_NAME *cert_issuer = X509_get_issuer_name(cert);
AUTHORITY_KEYID *akid = NULL;
/* We cannot use X509_NAME_cmp() because it considers the order of the
* X509_NAME_Entries.
*/
if (!own_X509_NAME_equal(issuer_subject, cert_issuer)) {
g_autofree char *issuer_subject_str =
X509_NAME_oneline(issuer_subject, NULL, 0);
g_autofree char *cert_issuer_str =
X509_NAME_oneline(cert_issuer, NULL, 0);
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
_("Subject issuer mismatch:\n'%s'\n'%s'"),
issuer_subject_str, cert_issuer_str);
return -1;
}
g_autoptr(AUTHORITY_KEYID) akid = NULL;
akid = X509_get_ext_d2i(cert, NID_authority_key_identifier, NULL, NULL);
if (akid && X509_check_akid(issuer, akid) != X509_V_OK) {
@@ -1834,14 +1826,12 @@ static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
g_assert(out_len >= 0);
num_bytes_written = BIO_write(b_out, out_buf, out_len);
if (num_bytes_written < 0) {
if (num_bytes_written != out_len) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("Failed to write"));
return -1;
}
g_assert(num_bytes_written == out_len);
tmp_size_out += (guint)num_bytes_written;
/* Set new tweak value. Please keep in mind that the

View File

@@ -75,6 +75,7 @@ void x509_pair_free(x509_pair *pair);
/* Register auto cleanup functions */
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)

View File

@@ -24,11 +24,25 @@
#define OS_INFO_VMCOREINFO 0
#define OS_INFO_REIPL_BLOCK 1
#define OS_INFO_FLAGS_ENTRY 2
#define OS_INFO_RESERVED 3
#define OS_INFO_IDENTITY_BASE 4
#define OS_INFO_KASLR_OFFSET 5
#define OS_INFO_KASLR_OFF_PHYS 6
#define OS_INFO_VMEMMAP 7
#define OS_INFO_AMODE31_START 8
#define OS_INFO_AMODE31_END 9
#define OS_INFO_IMAGE_START 10
#define OS_INFO_IMAGE_END 11
#define OS_INFO_IMAGE_PHYS 12
#define OS_INFO_MAX 13
#define OS_INFO_FLAG_REIPL_CLEAR (1UL << 0)
struct os_info_entry {
uint64_t addr;
union {
uint64_t addr;
uint64_t val;
};
uint64_t size;
uint32_t csum;
} __packed;
@@ -40,10 +54,12 @@ struct os_info {
uint16_t version_minor;
uint64_t crashkernel_addr;
uint64_t crashkernel_size;
struct os_info_entry entry[3];
uint8_t reserved[4004];
struct os_info_entry entry[OS_INFO_MAX];
uint8_t reserved[3804];
} __packed;
STATIC_ASSERT(sizeof(struct os_info) == 4096)
/*
* Return 0 in case of valid os_info
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is

View File

@@ -26,6 +26,17 @@
#define DF_S390_EM_STR "DUMP_END"
#define DF_S390_CPU_MAX 512
#define DF_S390_MAGIC_BLK_ECKD 3
#define DF_S390_DUMPER_MAGIC_SIZE 7
#define DF_S390_DUMPER_MAGIC32 "ZECKD31"
#define DF_S390_DUMPER_MAGIC64 "ZECKD64"
#define DF_S390_DUMPER_MAGIC_EXT "XECKD64"
#define DF_S390_DUMPER_MAGIC32_FBA "ZDFBA31"
#define DF_S390_DUMPER_MAGIC64_FBA "ZDFBA64"
#define DF_S390_DUMPER_MAGIC_FBA_EXT "XDFBA64"
#define DF_S390_DUMPER_MAGIC_MV "ZMULT64"
#define DF_S390_DUMPER_MAGIC_MV_EXT "XMULT64"
#define OLD_DUMPER_HEX_INSTR1 "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
#define OLD_DUMPER_HEX_INSTR2 "\x0d\xd0" /* BASR 13,0 */
/*
* Architecture of dumped system

View File

@@ -21,7 +21,9 @@
#define AP_UDEV_FILE "/etc/udev/rules.d/41-ap.rules"
#define AP_LOCKFILE "/run/lock/s390apconfig.lock"
#define AP_LOCK_RETRIES 15
#define AP_LOCK_RETRIES 3000
#define AP_LOCK_DELAY_US 30000 /* wait at least 30ms between lock retries */
#define AP_LOCK_VARIANCE_US 3000 /* or as much as 33ms */
/* apmask and aqmask are each represented as 67 character strings with:
* '0x' leading characters
@@ -70,6 +72,7 @@ char *path_get_ap_udev(void);
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev);
/* Functions for reading JSON device config */
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
@@ -85,6 +88,9 @@ bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
bool *read_aq);
void ap_mask_to_list(char *mask, struct util_list *list);
void ap_list_remove_all(struct util_list *list);
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size);
/* Lock Functions */
int ap_get_lock(void);

View File

@@ -27,6 +27,7 @@ enum util_arch_machine_type {
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
UTIL_ARCH_MACHINE_TYPE_Z16 = 3931,
UTIL_ARCH_MACHINE_TYPE_Z16_A02 = 3932,
};
int util_arch_machine_type(void);

View File

@@ -14,7 +14,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "zt_common.h"
#include "lib/util_libc.h"
void util_hexdump(FILE *fh, const char *tag, const void *data, int cnt);
void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group,
@@ -37,4 +40,30 @@ static inline void util_ptr_vec_free(void **ptr_vec, int count)
free(ptr_vec);
}
/*
* Expand size of dynamic array (element_t *) by one element
*
* @param[in,out] array Pointer to array (element_t **)
* @param[in,out] num Pointer to integer containing number of elements
*/
#define util_expand_array(array, num) \
do { \
unsigned int __size = sizeof(*(*(array))); \
*(array) = util_realloc(*(array), ++(*(num)) * __size); \
memset(&((*(array))[*(num) - 1]), 0, __size); \
} while (0)
/*
* Append one element to dynamic array (element_t *)
*
* @param[in,out] array Pointer to array (element_t **)
* @param[in,out] num Pointer to integer containing number of elements
* @param[in] element Element to add (element_t)
*/
#define util_add_array(array, num, element) \
do { \
util_expand_array(array, num); \
(*(array))[*(num) - 1] = (element) ; \
} while (0)
#endif /* LIB_UTIL_BASE_H */

235
include/lib/util_fmt.h Normal file
View File

@@ -0,0 +1,235 @@
/*
* util_fmt - Format structured key-value data as JSON, text pairs, or CSV
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
* This module provides helper functions for converting structured key-value
* data into different output formats.
*
* Benefits:
* - Output format can be dynamically configured at run-time
* - Callers do not need to add extra code for each output format
* - Some format-specific requirements such as quoting, indentation, and
* comma-placement are automated
*
* Basic API calling sequence:
*
* util_fmt_init() => Select output format
* util_fmt_obj_start() => Start a new object or list
* util_fmt_pair() => Emit a key-value pair
* util_fmt_obj_end() => End the latest object or list
* util_fmt_exit() => Cleanup
*
* Note:
* - Supported data elements are objects, lists and key-value pairs (mappings)
* - Scalars are only supported as part of a mapping
* - For CSV output and key filtering, mapping keys must be unique - this can
* be achieved either by choosing unique key names or by including object
* names via the FMT_PREFIX flag
* - For CSV output, at least one object or list with the FMT_ROW flag must be
* emitted
* - Common tool-specific meta-information such as API-level, tool version,
* etc. is automatically added to the output
*/
#ifndef LIB_UTIL_FMT_H
#define LIB_UTIL_FMT_H
#include <stdbool.h>
#include <stdio.h>
/* Flag value for default behavior (all flag types). */
#define FMT_DEFAULT 0
/* Names of supported output format types. */
#define FMT_TYPE_NAMES "json json-seq pairs csv"
/**
* enum util_fmt_t - Output format types.
* @FMT_JSON: JavaScript Object Notation output data structure
* @FMT_JSONSEQ: Sequence of JSON data structures according to RFC7464
* @FMT_PAIRS: Textual key=value pairs
* @FMT_CSV: Comma-separated-values output
*
* Use these types with util_fmt_init() to control the output format.
*/
enum util_fmt_t {
FMT_JSON,
FMT_JSONSEQ,
FMT_PAIRS,
FMT_CSV,
};
/**
* enum util_fmt_flags_t - Format control flags.
* @FMT_NOPREFIX: (pairs) Remove object hierarchy prefix from keys
* @FMT_KEEPINVAL: (all) Print mappings even if value is marked as invalid
* Values will be replaced with null (JSON) or an empty
* string
* @FMT_QUOTEALL: (all) Add quotes to all mapping values
* @FMT_FILTER: (all) Ignore keys not announced via util_fmt_add_key()
* @FMT_HANDLEINT: (json) Ensure correct JSON closure when interrupted
* @FMT_NOMETA: (all) Do not emit tool meta-data
* @FMT_WARN: (all) Warn about incorrect API usage
*
* Use these flags with util_fmt_init() to control generic aspects.
*/
enum util_fmt_flags_t {
FMT_NOPREFIX = (1 << 0),
FMT_KEEPINVAL = (1 << 1),
FMT_QUOTEALL = (1 << 2),
FMT_FILTER = (1 << 3),
FMT_HANDLEINT = (1 << 4),
FMT_NOMETA = (1 << 5),
FMT_WARN = (1 << 6),
};
/**
* enum util_fmt_oflags_t - Object flags.
* @FMT_LIST: (all) Object is a list
* @FMT_ROW: (csv) Start a new CSV row with this object
* @FMT_PREFIX: (all) Include object name in key prefix for CSV headings
* and filter keys
*
* Use these flags with util_fmt_obj_start() to control object related
* aspects.
*/
enum util_fmt_oflags_t {
FMT_LIST = (1 << 0),
FMT_ROW = (1 << 1),
FMT_PREFIX = (1 << 2),
};
/**
* enum util_fmt_mflags_t - Mapping flags.
* @FMT_QUOTE: (all) Quote value
* @FMT_INVAL: (all) Mark value as invalid
* @FMT_PERSIST: (csv) Keep value across CSV rows until overwritten
*
* Use these flags with util_fmt_pair() to control mapping related aspects.
*/
enum util_fmt_mflags_t {
FMT_QUOTE = (1 << 0),
FMT_INVAL = (1 << 1),
FMT_PERSIST = (1 << 2),
};
/**
* util_fmt_init() - Initialize output formatter.
* @fd : Output file descriptor
* @type : Output format type
* @flags: Formatting parameters
* @api_level: Output format level indicator
*
* Prepare for writing formatted output with the given @type to @fd. Additional
* @flags can be specified to control certain output aspects (see &enum
* util_fmt_flags_t).
*
* @api_level represents an application-specific output format version number:
* this number starts at 1 and must be increased whenever an incompatible format
* change is introduced, e.g. when a non-optional object or mapping is removed
* or used for different data.
*/
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
int api_level);
/**
* util_fmt_exit() - Release resources used by output formatter.
*
* Release all resources currently in use by the output formatter.
*/
void util_fmt_exit(void);
/**
* util_fmt_name_to_type() - Convert format name to type identifier.
* @name: Format name
* @type: Pointer to resulting format type identifier
*
* Search supported output format types for a type with associated @name. If
* found, store resulting type identifier in @type.
*
* Return: %true if type is found, %false otherwise.
*/
bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type);
/**
* util_fmt_set_indent() - Set indentation parameters.
* @base : Base indentation level to apply to all output lines (default 0)
* @width : Number of indentation characters per intendation level (default 2)
* @ind_char: Indentation characters to use (default space).
*/
void util_fmt_set_indent(unsigned int base, unsigned int width, char ind_char);
/**
* util_fmt_add_key() - Register expected mapping keys.
* @fmt: Format string to generate key
*
* Register a mapping key before the associated key-value pair is emitted.
*
* Use this function together with format control flag @FMT_FILTER to ignore all
* key-value pairs for which the key has not been registered. This can be
* useful to allow for dynamically configured filtering of output based on
* a static list of emitted mappings.
*
* When creating CSV output, use this function to register all column keys
* in advance to enable a stable column list in case of rows that do not
* provide data for all columns.
*/
void util_fmt_add_key(const char *fmt, ...);
/**
* util_fmt_obj_start() - Start a new data object.
* @oflags: Flags controlling aspects of this object.
* @fmt : Format string for generating an object name or %NULL.
*
* Use this function to start a new object in output data. Depending on
* @oflags, the new object represents either a normal object or a list. @oflags
* can also be used to indicated that an object corresponds to a new row of
* CSV data. If @fmt is non-%NULL, the resulting name is used in a format
* type specified way:
*
* Pairs:
* - Object names are reflected as dot-separated component in the mapping
* prefix, e.g. 'a.b.key=value'
* - An index is generated for mappings and objects that are part of list,
* e.g. 'a.b[1].key=value'
* JSON:
* - Object names are reflected as key-object mappings, e.g.
* <name>: { }
* - Required commas between objects and mappings are automatically generated
* CSV:
* - Object names and the list type flag have no effect
* - When flag @FMT_ROW is specified, a CSV row will be emitted when
* util_fmt_obj_end() is called for the associated object
*/
void util_fmt_obj_start(unsigned int oflags, const char *fmt, ...);
/**
* util_fmt_obj_end() - Announce the end of the latest data object started.
*
* Each object started with util_fmt_obj_start() must be ended with an
* associated util_fmt_obj_end() call.
*/
void util_fmt_obj_end(void);
/**
* util_fmt_pair() - Emit a key-value pair.
* @mflags: Flags controlling this pair.
* @key : Key for this pair, excluding prefix.
* @fmt : Format string used to generated the pair value.
*
* Emit a key-value pair with the specified @key and the value that results
* from format string @fmt.
*
* Notes:
* - For JSON, a mapping can only occur after util_fmt_obj_start()
* - For CSV, each @key must be unique, either by choosing unique key names
* or by including object names as prefix via the use of FMT_PREFIX in
* parent objects
*/
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...);
#endif /* LIB_UTIL_FMT_H */

View File

@@ -127,6 +127,7 @@ do { \
int __util_vsprintf(const char *func, const char *file, int line,
char *str, const char *fmt, va_list ap);
char *util_strcat_realloc(char *str1, const char *str2);
void util_concatf(char **str1, const char *fmt, ...);
void util_str_toupper(char *str);
char *util_strstrip(char *s);

View File

@@ -18,7 +18,11 @@
#define UTIL_LOCKFILE_ERR 4 /* Other, unexpected error conditions */
int util_lockfile_lock(char *lockfile, int retries);
int util_lockfile_lock_cw(char *lockfile, int retries, unsigned int waitinc,
unsigned int maxwait);
int util_lockfile_parent_lock(char *lockfile, int retries);
int util_lockfile_parent_lock_cw(char *lockfile, int retries,
unsigned int waitinc, unsigned int maxwait);
int util_lockfile_release(char *lockfile);
int util_lockfile_parent_release(char *lockfile);

View File

@@ -40,6 +40,7 @@
#define LV_COMPAT_CYL 0xFFFE
#define VTOC_ERROR "VTOC error:"
#define MAX_VTOC_ENTRIES 9 /* max number of VTOC labels for cdl formatted DASD */
typedef struct ttr
{

View File

@@ -1,439 +0,0 @@
/*
* Certificate functions and definitions.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_CERT_H
#define LIBPV_CERT_H
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "libpv/common.h"
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
/* Minimum security level for the keys/certificates used to establish a chain of
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
* for details).
*/
#define PV_CERTS_SECURITY_LEVEL 2
/** pv_cert_init:
*
* Should not be called by user.
* Use pv_init() instead which
* calls this function during creation.
*
* Sets up data structures for caching CRLs.
*/
void pv_cert_init(void);
/** pv_cert_cleanup:
*
* Should not be called by user.
* Use pv_cleanup() instead which
* calls this function during creation.
*
* Cleans up data structures for caching CRLs.
*/
void pv_cert_cleanup(void);
#define PV_CERT_ERROR g_quark_from_static_string("pv-cert-error-quark")
typedef enum {
PV_CERT_ERROR_CERT_REVOKED,
PV_CERT_ERROR_CERT_SIGNATURE_INVALID,
PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
PV_CERT_ERROR_CRL_DOWNLOAD_FAILED,
PV_CERT_ERROR_CRL_SIGNATURE_INVALID,
PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
PV_CERT_ERROR_INTERNAL,
PV_CERT_ERROR_INVALID_PARM,
PV_CERT_ERROR_INVALID_SIGNATURE_ALGORITHM,
PV_CERT_ERROR_INVALID_VALIDITY_PERIOD,
PV_CERT_ERROR_LOAD_CRL,
PV_CERT_ERROR_LOAD_DEFAULT_CA,
PV_CERT_ERROR_LOAD_ROOT_CA,
PV_CERT_ERROR_MALFORMED_CERTIFICATE,
PV_CERT_ERROR_MALFORMED_ROOT_CA,
PV_CERT_ERROR_NO_CRL,
PV_CERT_ERROR_NO_CRLDP,
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
PV_CERT_ERROR_NO_PUBLIC_KEY,
PV_CERT_ERROR_READ_CERTIFICATE,
PV_CERT_ERROR_READ_CRL,
PV_CERT_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
PV_CERT_ERROR_SKID_AKID_MISMATCH,
PV_CERT_ERROR_VERIFICATION_FAILED,
PV_CERT_ERROR_WRONG_CA_USED,
} PvCertErrors;
/** PvX509WithPath - X509 certificate associated with a path
*/
typedef struct {
X509 *cert;
char *path;
} PvX509WithPath;
/** pv_x509_with_path_new:
*
* @cert: X509 certificate
* @path: Path of that X509 certificate
*
* Returns: (nullable) (transfer full): new X509 with path
*/
PvX509WithPath *pv_x509_with_path_new(X509 *cert, const char *path);
/** pv_x509_with_path_free:
*
* Frees the path and the PvX509WithPath; Decreases the refcount of the X509
*/
void pv_x509_with_path_free(PvX509WithPath *cert);
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
typedef STACK_OF(X509) STACK_OF_X509;
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
typedef GSList PvCertWithPathList;
typedef struct {
X509 *cert;
STACK_OF_X509_CRL *crls;
} PvX509Pair;
/** pv_x509_pair_new_take:
* @cert: ptr to X509
* @crls: ptr to CRLs
*
* Takes a X509 and the associated CRLs and builds a pair.
* Both, *cert and *crls will be NULL afterwards, and owned by the pair.
*
* Returns: (nullable) (transfer full): New PvX509Pair
*/
PvX509Pair *pv_x509_pair_new_take(X509 **cert, STACK_OF_X509_CRL **crls);
/** pv_x509_pair_free:
*
* Decreases the refcount of the X509 and crls.
* Frees the PvX509Pair.
*/
void pv_x509_pair_free(PvX509Pair *pair);
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
void STACK_OF_X509_free(STACK_OF_X509 *stack);
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
/** pv_x509_from_pem_der_data:
*
* @data: GBytes containing the cert in PEM format
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): X509 cert
*/
X509 *pv_x509_from_pem_der_data(GBytes *data, GError **error);
/** pv_x509_get_ec_pubkey:
*
* @cert: X509 to extract elliptic curve pubkey from
* @nid: numerical identifier of the expected curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): corresponding pupkey for the given certificate
*/
EVP_PKEY *pv_x509_get_ec_pubkey(X509 *cert, int nid, GError **error);
/** pv_get_ec_pubkeys:
*
* @certs_with_path: List of PvX509WithPath
* @nid: numerical identifier of the expected curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): List of corresponding public keys for the given certificate
*/
GSList *pv_get_ec_pubkeys(PvCertWithPathList *certs_with_path, int nid, GError **error);
/* pv_load_certificates:
*
* @cert_paths: list of cert paths.
* @error: return location for a #GError
*
* @cert_paths must contain at least one element, otherwise an error is
* reported.
*
* Returns: (nullable) (transfer full): List of PvX509WithPath corresponding to the given paths
*/
PvCertWithPathList *pv_load_certificates(char **cert_paths, GError **error);
/* pv_load_first_cert_from_file:
*
* @path: location of the x509
* @error: return location for a #GError
*
* This function reads in only the first certificate and ignores all other. This
* is only relevant for the PEM file format. For the host-key document and the
* root CA this behavior is expected.
*
* Returns: (nullable) (transfer full): PvX509WithPath corresponding to the given path
*/
X509 *pv_load_first_cert_from_file(const char *path, GError **error);
/* pv_load_first_crl_from_file:
*
* @path: location of the x509 CRL
* @error: return location for a #GError
*
* This function reads in only the first CRL and ignores all other. This
* is only relevant for the PEM file format.
*
* Returns: (nullable) (transfer full): X509_CRL corresponding to the given path
*/
X509_CRL *pv_load_first_crl_from_file(const char *path, GError **error);
/** pv_store_setup_crl_download:
*
* @st: X509_STORE
*/
void pv_store_setup_crl_download(X509_STORE *st);
/** pv_load_first_crl_by_cert:
* @cert: X509 to specify the download location.
* @error: return location for a #GError
*
* This function returns the first X509_CRL found from the CRL distribution
* points specified in @cert.
*
* Returns: (nullable) (transfer full): x509 CRL corresponding to the given X509
*/
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error);
/** pv_try_load_crls_by_certs:
*
* @certs_with_path: List of PvX509WithPath
*
* Returns: (nullable) (transfer full): Stack of CRLs corresponding to the given X509
*/
STACK_OF_X509_CRL *pv_try_load_crls_by_certs(PvCertWithPathList *certs_with_path);
/** pv_store_setup:
*
* @root_ca_path: Location of the rootCA or NULL if SystemRoot CA shall be used
* @crl_paths: List of CRL paths or NULL
* @cert_with_crl_paths: List of (untrusted) X509 paths
* @error: return location for a #GError
*
* The untrusted certs need to be verified before actually verifying a Host Key Document.
*
* Returns: (nullable) (transfer full): X509_store with given input data.
*
*/
X509_STORE *pv_store_setup(char *root_ca_path, char **crl_paths, char **cert_with_crl_paths,
GError **error);
/** pv_get_x509_stack:
*
* x509_with_path_list: list of PvX509WithPath
*
* Returns: (nullable) (transfer full): Stack of X509 corresponding to the given x509 with path
*/
STACK_OF_X509 *pv_get_x509_stack(const GSList *x509_with_path_list);
/** pv_init_store_ctx:
*
* @ctx: a uninitialized Store CTX
* @trusted: X509_STORE with a trusted rootCA
* @chain: untrusted X509s
* @error: return location for a #GError
*
* Can be called multiple times on the same context if X509_STORE_CTX_cleanup(ctx)
* was called before.
*
* Returns:
* 0 on success
* -1 in failure
*/
int pv_init_store_ctx(X509_STORE_CTX *ctx, X509_STORE *trusted, STACK_OF_X509 *chain,
GError **error) PV_NONNULL(1, 2, 3);
/** pv_init_store_ctx:
*
* @trusted: X509_STORE with a trusted rootCA
* @chain: untrusted X509s
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): X509_STORE_CTX setup with the input data
*/
X509_STORE_CTX *pv_create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain, GError **error)
PV_NONNULL(1, 2);
/** pv_remove_ibm_signing_certs:
*
* @certs: Stack of X509s
*
* Returns: (transfer full):
* List of all IBM Z signing key certificates in @certs and remove them
* from the chain.
* Empty stack if no IBM Z signing key is found.
*/
STACK_OF_X509 *pv_remove_ibm_signing_certs(STACK_OF_X509 *certs);
/** pv_c2b_name:
*
* Workaround to fix the mismatch between issuer name of the
* IBM Z signing CRLs and the IBM Z signing key subject name.
*
* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
* ordered. The problem is that our certificates are not consistent in the order
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
*
* This function tries to reorder the name attributes such that
* further OpenSSL calls can work with it. The caller is
* responsible to free the returned value.
*/
X509_NAME *pv_c2b_name(const X509_NAME *name);
/** pv_verify_host_key:
*
* @host_key: X509 to be verified
* @issuer_pairs: IBM signing key X509+CRLs Pairs used for verification
* @level: Security level. see PV_CERTS_SECURITY_LEVEL
* @error: return location for a #GError
*
* Returns:
* 0 if Host key could be verified with one of the IBM signing keys
* -1 if no IBM signing key could verify the authenticity of the given host key
*
*/
int pv_verify_host_key(X509 *host_key, GSList *issuer_pairs, int verify_flags, int level,
GError **error);
/** pv_verify_cert:
*
* @ctx: trusted store ctx used for verification
* @cert: X509 to be verified
* @error: return location for a #GError
*
* Cannot be used to verify host keys with IBM signing keys, as IBM signing
* keys are no intermediate CAs. Use pv_verify_host_key() instead.
*
* Returns:
* 0 if @cert could be verified
* -1 if @cert could not be verified
*/
int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error) PV_NONNULL(1, 2);
/** pv_check_crl_valid_for_cert:
*
* @crl: CRL to be verified
* @cert: Cert that probably issued the given CRL
* @verify_flags: X509 Verification flags (X509_V_FLAG_<TYPE>)
* @error: return location for a #GError
*
* Verify whether a revocation list @crl is valid and is issued by @cert. For
* this multiple steps must be done:
*
* 1. verify issuer of the CRL matches with the suject name of @cert
* 2. verify the validity period of the CRL
* 3. verify the signature of the CRL
*
* Important: This function does not verify whether @cert is allowed to issue a
* CRL.
*
* Returns:
* 0 if @crl is valid and issued by @cert
* -1 otherwise
*/
int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error);
/** pv_check_chain_parameters:
*
* @chain: chain of trust to be validated
* @error: return location for a #GError
*
* Verifies that chain has at least a RootCA ans intermediate CA
* and logs the used ROD CA subject
*
* Returns:
* 0 @chain is valid
* -1 otherwise
*/
int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error);
/** pv_store_set_verify_param:
*
* @store: X509_STORE to set parameters
* @error: return location for a #GError
*
* Returns:
* 0 on success
* -1 on failure
*/
int pv_store_set_verify_param(X509_STORE *store, GError **error);
/** pv_store_ctx_find_valid_crls:
*
* @ctx: STORE_CTX for searching CRLs
* @cert: X509 to match CRLs aggainst
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): STACK of CRLs related to given @crl fin @ctx
*/
STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert, GError **error)
PV_NONNULL(1, 2);
/** pv_verify_host_key_doc:
*
* @host_key_certs_with_path: X509s to be verified
* @trusted. X509_STORE with a rusted RootCA
* @untrusted_certs: STACK OF untrusted X509s
* @online: true if CRLs shall be downloaded
* @error: return location for a #GError
*
* Returns:
* 0 if all given HKDs could be verified using the chain of trust.
* -1 otherwise
*/
int pv_verify_host_key_doc(PvCertWithPathList *host_key_certs_with_path, X509_STORE *trusted,
STACK_OF_X509 *untrusted_certs, gboolean online, GError **error)
PV_NONNULL(1, 2, 3);
/** pv_verify_host_key_docs_by_path:
*
* @host_key_paths: locations of X509 to be verified
* @optional_root_ca_path: rootCA location or NULL if Default shall be used
* @optional_crl_paths: locations of CRLs or NULL
* @untrusted_cert_paths: locations of IntermediateCAs including the IBM signing key
* @online: true if CRLs shall be downloaded
* @error: return location for a #GError
*
* Returns:
* 0 if all given HKDs could be verfied using the chain of trust.
* -1 otherwise
*/
int pv_verify_host_key_docs_by_path(char **host_key_paths, char *optional_root_ca_path,
char **optional_crl_paths, char **untrusted_cert_paths,
gboolean online, GError **error) PV_NONNULL(1, 4);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509WithPath, pv_x509_with_path_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509Pair, pv_x509_pair_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
#endif /* LIBPV_CERT_H */

View File

@@ -14,22 +14,6 @@
* the glib version is supported
*/
#include "libpv/glib-helper.h"
#include <glib/gi18n.h>
#include "libpv/openssl-compat.h"
#include "libpv/macros.h"
/** pv_init:
*
* Must be called before any libpv call.
*/
int pv_init(void);
/** pv_cleanup:
*
* Must be called when done with using libpv.
*/
void pv_cleanup(void);
#endif /* LIBPV_COMMON_H */

View File

@@ -15,6 +15,7 @@
#include <openssl/evp.h>
#include "libpv/common.h"
#define PV_NONNULL(...)
typedef struct pv_cipher_parms {
const EVP_CIPHER *cipher;
@@ -26,17 +27,6 @@ typedef struct pv_cipher_parms {
};
} PvCipherParms;
typedef union {
struct {
uint8_t x[80];
uint8_t y[80];
};
uint8_t data[160];
} PvEcdhPubKey;
G_STATIC_ASSERT(sizeof(PvEcdhPubKey) == 160);
typedef GSList PvEvpKeyList;
enum PvCryptoMode {
PV_ENCRYPT,
PV_DECRYPT,
@@ -61,42 +51,6 @@ char *pv_get_openssl_errors(void);
*/
int pv_BIO_reset(BIO *b);
/**
* pv_generate_rand_data:
* @size: number of generated random bytes using a crypographically secure pseudo random generator
* @error: return location for a #GError
*
* Creates a new #GBytes with @size random bytes using a cryptographically
* secure pseudo random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_rand_data(size_t size, GError **error);
/**
* pv_generate_key:
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure key should be generated
* @error: return location for a #GError
*
* Creates a random key for @cipher using a cryptographically secure pseudo
* random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
/**
* pv_generate_iv:
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure IV should be generated
* @error: return location for a #GError
*
* Creates a random IV for @cipher using a cryptographically secure pseudo
* random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
/* Symmetric en/decryption functions */
/**
@@ -135,7 +89,7 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
* @derived_key_len: size of the output key
* @key: input key
* @salt: salt for the extraction
* @info: infor for the expansion
* @info: info for the expansion
* @md: EVP mode of operation
* @error: return location for a #GError
*
@@ -147,54 +101,15 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
const EVP_MD *md, GError **error) PV_NONNULL(2, 3, 4, 5);
/** pv_generate_ec_key:
*
* @nid: Numerical identifier of the curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): new random key based on the given curve
*/
EVP_PKEY *pv_generate_ec_key(int nid, GError **error);
/** pv_evp_pkey_to_ecdh_pub_key:
*
* @key: input key in EVP_PKEY format
* @error: return location for a #GError
*
* Returns: the public part of the input @key in ECDH format.
*/
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error) PV_NONNULL(1);
/** pv_derive_exchange_key:
* @cust: Customer Key
* @host: Host key
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): Shared Secret of @cust and @host
*/
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error) PV_NONNULL(1, 2);
GQuark pv_crypto_error_quark(void);
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
typedef enum {
PV_CRYPTO_ERROR_DERIVE,
PV_CRYPTO_ERROR_HKDF_FAIL,
PV_CRYPTO_ERROR_INTERNAL,
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
PV_CRYPTO_ERROR_KEYGENERATION,
PV_CRYPTO_ERROR_RANDOMIZATION,
PV_CRYPTO_ERROR_READ_FILE,
PV_CRYPTO_ERROR_NO_MATCH_TAG,
} PvCryptoErrors;
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)

View File

@@ -1,53 +0,0 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_CURL_H
#define LIBPV_CURL_H
#include <curl/curl.h>
#include "libpv/common.h"
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
#define CRL_DOWNLOAD_MAX_SIZE 0x100000
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
/** curl_download:
* @url: URL to specify location of data
* @timeout_ms: time to wait until fail
* @max_size: Maximum size of the downloaded data
* @error: return location for a GError
*
* Returns: (nullable) (transfer full): Downloaded data as #GByteArray
*/
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err);
/** pv_curl_init:
*
* Should not be called by user.
* Use pv_init() instead which
* calls this function during creation.
*/
int pv_curl_init(void);
/** pv_curl_cleanup:
*
* Should not be called by user.
* Use pv_cleanup() instead which
* calls this function during creation.
*/
void pv_curl_cleanup(void);
#define PV_CURL_ERROR g_quark_from_static_string("pv-curl-error-quark")
typedef enum {
PV_CURL_ERROR_CURL_INIT_FAILED,
PV_CURL_ERROR_DOWNLOAD_FAILED,
} PvCurlErrors;
#endif /* LIBPV_CURL_H */

View File

@@ -28,8 +28,6 @@
#include <gmodule.h>
#include <stdio.h>
#include "libpv/macros.h"
#ifdef __clang__
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
DO_PRAGMA(clang diagnostic push) \
@@ -40,6 +38,8 @@
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
#endif
#define DO_PRAGMA(x) _Pragma(#x)
#define pv_wrapped_g_assert(__expr) g_assert(__expr)
/** pv_sec_gbytes_new_take:

View File

@@ -1,119 +0,0 @@
/*
* Hashing definitions.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_HASH_H
#define LIBPV_HASH_H
#include <openssl/hmac.h>
#include "libpv/common.h"
/** pv_digest_ctx_new:
* @md: mode of digest, e.g. #EVP_sha256()
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): a new #EVP_MD_CTX, or %NULL in case of an error
*/
EVP_MD_CTX *pv_digest_ctx_new(const EVP_MD *md, GError **error);
/** pv_digest_ctx_update:
* @ctx: EVP_MD_CTX to add data
* @data: #GBytes to add to the context
* @error: return location for a #GError
*
* Adds @data to the digest context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_digest_ctx_update(EVP_MD_CTX *ctx, GBytes *data, GError **error);
/** pv_digest_ctx_update_raw:
* @ctx: #EVP_MD_CTX to add data
* @buf: data to add to the context
* @size: size of @buf
* @error: return location for a #GError
*
* Adds @buf to the digest context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_digest_ctx_update_raw(EVP_MD_CTX *ctx, const uint8_t *buf, size_t size, GError **error);
/** pv_digest_ctx_finalize:
* @ctx: #EVP_MD_CTX with data to digest
* @error: return location for a #GError
*
* Calculates the digest of all previously added data. Do not use @ctx afterwards.
*
* Returns: (nullable) (transfer full): Digest of all data added before as #GBytes, or NULL in case of error.
*/
GBytes *pv_digest_ctx_finalize(EVP_MD_CTX *ctx, GError **error);
/** pv_sha256_hash:
* @buf: data for which a sha256 hash sould be calculated
* @size: size of @buf
* @error: return location for a #GError
*
* Shorthand for initializing a sha256-digest ctx, updating, and finalizing.
*
* Returns: (nullable) (transfer full): SHA256 of @buf as #GBytes, or NULL in case of error.
*/
GBytes *pv_sha256_hash(uint8_t *buf, size_t size, GError **error);
/** pv_hmac_ctx_new:
* @key: key used for the HMAC
* @md: mode of digest, e.g. #EVP_sha512()
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): New #HMAC_CTX or NULL in case of error
*/
HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error);
/** pv_hmac_ctx_update_raw:
* @ctx: #HMAC_CTX to add data
* @buf: data to add to the context
* @size: size of @buf
* @error: return location for a #GError
*
* Adds @buf to the HMAC context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *data, size_t size, GError **error);
/** pv_hmac_ctx_update:
* @ctx: #HMAC_CTX to add data
* @data: #GBytes to add to the context
* @error: return location for a #GError
*
* Adds @data to the HMAC context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_hmac_ctx_update(HMAC_CTX *ctx, GBytes *data, GError **error);
/** pv_hmac_ctx_finalize:
* @ctx: #HMAC_CTX with data to digest
* @error: return location for a #GError
*
* Calculates the HMAC of all previously added data. Do not use @ctx afterwards.
*
* Returns: (nullable) (transfer full): HMAC of all data added before as #GBytes, or NULL in case of error.
*/
GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error);
#define PV_HASH_ERROR g_quark_from_static_string("pv-crypro-error-quark")
typedef enum {
PV_HASH_ERROR_INTERNAL,
} PvHashErrors;
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(HMAC_CTX, HMAC_CTX_free)
#endif /* LIBPV_HASH_H */

View File

@@ -1,21 +0,0 @@
/*
* Libpv common macro definitions.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*/
#ifndef LIBPV_MACROS_H
#define LIBPV_MACROS_H
#include <stdint.h>
#define PV_NONNULL(...)
#define DO_PRAGMA(x) _Pragma(#x)
/* Most significant bit */
#define PV_MSB(idx) ((uint64_t)1 << (63 - (idx)))
#endif /* LIBPV_MACROS_H */

View File

@@ -1,29 +0,0 @@
/*
* OpenSSL compatibility utils
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_OPENSSL_COMPAT_H
#define LIBPV_OPENSSL_COMPAT_H
#include <openssl/opensslv.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
#define pv_X509_STORE_CTX_get_current_cert(ctx) X509_STORE_CTX_get_current_cert(ctx)
#define pv_X509_STORE_CTX_get1_crls(ctx, nm) X509_STORE_CTX_get1_crls((ctx), (nm))
#define pv_X509_STORE_set_lookup_crls(st, cb) X509_STORE_set_lookup_crls(st, cb)
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
#define pv_X509_STORE_CTX_get_current_cert(ctx) \
X509_STORE_CTX_get_current_cert((X509_STORE_CTX *)(ctx))
#define pv_X509_STORE_CTX_get1_crls(ctx, nm) \
X509_STORE_CTX_get1_crls((X509_STORE_CTX *)(ctx), (X509_NAME *)(nm))
#define pv_X509_STORE_set_lookup_crls(st, cb) \
X509_STORE_set_lookup_crls(st, (X509_STORE_CTX_lookup_crls_fn)(cb))
#endif
#endif /* LIBPV_OPENSSL_COMPAT_H */

View File

@@ -1,96 +0,0 @@
/*
* PV/SE header definitions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_SE_HDR_H
#define LIBPV_SE_HDR_H
#include "libpv/common.h"
#include <openssl/sha.h>
#include "boot/psw.h"
#include "libpv/crypto.h"
#include "libpv/macros.h"
/* Magic number which is used to identify the file containing the PV
* header
*/
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
#define PV_VERSION_1 0x00000100U
/* Plaintext control flags */
/* dumping of the configuration is allowed */
#define PV_PCF_ALLOW_DUMPING PV_MSB(34)
/* prevent Ultravisor decryption during unpack operation */
#define PV_PCF_NO_DECRYPTION PV_MSB(35)
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
#define PV_PCF_PCKMO_DEA_TDEA PV_MSB(56)
/* PCKMO encrypt-AES-key functions allowed */
#define PV_PCF_PCKMO_AES PV_MSB(57)
/* PCKMO encrypt-ECC-key functions allowed */
#define PV_PCF_PCKM_ECC PV_MSB(58)
/* maxima for the PV version 1 */
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
#define PV_V1_PV_HDR_MIN_SIZE \
(sizeof(struct pv_hdr_head) + sizeof(struct pv_hdr_encrypted) + \
sizeof(((struct pv_hdr *)0)->tag) + 1 * sizeof(struct pv_hdr_key_slot))
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
#define PV_IMAGE_ENCR_KEY_SIZE 64
typedef struct pv_hdr_key_slot {
uint8_t digest_key[SHA256_DIGEST_LENGTH];
uint8_t wrapped_key[32];
uint8_t tag[16];
} __packed PvHdrKeySlot;
typedef struct pv_hdr_opt_item {
uint32_t otype;
uint8_t ibk[32];
uint8_t data[];
} __packed PvHdrOptItem;
/* integrity protected data (by GCM tag), but non-encrypted */
struct pv_hdr_head {
uint64_t magic;
uint32_t version;
uint32_t phs;
uint8_t iv[12];
uint32_t res1;
uint64_t nks;
uint64_t sea;
uint64_t nep;
uint64_t pcf;
PvEcdhPubKey cust_pub_key;
uint8_t pld[SHA512_DIGEST_LENGTH];
uint8_t ald[SHA512_DIGEST_LENGTH];
uint8_t tld[SHA512_DIGEST_LENGTH];
} __packed;
/* Must not have any padding */
struct pv_hdr_encrypted {
uint8_t cust_comm_key[32];
uint8_t img_enc_key_1[PV_IMAGE_ENCR_KEY_SIZE / 2];
uint8_t img_enc_key_2[PV_IMAGE_ENCR_KEY_SIZE / 2];
struct psw_t psw;
uint64_t scf;
uint32_t noi;
uint32_t res2;
};
G_STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) == 32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4);
typedef struct pv_hdr {
struct pv_hdr_head head;
struct pv_hdr_key_slot *slots;
struct pv_hdr_encrypted *encrypted;
struct pv_hdr_opt_item **optional_items;
uint8_t tag[16];
} PvHdr;
#endif /* LIBPV_SE_HDR_H */

View File

@@ -15,8 +15,31 @@
#include <string.h>
#include <unistd.h>
#include "lib/util_path.h"
#include "lib/util_panic.h"
#include "ipl_tools.h"
/*
* Look up for the device in /sys/devices/ hierarchy.
*
* path must be PATH_MAX large and the value will be replaced in place
*/
static int device_sysfs_path(const char *device, char *path, const size_t path_size)
{
util_assert(device != NULL, "Internal error: device is NULL");
util_assert(path != NULL, "Internal error: path is NULL");
util_assert(path_size == PATH_MAX, "Internal error: path_size is '%zu', but must be '%zu'",
path_size, PATH_MAX);
char *buf = util_path_sysfs("block/%s/device", device);
if (!realpath(buf, path)) {
free(buf);
return -1;
}
free(buf);
return 0;
}
/*
* Check if the specified device number is a valid device number
* which can be found in the /sys/bus/ccw/drivers/dasd-eckd/
@@ -42,6 +65,26 @@ int ccw_is_device(const char *busid)
return 0;
}
/*
* Check if the specified device is a valid virtio subchannel device
*/
int ccw_is_virtio_device(const char *device)
{
char path[PATH_MAX] = { '\0' };
unsigned virtio = 0;
if (device_sysfs_path(device, path, sizeof(path)) != 0)
return -1;
/*
* The output has the following format:
* /sys/devices/css0/0.0.0000/0.0.0000/virtio0/block/vda
*/
if (sscanf(path, "/sys/devices/css0/%*[0-9a-f.]/%*[0-9a-f.]/virtio%u", &virtio) != 1)
return -1;
return 0;
}
/*
* Return CCW Bus ID (old sysfs)
*/
@@ -77,11 +120,9 @@ out_fclose:
*/
static int ccw_busid_get_sysfs_new(const char *device, char *busid)
{
char path[PATH_MAX], buf[4096];
char path[PATH_MAX] = { '\0' };
memset(buf, 0, sizeof(buf));
snprintf(path, sizeof(path), "/sys/block/%s/device", device);
if (realpath(path, buf) == NULL)
if (device_sysfs_path(device, path, sizeof(path)) != 0)
return -1;
/*
@@ -89,7 +130,7 @@ static int ccw_busid_get_sysfs_new(const char *device, char *busid)
* /sys/devices/css0/0.0.0119/0.0.3f19/block/dasda
* /sys/devices/css0/0.0.0000/0.0.0000/virtio0/block/vda
*/
if (sscanf(buf, "/sys/devices/css0/%*[0-9a-f.]/%[0-9a-f.]", busid) != 1)
if (sscanf(path, "/sys/devices/css0/%*[0-9a-f.]/%[0-9a-f.]", busid) != 1)
return -1;
return 0;
}

View File

@@ -391,7 +391,8 @@ static void dev_from_part_nvme(char *dev_name)
static int set_reipl_type(const char *dev_name)
{
if (strncmp(dev_name, "dasd", strlen("dasd")) == 0 ||
strncmp(dev_name, "vd", strlen("vd")) == 0)
strncmp(dev_name, "vd", strlen("vd")) == 0 ||
ccw_is_virtio_device(dev_name) == 0)
l.reipl_type = REIPL_CCW;
else if (strncmp(dev_name, "sd", strlen("sd")) == 0)
l.reipl_type = REIPL_FCP;
@@ -722,14 +723,14 @@ static void check_exists(const char *path, const char *attr)
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
if (access(fpath, F_OK) != 0)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
static void write_str_optional(char *string, char *file, int exit_on_fail,
const char *attr)
{
if (write_str_errno(string, file) && exit_on_fail)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
/*

View File

@@ -87,6 +87,7 @@ int nvme_is_device(char *fid_str, char *nsid_str);
* CCW
*/
extern int ccw_is_device(const char *devno);
extern int ccw_is_virtio_device(const char *device);
extern void ccw_busid_get(const char *device, char *devno);
/*

View File

@@ -15,7 +15,7 @@
prog_name=`basename $0`
guest_name=${USER:-`whoami 2>/dev/null`}
terminal=lnxhvc0
iucvconn=`which iucvconn 2>/dev/null`
iucvconn=`command -v iucvconn 2>/dev/null`
__error() {
printf "$prog_name: $@\n" >&2

View File

@@ -11,12 +11,15 @@
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef HAVE_JSONC
#include <json-c/json.h>
@@ -30,6 +33,9 @@
#include "lib/util_path.h"
#include "lib/util_udev.h"
static const char default_mask[AP_MASK_SIZE] =
"0x0000000000000000000000000000000000000000000000000000000000000000";
/*
* Return sysfs path to a bus attribute
* Note: caller is responsible for freeing the returned string
@@ -115,6 +121,37 @@ static void modify_device_attr(struct util_list *list, char *value)
vfio_ap_node_remove_dupes(list);
}
/*
* Pass a comma-delimited string of masks (adapters,domains,controls) and
* for each ON bit in these masks add the associated ID to the device
* lists.
*/
static void modify_device_ap_config(struct vfio_ap_device *dev,
char *value)
{
char *mask, *adapters, *domains, *controls;
mask = util_strdup(value);
adapters = strtok(mask, ",");
domains = strtok(NULL, ",");
controls = strtok(NULL, ",");
util_assert((!strtok(NULL, ",")) && adapters && domains && controls,
"Invalid ap_config attribute encountered %s", value);
/*
* ap_config overwrites the current list of adapters, domains and
* control domains. Clear the current lists before generating new ones
* based upon the input mask values.
*/
ap_list_remove_all(dev->adapters);
ap_list_remove_all(dev->domains);
ap_list_remove_all(dev->controls);
ap_mask_to_list(adapters, dev->adapters);
ap_mask_to_list(domains, dev->domains);
ap_mask_to_list(controls, dev->controls);
}
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
const char *value)
{
@@ -126,6 +163,8 @@ static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
modify_device_attr(dev->domains, v);
else if (strcmp(attr, "assign_control_domain") == 0)
modify_device_attr(dev->controls, v);
else if (strcmp(attr, "ap_config") == 0)
modify_device_ap_config(dev, v);
free(v);
}
@@ -413,6 +452,28 @@ void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control)
}
}
/**
* Determine if the specified device is currently active. If so, see if
* it is enabled for dynamic configuration support.
*
* @param[in] dev Vfio-ap struct
*
* @retval True Device is active and enabled for dynamic config
* @retval False Device is not active OR no dynamic config support
*/
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev)
{
char *attr = path_get_vfio_ap_attr(dev->uuid, "ap_config");
if (!attr)
return false;
if (!util_path_is_readable(attr))
return false;
return true;
}
#ifdef HAVE_JSONC
/**
@@ -689,7 +750,7 @@ void ap_mask_to_list(char *mask, struct util_list *list)
*/
void ap_list_remove_all(struct util_list *list)
{
struct ap_node *node;
struct vfio_ap_node *node;
while (!util_list_is_empty(list)) {
node = util_list_start(list);
@@ -698,6 +759,104 @@ void ap_list_remove_all(struct util_list *list)
}
}
static unsigned int random_delay(void)
{
static bool libap_seed = true;
struct timeval t;
if (libap_seed) {
gettimeofday(&t, NULL);
srand((unsigned int)((t.tv_sec + t.tv_usec) % UINT_MAX));
libap_seed = false;
}
return AP_LOCK_DELAY_US + (rand() % AP_LOCK_VARIANCE_US);
}
/**
* Return a mask of assigned adapters for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get adapter mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Adapter mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->adapters, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->domains, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned control domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get control domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Control domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->controls, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Acquire the ap config lock using this Process ID
*
@@ -707,7 +866,9 @@ void ap_list_remove_all(struct util_list *list)
*/
int ap_get_lock(void)
{
return util_lockfile_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
unsigned int delay = random_delay();
return util_lockfile_lock_cw(AP_LOCKFILE, AP_LOCK_RETRIES, delay, delay);
}
/**
@@ -719,7 +880,10 @@ int ap_get_lock(void)
*/
int ap_get_lock_callout(void)
{
return util_lockfile_parent_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
unsigned int delay = random_delay();
return util_lockfile_parent_lock_cw(AP_LOCKFILE, AP_LOCK_RETRIES, delay,
delay);
}
/**

View File

@@ -1084,8 +1084,6 @@ int kmip_connection_new(const struct kmip_conn_config *config,
return -EINVAL;
}
break;
break;
default:
kmip_debug(debug, "Invalid encoding: %d", config->encoding);
return -EINVAL;

View File

@@ -89,7 +89,7 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
} else {
n->type = kmip_type_by_name_or_hex(type_attr);
if (n->type == 0) {
kmip_debug(debug, "Unknown 'type' in JSON object: '%s'",
kmip_debug(debug, "Unknown 'type' in XML object: '%s'",
type_attr);
rc = -EBADMSG;
goto out;
@@ -361,7 +361,7 @@ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug)
while (element != NULL) {
rc = kmip_encode_xml(element, &elem_xml, debug);
if (rc != 0) {
kmip_debug(debug, "kmip_encode_json failed");
kmip_debug(debug, "kmip_encode_xml failed");
goto out;
}
if (xmlAddChild(ret_xml, elem_xml) == NULL) {

View File

@@ -9,10 +9,7 @@ GLIB2_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcrypto)
LIBCRYPTO_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
LIBCURL_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcurl)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS)
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
@@ -24,18 +21,15 @@ WARNINGS := -Wall -Wextra -Wshadow \
ALL_CFLAGS += -DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \
$(WARNINGS) \
$(NULL)
BUILD_TARGETS := skip-$(LIB)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL},0)
BUILD_TARGETS := $(LIB)
endif
endif
endif
sources := $(wildcard *.c)
objects := $(patsubst %.c,%.o,$(sources))
@@ -82,9 +76,4 @@ skip-$(LIB):
"openssl-devel / libssl-dev version >= 1.1.1", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(LIB)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +0,0 @@
/*
* Libpv common functions.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*/
/* Must be included before any other header */
#include "config.h"
#include "libpv/common.h"
#include "libpv/cert.h"
#include "libpv/curl.h"
/* setup and tear down */
int pv_init(void)
{
static size_t openssl_initalized;
if (g_once_init_enter(&openssl_initalized)) {
if (OPENSSL_VERSION_NUMBER < 0x1000100fL)
g_assert_not_reached();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
SSL_load_error_strings();
#else
OPENSSL_init_crypto(0, NULL);
#endif
if (pv_curl_init() != 0)
return -1;
pv_cert_init();
g_once_init_leave(&openssl_initalized, 1);
}
return 0;
}
void pv_cleanup(void)
{
pv_cert_cleanup();
pv_curl_cleanup();
}

View File

@@ -17,7 +17,6 @@
#include "lib/zt_common.h"
#include "libpv/crypto.h"
#include "libpv/glib-helper.h"
#include "libpv/hash.h"
char *pv_get_openssl_errors(void)
{
@@ -46,59 +45,6 @@ int pv_BIO_reset(BIO *b)
return 1;
}
GBytes *pv_generate_rand_data(size_t size, GError **error)
{
g_autofree uint8_t *data = NULL;
if (size > INT_MAX) {
g_set_error_literal(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_RANDOMIZATION,
"Too many random data requested. Split it up");
OPENSSL_clear_free(data, size);
return NULL;
}
data = g_malloc(size);
if (RAND_bytes(data, (int)size) != 1) {
g_set_error_literal(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_RANDOMIZATION,
"The required amount of random data is not available");
return NULL;
}
return pv_sec_gbytes_new_take(g_steal_pointer(&data), size);
}
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error)
{
int size;
pv_wrapped_g_assert(cipher);
size = EVP_CIPHER_key_length(cipher);
if (size <= 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
"Unknown cipher");
return NULL;
}
return pv_generate_rand_data((guint)size, error);
}
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error)
{
int size;
pv_wrapped_g_assert(cipher);
size = EVP_CIPHER_iv_length(cipher);
if (size <= 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
"Unknown cipher");
return NULL;
}
return pv_generate_rand_data((guint)size, error);
}
static int64_t pv_gcm_encrypt_decrypt(GBytes *input, GBytes *aad, const PvCipherParms *parms,
GBytes **output, GBytes **tagp, enum PvCryptoMode mode,
GError **error)
@@ -360,168 +306,6 @@ GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *
return pv_sec_gbytes_new_take(g_steal_pointer(&derived_key), derived_key_len);
}
EVP_PKEY *pv_generate_ec_key(int nid, GError **error)
{
g_autoptr(EVP_PKEY_CTX) ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
g_autoptr(EVP_PKEY) ret = NULL;
g_assert(ctx);
if (EVP_PKEY_keygen_init(ctx) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
if (EVP_PKEY_keygen(ctx, &ret) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
return g_steal_pointer(&ret);
}
/* Convert a EVP_PKEY to the key format used in the PV header */
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error)
{
g_autofree PvEcdhPubKey *ret = g_new0(PvEcdhPubKey, 1);
g_autoptr(BIGNUM) pub_x_big = NULL, pub_y_big = NULL;
g_autoptr(EC_KEY) ec_key = NULL;
const EC_POINT *pub_key;
const EC_GROUP *grp;
pv_wrapped_g_assert(key);
ec_key = EVP_PKEY_get1_EC_KEY(key);
if (!ec_key) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key has the wrong type"));
return NULL;
}
pub_key = EC_KEY_get0_public_key(ec_key);
if (!pub_key) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Failed to get public key"));
return NULL;
}
grp = EC_KEY_get0_group(ec_key);
if (!grp) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Failed to get EC group"));
return NULL;
}
pub_x_big = BN_new();
if (!pub_x_big)
g_abort();
pub_y_big = BN_new();
if (!pub_y_big)
g_abort();
if (EC_POINT_get_affine_coordinates_GFp(grp, pub_key, pub_x_big, pub_y_big, NULL) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
if (BN_bn2binpad(pub_x_big, ret->x, sizeof(ret->x)) < 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
if (BN_bn2binpad(pub_y_big, ret->y, sizeof(ret->y)) < 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
return g_steal_pointer(&ret);
}
static GBytes *derive_key(EVP_PKEY *key1, EVP_PKEY *key2, GError **error)
{
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
uint8_t *data = NULL;
size_t data_size, key_size;
ctx = EVP_PKEY_CTX_new(key1, NULL);
if (!ctx)
g_abort();
if (EVP_PKEY_derive_init(ctx) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key derivation failed"));
return NULL;
}
if (EVP_PKEY_derive_set_peer(ctx, key2) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key derivation failed"));
return NULL;
}
/* Determine buffer length */
if (EVP_PKEY_derive(ctx, NULL, &key_size) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
return NULL;
}
data_size = key_size;
data = OPENSSL_malloc(data_size);
if (!data)
g_abort();
if (EVP_PKEY_derive(ctx, data, &data_size) != 1) {
OPENSSL_clear_free(data, data_size);
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
return NULL;
}
g_assert(data_size == key_size);
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
}
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error)
{
const guint8 append[] = { 0x00, 0x00, 0x00, 0x01 };
g_autoptr(GBytes) derived_key = NULL, ret = NULL;
g_autoptr(GByteArray) der_key_ga = NULL;
g_autofree uint8_t *raw = NULL;
size_t raw_len;
pv_wrapped_g_assert(cust);
pv_wrapped_g_assert(host);
derived_key = derive_key(cust, host, error);
if (!derived_key)
return NULL;
der_key_ga = g_bytes_unref_to_array(g_steal_pointer(&derived_key));
/* ANSI X.9.63-2011: 66 bytes x with leading 7 bits and
* concatenate 32 bit int '1'
*/
der_key_ga = g_byte_array_append(der_key_ga, append, sizeof(append));
/* free GBytesArray and get underlying data */
raw_len = der_key_ga->len;
raw = g_byte_array_free(g_steal_pointer(&der_key_ga), FALSE);
ret = pv_sha256_hash(raw, raw_len, error);
OPENSSL_cleanse(raw, raw_len);
return g_steal_pointer(&ret);
}
GQuark pv_crypto_error_quark(void)
{
return g_quark_from_static_string("pv-crypto-error-quark");

View File

@@ -1,116 +0,0 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include <curl/curl.h>
#include <stdio.h>
#include "lib/zt_common.h"
#include "libpv/curl.h"
struct UserData {
GByteArray *buffer;
uint max_size;
};
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
g_assert(userdata);
struct UserData *data = (struct UserData *)userdata;
GByteArray *buffer = data->buffer;
uint64_t actual_size;
size_t err;
g_assert(buffer);
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
g_abort();
/* Signal an error condition by returning a amount that differs
* from the amount passed to the callback. This results in a
* CURLE_WRITE_ERROR.
*/
err = actual_size + 1;
if (actual_size > G_MAXUINT)
return err;
data->buffer = g_byte_array_append(buffer, (uint8_t *)ptr, (uint)actual_size);
if (data->buffer->len > data->max_size)
return err;
return actual_size;
}
int pv_curl_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
return -1;
return 0;
}
void pv_curl_cleanup(void)
{
curl_global_cleanup();
}
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err)
{
g_autoptr(GByteArray) ret = NULL;
g_autoptr(CURL) handle = NULL;
g_autofree char *agent = NULL;
struct UserData userdata;
CURLcode rc;
/* set up curl session */
handle = curl_easy_init();
if (!handle)
g_abort();
/* follow redirection */
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
if (rc != CURLE_OK)
goto curl_err;
agent = g_strdup_printf("%s/%s", GETTEXT_PACKAGE, RELEASE_STRING);
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
if (rc != CURLE_OK)
goto curl_err;
ret = g_byte_array_new();
userdata.buffer = ret;
userdata.max_size = max_size;
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_perform(handle);
if (rc != CURLE_OK) {
g_set_error(err, PV_CURL_ERROR, PV_CURL_ERROR_DOWNLOAD_FAILED,
_("download failed: %s"), curl_easy_strerror(rc));
return NULL;
}
return g_steal_pointer(&ret);
curl_err:
g_set_error(err, PV_CURL_ERROR, PV_CURL_ERROR_CURL_INIT_FAILED,
_("cURL initialization failed: %s"), curl_easy_strerror(rc));
return NULL;
}

View File

@@ -1,153 +0,0 @@
/*
* Hashing functions.
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include "libpv/crypto.h"
#include "libpv/hash.h"
GBytes *pv_sha256_hash(uint8_t *buf, size_t size, GError **error)
{
g_autoptr(EVP_MD_CTX) ctx = NULL;
ctx = pv_digest_ctx_new(EVP_sha256(), error);
if (!ctx)
return NULL;
if (pv_digest_ctx_update_raw(ctx, buf, size, error) != 0)
return NULL;
return pv_digest_ctx_finalize(ctx, error);
}
EVP_MD_CTX *pv_digest_ctx_new(const EVP_MD *md, GError **error)
{
g_autoptr(EVP_MD_CTX) ctx = EVP_MD_CTX_new();
if (!ctx) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("Hash context generation failed"));
return NULL;
}
if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestInit_ex failed"));
return NULL;
}
return g_steal_pointer(&ctx);
}
int pv_digest_ctx_update_raw(EVP_MD_CTX *ctx, const uint8_t *buf, size_t size, GError **error)
{
if (!buf || size == 0)
return 0;
if (EVP_DigestUpdate(ctx, buf, size) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
return -1;
}
return 0;
}
int pv_digest_ctx_update(EVP_MD_CTX *ctx, GBytes *data, GError **error)
{
const uint8_t *buf;
size_t buf_size;
if (!data)
return 0;
buf = g_bytes_get_data((GBytes *)data, &buf_size);
return pv_digest_ctx_update_raw(ctx, buf, buf_size, error);
}
GBytes *pv_digest_ctx_finalize(EVP_MD_CTX *ctx, GError **error)
{
int md_size = EVP_MD_size(EVP_MD_CTX_md(ctx));
g_autofree uint8_t *digest = NULL;
unsigned int digest_size;
g_assert(md_size > 0);
digest = g_malloc0((uint)md_size);
if (EVP_DigestFinal_ex(ctx, digest, &digest_size) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestFinal_ex failed"));
return NULL;
}
g_assert(digest_size == (uint)md_size);
return g_bytes_new_take(g_steal_pointer(&digest), digest_size);
}
HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error)
{
g_autoptr(HMAC_CTX) ctx = HMAC_CTX_new();
const uint8_t *key_data;
size_t key_size;
key_data = g_bytes_get_data(key, &key_size);
if (HMAC_Init_ex(ctx, key_data, (int)key_size, md, NULL) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to create HMAC context: %s", openssl_err_msg);
return NULL;
}
return g_steal_pointer(&ctx);
}
int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *buf, size_t size, GError **error)
{
if (!buf || size == 0)
return 0;
if (HMAC_Update(ctx, buf, size) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to add data to HMAC context: %s", openssl_err_msg);
return -1;
}
return 0;
}
int pv_hmac_ctx_update(HMAC_CTX *ctx, GBytes *data, GError **error)
{
const uint8_t *buf;
size_t buf_size;
if (!data)
return 0;
buf = g_bytes_get_data((GBytes *)data, &buf_size);
return pv_hmac_ctx_update_raw(ctx, buf, buf_size, error);
}
GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error)
{
int md_size = EVP_MD_size(HMAC_CTX_get_md(ctx));
g_autofree uint8_t *hmac = NULL;
unsigned int hmac_size = 0;
g_assert(md_size > 0);
hmac = g_malloc0((unsigned int)md_size);
if (HMAC_Final(ctx, hmac, &hmac_size) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to calculate HMAC: %s", openssl_err_msg);
return NULL;
}
return g_bytes_new_take(g_steal_pointer(&hmac), hmac_size);
}

View File

@@ -90,10 +90,10 @@ const char *util_arch_machine_type_to_str(int type)
case UTIL_ARCH_MACHINE_TYPE_Z14_ZR1:
return "IBM z14 ZR1";
case UTIL_ARCH_MACHINE_TYPE_Z15:
return "IBM z15";
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
return "IBM z15 Model T02";
return "IBM z15";
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
return "IBM z16";
default:
return "Unknown machine type";
@@ -111,6 +111,7 @@ unsigned long util_arch_hsa_maxsize(void)
case UTIL_ARCH_MACHINE_TYPE_Z15:
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
return HSA_SIZE_512M;
default:
return HSA_SIZE_32M;

View File

@@ -27,7 +27,7 @@ void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int grp,
for (i = 0; i < count; i++) {
if (first) {
fprintf(fh, "%*s", indent, " ");
fprintf(fh, "%*s", indent, "");
if (tag)
fprintf(fh, "%s: ", tag);
fprintf(fh, "%08x: ", i);

View File

@@ -110,7 +110,8 @@ static int file_puts(const char *str, const char *path)
}
rc = 0;
out_fclose:
fclose(fp);
if (fclose(fp))
return -1;
return rc;
}

771
libutil/util_fmt.c Normal file
View File

@@ -0,0 +1,771 @@
/*
* util - Utility function library
*
* Format structured data as key-value pairs, JSON, or CSV
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "lib/util_rec.h"
#include "lib/zt_common.h"
struct obj_t {
char *name;
bool is_list;
bool is_row;
bool is_prefix;
unsigned int index;
};
struct key_t {
char *name;
bool persist;
};
static struct {
enum util_fmt_t type;
FILE *fd;
int fileno;
/* Format control. */
bool hide_prefix;
bool hide_inval;
bool quote_all;
bool do_filter;
bool do_warn;
bool hide_meta;
bool handle_int;
int api_level;
const char *nl;
/* JSON specifics. */
unsigned int ind_base;
unsigned int ind_width;
char ind_char;
bool meta_done;
/* CSV specifics. */
struct util_rec *csv_rec;
bool csv_hdr;
bool csv_data;
/* State. */
unsigned int lvl;
struct obj_t *objs;
unsigned int num_objs;
struct key_t *keys;
unsigned int num_keys;
struct sigaction old_int;
struct sigaction old_term;
/* Methods. */
void (*obj_start)(struct obj_t *parent, struct obj_t *obj);
void (*obj_end)(struct obj_t *parent, struct obj_t *obj);
void (*map)(struct obj_t *parent, unsigned int mflags, const char *key,
const char *val);
void (*term)(void);
} f;
#define fwarn(fmt, ...) \
do { if (f.do_warn) warnx(fmt, ##__VA_ARGS__); } while (0)
/* Map format name to format ID. */
static const struct {
const char *name;
enum util_fmt_t fmt;
} formats[] = {
{ "json", FMT_JSON },
{ "json-seq", FMT_JSONSEQ },
{ "pairs", FMT_PAIRS },
{ "csv", FMT_CSV },
};
/* Signal mask for blocking INT and TERM signals. */
static sigset_t no_int_mask;
bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (strcasecmp(name, formats[i].name) == 0) {
*type = formats[i].fmt;
return true;
}
}
return false;
}
static void safe_write(const char *str)
{
size_t done, todo;
ssize_t rc;
if (f.fileno < 0)
return;
for (done = 0; (todo = strlen(&str[done])) > 0; done += (size_t)rc) {
rc = write(f.fileno, &str[done], todo);
if (rc <= 0)
return;
}
}
static void _indent(unsigned int off, bool safe)
{
unsigned int num, i;
if (f.type == FMT_JSONSEQ)
return;
num = f.ind_base + off;
if (f.type == FMT_JSON && f.lvl > 0)
num += f.lvl - 1;
for (i = 0; i < num * f.ind_width; i++) {
if (!safe) {
fputc(f.ind_char, f.fd);
} else if (f.fileno >= 0) {
if (write(f.fileno, &f.ind_char, 1) <= 0)
return;
}
}
}
#define indent(x) _indent(x, false)
static void obj_free(struct obj_t *obj)
{
free(obj->name);
memset(obj, 0, sizeof(*obj));
}
static void disable_int(sigset_t *saved)
{
if (f.handle_int)
sigprocmask(SIG_BLOCK, &no_int_mask, saved);
}
static void enable_int(sigset_t *saved)
{
if (f.handle_int) {
/* Ensure latest updates are flushed to file descriptor. */
fflush(f.fd);
sigprocmask(SIG_SETMASK, saved, NULL);
}
}
static void int_handler(int signum)
{
struct sigaction *old;
if (f.term)
f.term();
/* Re-install and call original handler. */
old = (signum == SIGINT) ? &f.old_int : &f.old_term;
sigaction(signum, old, NULL);
raise(signum);
}
static void setup_int_handler(void)
{
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = &int_handler;
sigaction(SIGINT, &act, &f.old_int);
sigaction(SIGTERM, &act, &f.old_term);
}
static void remove_int_handler(void)
{
sigaction(SIGINT, &f.old_int, NULL);
sigaction(SIGTERM, &f.old_term, NULL);
}
void util_fmt_exit(void)
{
unsigned int i;
if (f.handle_int)
remove_int_handler();
if (f.lvl > 0)
fwarn("%s before remaining %d util_obj_end()", __func__, f.lvl);
for (i = 0; i < f.num_keys; i++)
free(f.keys[i].name);
free(f.keys);
for (i = 0; i < f.num_objs; i++)
obj_free(&f.objs[i]);
free(f.objs);
if (f.type == FMT_CSV)
util_rec_free(f.csv_rec);
}
void util_fmt_set_indent(unsigned int base, unsigned int width, char ind_char)
{
f.ind_base = base;
f.ind_width = width;
f.ind_char = ind_char;
}
static unsigned int to_hex(char *str, int val, unsigned int num_digits)
{
int digit;
char *c;
for (c = str + num_digits - 1; c >= str; c--) {
digit = (val & 0xf);
val >>= 4;
*c = (char)((digit >= 10) ? digit - 10 + 'a' : digit + '0');
}
return num_digits;
}
static char get_escape(const char *map, char c)
{
int i;
for (i = 0; map[i] && map[i + 1]; i += 2) {
if (map[i] == c)
return map[i + 1];
}
return 0;
}
struct quote_params {
const char *double_chars;
const char *esc_map;
char hex_char;
unsigned int hex_digits;
unsigned int max_width_per_char;
};
static char *do_quote(const char *str, const struct quote_params *p)
{
unsigned int from, to;
char *q, esc, c;
/* Start with worst-case length assuming every char is replaced. */
q = util_zalloc(strlen(str) * p->max_width_per_char + /* "" nul */ 3);
to = 0;
q[to++] = '"';
for (from = 0; (c = str[from]); from++) {
if (p->double_chars && strchr(p->double_chars, c)) {
/* Escape characters by doubling them ("" in CSV). */
q[to++] = c;
q[to++] = c;
} else if (p->esc_map && (esc = get_escape(p->esc_map, c))) {
/* Escape characters with backslash + letter. */
q[to++] = '\\';
q[to++] = esc;
} else if (p->hex_char && !isprint(c)) {
/* Escape characters with backslash + hex code. */
q[to++] = '\\';
q[to++] = p->hex_char;
to += to_hex(&q[to], c, p->hex_digits);
} else {
q[to++] = c;
}
}
q[to++] = '"';
return util_realloc(q, (size_t)to + 1);
}
static char *csv_quote(const char *str)
{
static const struct quote_params csv_quote_params = {
.double_chars = "\"",
.esc_map = NULL,
.hex_char = 0,
.hex_digits = 0,
.max_width_per_char = 2 /* " => "" */,
};
return do_quote(str, &csv_quote_params);
}
static void add_key(const char *name, bool persist)
{
struct key_t key;
char *hdr;
key.name = util_strdup(name);
key.persist = persist;
util_add_array(&f.keys, &f.num_keys, key);
if (f.type == FMT_CSV) {
hdr = csv_quote(name);
util_rec_def(f.csv_rec, name, UTIL_REC_ALIGN_LEFT, 0, hdr);
free(hdr);
util_rec_set(f.csv_rec, name, "\"\"");
f.csv_hdr = true;
}
}
static struct key_t *get_key(const char *name)
{
unsigned int i;
for (i = 0; i < f.num_keys; i++) {
if (strcmp(name, f.keys[i].name) == 0)
return &f.keys[i];
}
return NULL;
}
void util_fmt_add_key(const char *fmt, ...)
{
va_list args;
char *key;
va_start(args, fmt);
util_vasprintf(&key, fmt, args);
va_end(args);
/* Only add unique keys. */
if (!get_key(key))
add_key(key, true);
free(key);
}
static bool update_key(const char *name, bool persist)
{
struct key_t *key;
bool rc = true;
key = get_key(name);
if (key) {
key->persist = persist;
} else if (!f.do_filter) {
add_key(name, persist);
} else {
fwarn("util_fmt_pair for key '%s' without util_fmt_add_key()",
name);
rc = false;
}
return rc;
}
static struct obj_t *curr_obj(int off)
{
int lvl = (int)f.lvl - 1 + off;
return lvl < 0 ? NULL : &f.objs[lvl];
}
static void _util_fmt_obj_end(void);
/*
* By s390-tools convention, all tool output must be contained in an extra
* top-level object that includes tool-invocation meta-data.
*/
static void emit_meta_object(void)
{
unsigned int quoted = FMT_PERSIST | FMT_QUOTE, unquoted = FMT_PERSIST;
char hostname[HOST_NAME_MAX + 1] = { 0 }, date[30];
struct timeval tv;
struct tm *tm;
f.meta_done = true;
util_fmt_obj_start(FMT_DEFAULT, NULL);
util_fmt_obj_start(FMT_PREFIX, "meta");
/*
* "meta": {
* "api_level": 1,
* "version": "2.32.0",
* "host": "localhost",
* "time_epoch": 1714392976,
* "time": "2024-04-29 14:16:16+0200",
* }
*/
util_fmt_pair(unquoted, "api_level", "%d", f.api_level);
util_fmt_pair(quoted, "version", "%s", RELEASE_STRING);
gethostname(hostname, sizeof(hostname) - 1);
util_fmt_pair(quoted, "host", "%s", hostname);
gettimeofday(&tv, NULL);
util_fmt_pair(unquoted, "time_epoch", "%llu", tv.tv_sec);
tm = localtime(&tv.tv_sec);
if (!strftime(date, sizeof(date), "%F %T%z", tm))
date[0] = 0;
util_fmt_pair(quoted, "time", "%s", date);
_util_fmt_obj_end();
if (f.type == FMT_JSONSEQ) {
/* Tool meta-data is a separate object for JSONSEQ. */
util_fmt_obj_end();
}
}
void util_fmt_obj_start(unsigned int oflags, const char *fmt, ...)
{
struct obj_t *parent, *obj;
char *name = NULL;
sigset_t set;
va_list args;
if (!f.hide_meta && !f.meta_done && f.lvl == 0) {
emit_meta_object();
/*
* Allow override of top-level key name for supplementary
* output formats.
*/
if (!fmt)
name = util_strdup(program_invocation_short_name);
}
if (fmt) {
va_start(args, fmt);
util_vasprintf(&name, fmt, args);
va_end(args);
}
f.lvl++;
if (f.lvl > f.num_objs)
util_expand_array(&f.objs, &f.num_objs);
parent = curr_obj(-1);
obj = curr_obj(0);
obj->name = name;
obj->is_list = (oflags & FMT_LIST);
obj->is_row = (oflags & FMT_ROW);
obj->is_prefix = (oflags & FMT_PREFIX);
obj->index = 0;
if (f.obj_start) {
disable_int(&set);
f.obj_start(parent, obj);
enable_int(&set);
}
if (parent)
parent->index++;
}
static void _util_fmt_obj_end(void)
{
struct obj_t *obj, *parent;
sigset_t set;
if (f.lvl == 0) {
fwarn("%s without util_fmt_obj_start", __func__);
return;
}
parent = curr_obj(-1);
obj = curr_obj(0);
if (f.obj_end) {
disable_int(&set);
f.obj_end(parent, obj);
enable_int(&set);
}
f.lvl--;
obj_free(obj);
}
void util_fmt_obj_end(void)
{
_util_fmt_obj_end();
if (f.lvl == 1 && f.meta_done && f.type != FMT_JSONSEQ) {
/* Emit closure for top-level meta-container object. */
util_fmt_obj_end();
}
}
static char *add_prefix(const char *str, bool full)
{
struct obj_t *obj;
unsigned int i;
char *prefix;
prefix = util_strdup("");
for (i = 0; i < f.lvl; i++) {
obj = &f.objs[i];
if (!full && !obj->is_prefix)
continue;
if (obj->name) {
if (*prefix)
util_concatf(&prefix, ".");
util_concatf(&prefix, "%s", obj->name);
}
if (obj->is_list && full)
util_concatf(&prefix, "[%d]", obj->index - 1);
}
if (*prefix)
util_concatf(&prefix, ".");
util_concatf(&prefix, "%s", str);
return prefix;
}
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...)
{
char *val, *prefixed_key;
struct obj_t *obj;
bool is_filtered;
sigset_t set;
va_list args;
obj = curr_obj(0);
if (!obj) {
fwarn("%s before util_fmt_obj_start", __func__);
return;
}
/* Filter by key. */
if (f.do_filter) {
prefixed_key = add_prefix(key, false);
is_filtered = !get_key(prefixed_key);
free(prefixed_key);
if (is_filtered)
return;
}
/* Filter by validity. */
if (f.hide_inval && (mflags & FMT_INVAL))
return;
va_start(args, fmt);
util_vasprintf(&val, fmt, args);
va_end(args);
if (f.map) {
disable_int(&set);
f.map(obj, mflags, key, val);
enable_int(&set);
}
obj->index++;
free(val);
}
static char *pairs_quote(const char *str)
{
static const struct quote_params pairs_quote_params = {
.double_chars = NULL,
.esc_map = "\"\"$$``\\\\\aa\bb\ee\ff\nn\rr\tt\vv",
.hex_char = 'x',
.hex_digits = 2,
.max_width_per_char = 4 /* '\x' + 2 hex_digits */,
};
return do_quote(str, &pairs_quote_params);
}
static void pairs_map(struct obj_t *UNUSED(obj), unsigned int mflags,
const char *key, const char *val)
{
char *full_key, *qval = NULL;
if (mflags & FMT_INVAL)
val = "";
indent(0);
if (f.quote_all || (mflags & FMT_QUOTE))
qval = pairs_quote(val);
if (f.hide_prefix) {
fprintf(f.fd, "%s=%s\n", key, qval ?: val);
} else {
full_key = add_prefix(key, true);
fprintf(f.fd, "%s=%s\n", full_key, qval ?: val);
free(full_key);
}
free(qval);
}
static char *json_quote(const char *str)
{
static const struct quote_params json_quote_params = {
.double_chars = NULL,
.esc_map = "\"\"\\\\\bb\ff\nn\rr\tt",
.hex_char = 'u',
.hex_digits = 4,
.max_width_per_char = 6 /* '\u' + 4 hex_digits */,
};
return do_quote(str, &json_quote_params);
}
static void json_obj_start(struct obj_t *parent, struct obj_t *obj)
{
char *key;
if (!parent && f.type == FMT_JSONSEQ) {
/* Emit leading record separator according to RFC 7464. */
fprintf(f.fd, "\x1e");
}
if (parent && parent->index > 0)
fprintf(f.fd, ",%s", f.nl);
indent(0);
if (parent && !parent->is_list && obj->name) {
key = json_quote(obj->name);
fprintf(f.fd, "%s: ", key);
free(key);
}
fprintf(f.fd, obj->is_list ? "[%s" : "{%s", f.nl);
}
static void json_obj_end(struct obj_t *parent, struct obj_t *obj)
{
if (obj->index > 0)
fprintf(f.fd, "%s", f.nl);
indent(0);
fprintf(f.fd, obj->is_list ? "]" : "}");
if (!parent)
fprintf(f.fd, "\n");
}
/*
* Ensure syntactically correct JSON by emitting all pending closure elements.
* Called in signal context - only use signal-safe functions.
*/
static void json_term(void)
{
struct obj_t *obj, *parent;
for (; f.lvl > 0; f.lvl--) {
obj = curr_obj(0);
parent = curr_obj(-1);
if (obj->index > 0)
safe_write(f.nl);
_indent(0, true);
safe_write(obj->is_list ? "]" : "}");
if (!parent)
safe_write(f.nl);
}
}
static void json_map(struct obj_t *parent, unsigned int mflags,
const char *key, const char *val)
{
char *qkey, *qval = NULL;
qkey = json_quote(key);
if (mflags & FMT_INVAL)
qval = util_strdup("null");
else if (f.quote_all || (mflags & FMT_QUOTE))
qval = json_quote(val);
if (parent->index > 0)
fprintf(f.fd, ",%s", f.nl);
indent(1);
fprintf(f.fd, "%s: %s", qkey, qval ?: val);
free(qval);
free(qkey);
}
static void csv_obj_start(struct obj_t *UNUSED(parent), struct obj_t *obj)
{
if (!obj->is_row)
return;
}
static void csv_obj_end(struct obj_t *UNUSED(parent), struct obj_t *obj)
{
unsigned int i;
if (!(obj->is_row || (f.lvl == 1 && f.csv_data)))
return;
if (f.csv_hdr) {
/* Print row with CSV header. */
indent(0);
util_rec_print_hdr(f.csv_rec);
f.csv_hdr = false;
}
/* Print row with CSV data. */
indent(0);
util_rec_print(f.csv_rec);
f.csv_data = false;
/* Reset non-persistent fields. */
for (i = 0; i < f.num_keys; i++) {
if (!f.keys[i].persist)
util_rec_set(f.csv_rec, f.keys[i].name, "\"\"");
}
}
static void csv_map(struct obj_t *UNUSED(obj), unsigned int mflags,
const char *key, const char *val)
{
char *qval = NULL, *prefixed_key;
/* Use empty string for invalid values. */
if (mflags & FMT_INVAL)
val = "";
/* Quote value if requested. */
if (f.quote_all || (mflags & FMT_QUOTE))
qval = csv_quote(val);
/* Process key and value. */
prefixed_key = add_prefix(key, false);
if (update_key(prefixed_key, mflags & FMT_PERSIST)) {
util_rec_set(f.csv_rec, prefixed_key, "%s", qval ?: val);
f.csv_data = true;
}
free(prefixed_key);
free(qval);
}
static bool hide_meta_env(void)
{
char *v;
v = secure_getenv("FMT_NOMETA");
return (v && strcmp(v, "1") == 0);
}
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
int api_level)
{
memset(&f, 0, sizeof(f));
f.type = type;
f.fd = fd;
f.fileno = fileno(fd);
f.hide_prefix = (flags & FMT_NOPREFIX);
f.hide_inval = !(flags & FMT_KEEPINVAL);
f.hide_meta = (flags & FMT_NOMETA) || hide_meta_env();
f.quote_all = (flags & FMT_QUOTEALL);
f.do_filter = (flags & FMT_FILTER);
f.do_warn = (flags & FMT_WARN);
f.handle_int = (flags & FMT_HANDLEINT);
f.api_level = api_level;
if (type == FMT_JSONSEQ)
f.nl = "";
else
f.nl = "\n";
f.ind_width = 2;
f.ind_char = ' ';
f.meta_done = false;
switch (type) {
case FMT_PAIRS:
f.map = &pairs_map;
break;
case FMT_JSON:
case FMT_JSONSEQ:
f.obj_start = &json_obj_start;
f.obj_end = &json_obj_end;
f.map = &json_map;
f.term = &json_term;
break;
case FMT_CSV:
f.obj_start = &csv_obj_start;
f.obj_end = &csv_obj_end;
f.map = &csv_map;
f.csv_rec = util_rec_new_csv(",");
f.csv_hdr = true;
f.csv_data = false;
break;
}
/* Ensure consistent number format for callers that use setlocale(). */
setlocale(LC_NUMERIC, "C");
if (f.handle_int) {
setup_int_handler();
sigemptyset(&no_int_mask);
sigaddset(&no_int_mask, SIGINT);
sigaddset(&no_int_mask, SIGTERM);
}
}

251
libutil/util_fmt_example.c Normal file
View File

@@ -0,0 +1,251 @@
/*
* util_fmt_example - Example program for util_fmt
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include "lib/util_base.h"
#include "lib/util_fmt.h"
#define API_LEVEL 1
static void meta_example(enum util_fmt_t format)
{
util_fmt_init(stdout, format, FMT_DEFAULT, API_LEVEL);
/*
* First call to util_fmt_obj_start() automatically adds meta-data
* object as required by s390-tools convention.
*/
util_fmt_obj_start(FMT_DEFAULT, NULL);
util_fmt_pair(FMT_QUOTE, "key", "value");
util_fmt_obj_end();
util_fmt_exit();
}
static void simple_example(enum util_fmt_t format, int fmt_flags)
{
/*
* Note: Meta-data is excluded in this example for readability but
* must be included in actual tool output.
*/
util_fmt_init(stdout, format, fmt_flags | FMT_NOMETA, API_LEVEL);
/*
* {
* "child": {
* "key": "value",
* "invalid":"invalidvalue" <== Marked as invalid
* }
* }
*/
util_fmt_obj_start(FMT_DEFAULT, NULL);
util_fmt_obj_start(FMT_DEFAULT, "child");
util_fmt_pair(FMT_QUOTE, "key", "value");
util_fmt_pair(FMT_QUOTE | FMT_INVAL, "invalid", "invalidvalue");
util_fmt_obj_end();
util_fmt_obj_end();
util_fmt_exit();
}
static void list_example(enum util_fmt_t format, int flags)
{
int i;
/*
* Note: Meta-data is excluded in this example for readability but
* must be included in actual tool output.
*/
util_fmt_init(stdout, format, flags | FMT_NOMETA, API_LEVEL);
/*
* "cond","key"
* condvalue0,value0
* "",value1
* "",value2
* "",value3
*/
util_fmt_obj_start(FMT_DEFAULT, NULL);
util_fmt_obj_start(FMT_LIST, "list");
for (i = 0; i < 4; i++) {
util_fmt_obj_start(FMT_ROW, NULL);
if (i == 0)
util_fmt_pair(flags, "cond", "condvalue%d", i);
util_fmt_pair(FMT_DEFAULT, "key", "value%d", i);
util_fmt_obj_end();
}
util_fmt_obj_end();
util_fmt_obj_end();
util_fmt_exit();
}
#define NUM_KEYS 4
static void vary_example(enum util_fmt_t format, bool add)
{
const char *keys[NUM_KEYS] = { "key_a", "key_b", "key_c", "key_d" };
int i;
/*
* Note: Meta-data is excluded in this example for readability but
* must be included in actual tool output.
*/
util_fmt_init(stdout, format, FMT_NOMETA, API_LEVEL);
if (add) {
/* Make keys known before starting output. */
for (i = 0; i < NUM_KEYS; i++)
util_fmt_add_key(keys[i]);
}
util_fmt_obj_start(FMT_LIST, "list");
for (i = 0; i < 4; i++) {
util_fmt_obj_start(FMT_ROW, NULL);
util_fmt_pair(FMT_DEFAULT, keys[i], "value%d", i);
util_fmt_obj_end();
}
util_fmt_obj_end();
util_fmt_exit();
}
static void filter_example(enum util_fmt_t format)
{
/*
* Note: Meta-data is excluded in this example for readability but
* must be included in actual tool output.
*/
util_fmt_init(stdout, format, FMT_FILTER | FMT_NOMETA, API_LEVEL);
util_fmt_add_key("key_a");
/*
* {
* "key_a": "value_a",
* "key_b": "value_b" <== Not announced via util_fmt_add_key()
* }
*/
util_fmt_obj_start(FMT_DEFAULT, NULL);
util_fmt_pair(FMT_QUOTE, "key_a", "value_a");
util_fmt_pair(FMT_QUOTE, "key_b", "value_b");
util_fmt_obj_end();
util_fmt_exit();
}
static void prefix_example(enum util_fmt_t format, bool do_prefix)
{
/*
* Note: Meta-data is excluded in this example for readability but
* must be included in actual tool output.
*/
util_fmt_init(stdout, format, FMT_NOMETA, API_LEVEL);
/*
* {
* "key": "value0",
* "obj1": { // Marked as prefix object
* "key": "value1"
* }
* }
*/
util_fmt_obj_start(FMT_DEFAULT, "obj0");
util_fmt_pair(FMT_QUOTE, "key", "value0");
util_fmt_obj_start(do_prefix ? FMT_PREFIX : FMT_DEFAULT, "obj1");
util_fmt_pair(FMT_QUOTE, "key", "value1");
util_fmt_obj_end();
util_fmt_obj_end();
util_fmt_exit();
}
static void announce(const char *example_name)
{
static int example_number;
int i;
if (example_number++ > 0)
printf("\n");
printf("%d. %s\n====", example_number, example_name);
for (i = strlen(example_name); i > 0; i--)
printf("=");
printf("\n");
}
int main(int UNUSED(argc), char *UNUSED(argv[]))
{
announce("JSON output");
simple_example(FMT_JSON, FMT_KEEPINVAL);
announce("JSON without invalid pairs");
simple_example(FMT_JSON, FMT_DEFAULT);
announce("JSON formatted as sequence");
simple_example(FMT_JSONSEQ, FMT_DEFAULT);
announce("Pairs output");
simple_example(FMT_PAIRS, FMT_KEEPINVAL);
announce("Pairs output without invalid pairs");
simple_example(FMT_PAIRS, FMT_DEFAULT);
announce("Pairs without prefix");
simple_example(FMT_PAIRS, FMT_NOPREFIX);
announce("CSV output");
simple_example(FMT_CSV, FMT_KEEPINVAL);
announce("CSV list output");
list_example(FMT_CSV, FMT_DEFAULT);
announce("CSV list with persistent cond value");
list_example(FMT_CSV, FMT_PERSIST);
announce("JSON with filtered key");
filter_example(FMT_JSON);
announce("Pairs with filtered key");
filter_example(FMT_PAIRS);
announce("CSV with filtered key");
filter_example(FMT_CSV);
announce("CSV list with varying keys");
vary_example(FMT_CSV, false);
announce("CSV list with pre-announced varying keys");
vary_example(FMT_CSV, true);
announce("JSON output with meta-data");
meta_example(FMT_JSON);
announce("JSON sequence output with meta-data");
meta_example(FMT_JSONSEQ);
announce("Pairs output with meta-data");
meta_example(FMT_PAIRS);
announce("CSV output with meta-data");
meta_example(FMT_CSV);
announce("JSON output with duplicate keys");
prefix_example(FMT_JSON, false);
announce("CSV output with duplicate keys");
prefix_example(FMT_CSV, false);
announce("CSV output with duplicate keys distinguished by prefix");
prefix_example(FMT_CSV, true);
return 0;
}

View File

@@ -139,6 +139,26 @@ char *util_strcat_realloc(char *str1, const char *str2)
return buf;
}
/**
* Concatenate a string with the result of a format string expansion
*
* @param[in, out] str1 Pointer to pointer to first string
* @param[in] fmt Format string for generation of the second string
* @param[in] ... Parameters for format string
*/
void util_concatf(char **str1, const char *fmt, ...)
{
va_list args;
char *str2;
va_start(args, fmt);
util_vasprintf(&str2, fmt, args);
va_end(args);
*str1 = util_strcat_realloc(*str1, str2);
free(str2);
}
/**
* Convert string to uppercase
*

View File

@@ -40,6 +40,14 @@ int main(void)
fprintf(stderr, "result = \"%s\"\n", str);
free(str);
/* Use util_concatf() for string concatenation */
fprintf(stderr, "Try to concatenate \"list\" plus comma-separated list of numbers 1 to 3: ");
str = NULL;
util_concatf(&str, "list:");
for (int i = 1; i <= 3; i++)
util_concatf(&str, "%s%d", (i > 1 ? "," : ""), i);
fprintf(stderr, "result = %s\n", str); /* list:part1,part2,part3 */
/* One byte allocation should work */
fprintf(stderr, "Try to allocate 1 byte: ");
ptr = util_malloc(1);

View File

@@ -25,8 +25,8 @@
#include "lib/util_panic.h"
#define WAITPID 120 /* Time to wait for pid to be written */
#define WAITINC 5 /* Additional time to wait each retry */
#define MAXWAIT 60 /* Maximum wait between retries */
#define DEF_WAITINC_US 5000000 /* Additional time to wait each retry */
#define DEF_MAXWAIT_US 60000000 /* Maximum wait between retries */
#define BUFSIZE 40 /* Buffer must be large enough to fit pid string */
/**
@@ -133,15 +133,20 @@ static int handle_stale_lock(char *lockfile)
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
* @param[in] waitinc How many micro-seconds to extend wait time before
* additional retry
* @param[in] maxwait Maximum wait time before retry
* @param[in] pid PID to use for lock ownership
*
* @retval 0 Lock created with PID as owner
* @retval !=0 Lock was not created
*/
static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid)
static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid,
unsigned int waitinc, unsigned int maxwait)
{
int fd, plen, len, rc = 0, snooze = 0;
unsigned int tries = retries + 1;
int fd, plen, len, rc = 0;
unsigned int snooze = 0;
char buf[BUFSIZE];
char *tpath;
@@ -190,9 +195,9 @@ static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid)
if (rc != 0) {
tries--;
if (tries > 0) {
snooze += WAITINC;
snooze = (snooze > MAXWAIT) ? MAXWAIT : snooze;
sleep(snooze);
snooze += waitinc;
snooze = (snooze > maxwait) ? maxwait : snooze;
usleep(snooze);
}
}
} while (tries > 0);
@@ -255,7 +260,27 @@ static int do_lockfile_release(char *lockfile, int pid)
*/
int util_lockfile_lock(char *lockfile, int retries)
{
return do_lockfile_lock(lockfile, retries, getpid());
return do_lockfile_lock(lockfile, retries, getpid(), DEF_WAITINC_US,
DEF_MAXWAIT_US);
}
/**
* Attempt to create a lockfile owned by this process at the specified path
* using a custom wait/retry time.
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
* @param[in] waitinc How many micro-seconds to extend wait time before
* additional retry
* @param[in] maxwait Maximum wait time before retry
*
* @retval 0 Lock created
* @retval !=0 Lock was not created
*/
int util_lockfile_lock_cw(char *lockfile, int retries, unsigned int waitinc,
unsigned int maxwait)
{
return do_lockfile_lock(lockfile, retries, getpid(), waitinc, maxwait);
}
/**
@@ -270,7 +295,27 @@ int util_lockfile_lock(char *lockfile, int retries)
*/
int util_lockfile_parent_lock(char *lockfile, int retries)
{
return do_lockfile_lock(lockfile, retries, getppid());
return do_lockfile_lock(lockfile, retries, getppid(), DEF_WAITINC_US,
DEF_MAXWAIT_US);
}
/**
* Attempt to create a lockfile owned by the parent of this process at the
* specified path using a custom wait/retry time.
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
* @param[in] waitinc How many micro-seconds to extend wait time before
* additional retry
* @param[in] maxwait Maximum wait time before retry
*
* @retval 0 Lock created
* @retval !=0 Lock was not created
*/
int util_lockfile_parent_lock_cw(char *lockfile, int retries,
unsigned int waitinc, unsigned int maxwait)
{
return do_lockfile_lock(lockfile, retries, getppid(), waitinc, maxwait);
}
/**

View File

@@ -111,7 +111,7 @@ const char *util_rec_fld_get_key(struct util_rec_fld *fld)
/**
* Create a new record with "wide" output format
*
* @param[in] hdr_sep Header separator
* @param[in] hdr_sep Header separator or %NULL for no separator
*
* @returns Pointer to the created record
*/
@@ -121,7 +121,7 @@ struct util_rec *util_rec_new_wide(const char *hdr_sep)
rec->list = util_list_new(struct util_rec_fld, node);
rec->fmt.type = REC_FMT_WIDE;
rec->fmt.d.wide_p.hdr_sep = util_strdup(hdr_sep);
rec->fmt.d.wide_p.hdr_sep = hdr_sep ? util_strdup(hdr_sep) : NULL;
rec->fmt.d.wide_p.argz_sep = ',';
rec->fmt.indent = 0;
return rec;
@@ -249,7 +249,7 @@ static void rec_free_wide(struct util_rec *rec)
/**
* Create a new record with "long" output format
*
* @param[in] hdr_sep Header separator
* @param[in] hdr_sep Header separator or %NULL for no separator
* @param[in] col_sep Column separator
* @param[in] key Primary key of record
* @param[in] key_size Width of left column i.e. keys
@@ -264,7 +264,7 @@ struct util_rec *util_rec_new_long(const char *hdr_sep, const char *col_sep,
rec->list = util_list_new(struct util_rec_fld, node);
rec->fmt.type = REC_FMT_LONG;
rec->fmt.d.long_p.hdr_sep = util_strdup(hdr_sep);
rec->fmt.d.long_p.hdr_sep = hdr_sep ? util_strdup(hdr_sep) : NULL;
rec->fmt.d.long_p.col_sep = util_strdup(col_sep);
rec->fmt.d.long_p.key = util_strdup(key);
rec->fmt.d.long_p.key_size = key_size;

View File

@@ -45,7 +45,7 @@ vmcmd: Trigger CP command according to the 'VMCMD_X' configuration in
.TP
\fB - DUMP_TYPE:\fR
Type of dump device. Possible values are 'ccw', 'fcp' and 'nvme'.
Type of dump device. Possible values are 'ccw', 'eckd', 'fcp' and 'nvme'.
.TP
\fB - DEVICE:\fR
@@ -71,10 +71,19 @@ Namespace ID for NVMe dump device.
\fB - BOOTPROG:\fR
Boot program selector.
.TP
\fB - BR_CHR:\fR
Boot record location in "C,H,R" format (comma separated values for
Cylinder, Head and Record) or "auto".
.TP
\fB - BR_LBA:\fR
Boot record logical block address.
.TP
\fB - SCP_DATA:\fR
SCP data for SCSI, NVMe and ECKD dump devices.
.TP
\fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR
Up to eight CP commands, which are executed in case of a kernel panic
@@ -146,6 +155,23 @@ DEVICE=0.0.1234
DELAY_MINUTES=5
.br
#
.br
# Example configuration for an ECKD dump device (DASD)
.br
#
.br
ON_PANIC=dump
.br
DUMP_TYPE=eckd
.br
DEVICE=0.0.1004
.br
BOOTPROG=0
.br
BR_CHR=auto
.br
#
.br
# Example configuration for an FCP dump device (SCSI Disk)

View File

@@ -127,7 +127,7 @@ echo "$cmd: Copying kexec"
# Install both binary and required shared libraries
OLDPATH=$PATH
PATH=$OLDPATH:/sbin:/usr/sbin
kexec_bin=$(which kexec)
kexec_bin=$(command -v kexec)
kexec_sos=$(sharedobjs $kexec_bin)
PATH=$OLDPATH

View File

@@ -119,9 +119,9 @@ dobuild()
# append ramdisk if specified
if [ "$ramdisk" != "" ]
then
ramdisk_size=$(du -b $ramdisk | cut -f1)
kernel_size=$(du -b $kernel | cut -f1)
ramdisk_offset=$(du -b $image | cut -f1)
ramdisk_size=$(du -b -L $ramdisk | cut -f1)
kernel_size=$(du -b -L $kernel | cut -f1)
ramdisk_offset=$(du -b -L $image | cut -f1)
cat $ramdisk >> $image
binval=$(mktemp)
dec2be64 $ramdisk_offset > $binval
@@ -135,7 +135,7 @@ dobuild()
# set cmdline
if [ "$parmfile" != "" ]
then
parmfile_size=$(du -b $parmfile | cut -f1)
parmfile_size=$(du -b -L $parmfile | cut -f1)
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
then
# Clear any previous parameters

View File

@@ -1,22 +0,0 @@
# Common definitions
include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/pvattest"
SUBDIRS := src man tools
RECURSIVE_TARGETS := all-recursive clean-recursive install-recursive
all: all-recursive
install: install-recursive
clean: clean-recursive
$(RECURSIVE_TARGETS):
@target=`echo $@ |sed s/-recursive//`; \
for d in $(SUBDIRS); do \
$(MAKE) -C $$d $$target || exit 1; \
done
.PHONY: all install clean $(RECURSIVE_TARGETS)

View File

@@ -1,100 +0,0 @@
# pvattest
Use `pvattest` to attest an IBM Secure Execution guest running on z16 and later.
With `pvattest` you can create attestation requests in a trusted environment and attest
an IBM Secure Execution for Linux guest to verify that a provider is running the correct image.
To achieve this, use the following commands:
* `create` On a trusted system, creates an attestation request.
* `perform` Performs an attestation measurement on the SE-guest to be attested. For this a
attestation request is sent to the Ultravisor (UV) and the answer received. The `perform`
command requires IBM z16 or later z/Architecture hardware.
* `verify` On a trusted system, compares the answer from the Ultravisor to the
expected answer. If they differ, the Secure Execution guest might be a different guest
than expected, or not secure at all.
For meaningful results, run `create` and `verify` only in a trusted environment,
like your workstation or a previously attested IBM Secure Execution guest.
Otherwise, the attestation can be compromised.
For all certificates, revocation lists, and host-key documents, both the PEM and DER input
formats are supported. If you run this program on a non S390 System, 'perform' is not be available.
## Getting started
If all dependencies are met (see the s390-tools README) issue `make` in the source tree to build `pvattest`.
## Details
### create
`pvattest create` needs the host-key-document, a location to store the
attestation request protection key, and a location to store the request data.
Unless the `--no-verify` flag is set it additionally requires the IBM signing key
and the intermediate CA. The output contains the request in binary form which serves as input
to `pvattest perform`. Must be run in a trusted environment. Especially, do not create the request
on a system you want to attest. The attestation request protection key is valid for this request only,
must be kept until the verification is completed and must be destroyed afterwards
Keep the key secret.
### perform
`pvattest perform` needs a request in binary form generated by `pvattest create`and
a location to store the output. It will send the request to the device at `/dev/uv`
which passes the request to the Ultravisor.
Kernel will then send the request to the Ultravisor which will calculate the answer.
The Answer is then passed back to userspace and handled by `pvattest`
The output includes the original request and the answer from the Ultravisor.
### verify
`pvattest verify` needs the SE-guest header, the attestation request protection key,
and the attestation request and the response to the `pvattest perform` command from the Ultravisor.
It calculates the measurement in the trusted environment and compares it to the response from
the Ultravisor in the previous step.
The following return codes are possible:
0. successful verification: The calculated measurement matches the response from the Ultravisor
1. failed verification: The command ended with an error, for example, because of incorrect input or an invalid SE header
2. failed verification: The calculated measurement does not match the response from the Ultravisor
Run `pvattest verify` in a trusted environment. Especially, do not verify on the system you want to attest.
## Measurement
The measurement is a cryptographic measurement of the following block.
Only HMAC-SHA512 is supported.
| Start | Size | Content |
|---------|------------|---------------------------------------------------------------|
| 0x0 | 0x40 | Page List Digest (from SE header) |
| 0x40 | 0x40 | Address List Digest (from SE header) |
| 0x80 | 0x40 | Tweak List Digest (from SE header) |
| 0xc0 | 0x10 | SE Header Tag (from SE header) |
| 0xd0 | 0x10 | Configuration UID (generated by UV, included in the answer) |
| 0xe0 | 0x02 | User Data Length (defined during measurement on the SE-guest) |
| 0xe2 | 0x02 | Zeros |
| 0xe4 | 0x04 | Additional Data Length (set by UV, included in the answer) |
| 0xe8 | 0 - 0x100 | User Data (generated during measurement on the SE-guest) |
| ... | 0 or 0x10 | Optional Nonce (generated during request creation) |
| ... | 0 - 0x8000 | Additional Data (generated by UV, included in the answer) |
### User Data
By default `pvattest` does not include any User Data, therefore the length is zero.
`User Data` is data generated by the SE guest and passed to UV during the measurement.
The `User Data` must be known to or be replicable by the verifier to verify the correctness of the User Data.
The addition of user data is currently an experimental setting.
### Additional Data
`Additional data` is data known to the Ultravisor. By default UV will not include any `Additional Data`.
Adding `Additional Data` is currently an experimental setting.
## Example
Create an attestation request in a trusted environment:
`pvattest create -k hkd.crt --arpk arp.key -o arcb.bin --cert IntermediateCA.crt --cert IbmSigningKey.crt`
Perform an attestation measurement on an IBM Secure Execution guest:
`pvattest perform --input arcb.bin --output measurement.bin`
Verify the response from the Ultravisor against the attestation request in a trusted environment:
`pvattest verify --input measurement.bin --arpk arp.key --hdr se_guest.hdr`

View File

@@ -1,9 +0,0 @@
include ../../common.mak
all:
install:
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c *.1 -t $(DESTDIR)$(MANDIR)/man1
.PHONY: all install clean

View File

@@ -1,83 +0,0 @@
.\" Copyright 2022 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH pvattest-create 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] create [OPTIONS] \fP- create an attestation measurement request
\fB
.SH DESCRIPTION
Prepare attestation measurement requests for an IBM Secure Execution guest.
Only prepare attestation requests in a trusted environment, such as your workstation.
The 'pvattest create' command creates a randomly generated key to protect the attestation request.
This key is only valid for this specific request. In order to avoid compromising the attestation,
do not publish the protection key and delete it after verification.
Every 'create' command generates a new, random protection key.
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Prints usage information, then exits.
.TP
.B
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
Specify one or more host key documents. At least one is required.
Specify this option multiple times to create an attestation request control block that is usable on multiple hosts.
.TP
.B
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
Specifies the certificate that is used to establish a chain of trust for the verification of the host-key documents. Specify this option twice to specify the IBM Z signing key and the intermediate CA certificate (signed by the root CA). Required. Ignored when \fB--no-verify\fP is specified.
.TP
.B
\fB--crl\fP=\fBFILE\fP
Specifies the revocation list that is used to check whether a certificate of the chain of trust is
revoked. Specify this option multiple times to use multiple CRLs (optional).
.TP
.B
\fB--root-ca\fP=\fBFILE\fP
Specifies the root CA certificate for the verification. If omitted,
the system wide root CAs installed on the system are used. Use
this only if you trust the specified certificate. Optional.
.TP
.B
\fB-o\fP, \fB--output\fP=\fBFILE\fP
\fBFILE\fP specifies the output for the attestation request control block.
.TP
.B
\fB-a\fP, \fB--arpk\fP=\fBFILE\fP
Save the protection key as GCM-AES256 key in \fBFILE\fP Do not publish this key, otherwise your attestation is compromised.
.TP
.B
\fB--no-verify\fP
Disable the host-key document verification. Does not require the host-key documents to be valid. Do
not use for a production request unless you verified the host-key document before (optional).
.TP
.B
\fB--offline\fP
Specifies offline mode, in which no attempt is made to download CRLs. (optional).
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional).
.SH EXAMPLE
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', and verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt'.
.PP
.nf
.fam C
pvattest create -k hkd.crt --arpk arp.key -o attreq.bin --cert DigiCertCA.crt --cert IbmSigningKey.crt
.fam T
.fi
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt', and instead of downloading the certificate revocation list use certificate revocation lists 'DigiCertCA.crl', 'IbmSigningKey.crl', and 'rootCA.crl'.
.PP
.nf
.fam C
pvattest create -k hkd.crt --arpk arp.key -o attreq.bin --cert DigiCertCA.crt --cert IbmSigningKey.crt --offline --crl DigiCertCA.crl --crl IbmSigningKey.crl --crl rootCA.crl
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-verify\fP(1), \fBpvattest-perform\fP(1)

View File

@@ -1,50 +0,0 @@
.\" Copyright 2022 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH pvattest-perform 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] perform [OPTIONS] \fP- execute an attestation measurement request
\fB
.SH DESCRIPTION
Run a measurement of this system using '/dev/uv'. Works only if this device is
available and the attestation Ultravisor facility is present.
The input must be an attestation request created with 'pvattest create'.
Output will contain the original request and the response from the Ultravisor.
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-i\fP, \fB--input\fP=\fBFILE\fP
\fBFILE\fP specifies the attestation request as input.
.TP
.B
\fB-o\fP, \fB--output\fP=\fBFILE\fP
\fBFILE\fP specifies the output for the attestation result.
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
Perform an attestation measurement with the attestation request 'arcb.bin' and write the output to 'measurement.bin'.
.PP
.nf
.fam C
pvattest perform --input attreq.bin --output attresp.bin
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-create\fP(1), \fBpvattest-verify\fP(1)

View File

@@ -1,75 +0,0 @@
.\" Copyright 2022 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH pvattest-verify 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] verify [OPTIONS] \fP- verify an attestation measurement
\fB
.SH DESCRIPTION
Verify that a previously generated attestation measurement of an IBM Secure Execution guest is as expected. Only verify attestation requests in a trusted environment, such as your workstation. Input must contain the response as produced by 'pvattest perform'. The protection key must be the one that was used to create the request by 'pvattest create'. Please delete it after verification. The header must be the IBM Secure Execution header of the image that was attested during 'pvattest perform'
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-i\fP, \fB--input\fP=\fBFILE\fP
\fBFILE\fP specifies the attestation result as input.
.TP
.B
\fB-o\fP, \fB--ouput\fP=\fBFILE\fP
\fBFILE\fP specifies the output for the verification result.
.TP
.B
\fB--hdr\fP=\fBFILE\fP
Specify the header of the guest image. Exactly one is required.
.TP
.B
\fB-a\fP, \fB--arpk\fP=\fBFILE\fP
Use \fBFILE\fP to specify the GCM-AES256 key to decrypt the attestation request. Delete this key after verification.
.TP
.B
\fB--format\fP=\fByaml\fP
Define the output format.
Default value: 'yaml'
Possible values:
.RS 4
- \fByaml\fP: Use YAML format
.RE
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
To verify a measurement in 'measurement.bin' with the protection key 'arp.kep' and SE-guest header 'se_guest.hdr'.
.PP
.nf
.fam C
pvattest verify --input attresp.bin --arpk arp.key --hdr se_guest.hdr
.fam T
.fi
If the verification was successful the program exists with zero.
If the verification failed it exists with 2 and prints the following to stderr:
.PP
.nf
.fam C
ERROR: Attestation measurement verification failed:
Calculated and received attestation measurement are not the same.
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-create\fP(1), \fBpvattest-perform\fP(1)

View File

@@ -1,104 +0,0 @@
.\" Copyright 2022 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH pvattest 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] COMMAND [OPTIONS] \fP- create, perform, and verify attestation measurements
\fB
.RE
\fB
.SH SYNOPSIS
.nf
.fam C
\fBpvattest\fP \fIcreate\fP [\fIOPTIONS\fP]
\fBpvattest\fP \fIperform\fP [\fIOPTIONS\fP]
\fBpvattest\fP \fIverify\fP [\fIOPTIONS\fP]
.fam T
.fi
.fam T
.fi
.SH DESCRIPTION
Use \fBpvattest\fP to attest that an IBM Secure Execution guest is the correct guest, and that it was started in a secure manner.
Run '\fBpvattest\fP \fIcreate\fP' and '\fBpvattest\fP \fIverify\fP' in a trusted environment only.
.PP
.nf
.fam C
create On a trusted system, creates an attestation request.
perform On the SE-guest to be attested, sends the attestation request to the Ultravisor and receives the answer.
verify On a trusted system, compares the answer from the Ultravisor to the one from your trusted environment. If they differ, the Secure Execution guest might be compromised.
.fam T
.fi
For meaningful results, run '\fIcreate\fP' and '\fIverify\fP' in a trusted environment, like your workstation or a previously attested IBM Secure Execution guest. Otherwise, the attestation might be tampered with. For all certificates, revocation lists, and host-key documents, both the PEM and DER input formats are supported. If you run \fBpvattest\fP on a machine architecture other than z/Architecture, 'measure' is not available.
.PP
Use '\fBpvattest\fP [COMMAND] \fB-h\fP' to get detailed help
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-v\fP, \fB--version\fP
Print the version and exit.
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
For details refer to the man page of the command.
.PP
Create the request on a trusted system.
.PP
.nf
.fam C
trusted:~$ pvattest create -k hkd.crt --cert CA.crt --cert ibmsk.crt --arpk arp.key -o attreq.bin
.fam T
.fi
On the SE-guest, \fIperform\fP the attestation.
.PP
.nf
.fam C
seguest:~$ pvattest perform -i attreq.bin -o attresp.bin
.fam T
.fi
On a trusted system, \fIverify\fP that the response is correct. Here, the protection key from the creation and the SE-guests header is used to \fIverify\fP the measurement.
.PP
.nf
.fam C
trusted:~$ pvattest verify -i attresp.bin --arpk arp.key --hdr se_guest.hdr
trusted:~$ echo $?
0
.fam T
.fi
If the measurements do not match \fBpvattest\fP exits with code 2 and emits an error message. The SE-guest attestation failed.
.PP
.nf
.fam C
trusted:~$ pvattest verify -i wrongresp.bin --arpk arp.key --hdr se_guest.hdr
ERROR: Attestation measurement verification failed:
Calculated and received attestation measurement are not the same.
trusted:~$ echo $?
2
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP-\fIcreate\fP(1), \fBpvattest-\fIverify\fP\fP(1), \fBpvattest\fP-\fIperform\fP(1)

View File

@@ -1,2 +0,0 @@
.check-dep-pvattest
.detect-openssl.dep.c

View File

@@ -1,112 +0,0 @@
include ../../common.mak
BIN_PROGRAM = pvattest
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
PVATTESTDIR := $(rootdir)/pvattest
INCLUDE_PATHS = "$(SRC_DIR)" "$(rootdir)/include"
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
LIBPV_DIR = $(rootdir)/libpv
LIBPV = $(LIBPV_DIR)/libpv.a
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Wno-error=inline \
-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
$(NULL)
PVATTEST_SRCS := $(wildcard *.c) \
$(NULL)
$(BIN_PROGRAM)_SRCS := \
$(PVATTEST_SRCS) \
$(NULL)
$(BIN_PROGRAM)_OBJS := $($(BIN_PROGRAM)_SRCS:.c=.o)
GLIB2_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcrypto)
LIBCRYPTO_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
LIBCURL_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcurl)
ALL_CFLAGS += -DPKGDATADIR=$(PKGDATADIR) \
-DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \
$(WARNINGS) \
$(NULL)
ifneq ($(call check_header_prereq,"asm/uvdevice.h"),yes)
ALL_CFLAGS += -DPVATTEST_NO_PERFORM
endif
ALL_CPPFLAGS += $(INCLUDE_PARMS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
BUILD_TARGETS := skip-$(BIN_PROGRAM)
INSTALL_TARGETS := skip-$(BIN_PROGRAM)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL}, 0)
BUILD_TARGETS := $(BIN_PROGRAM)
INSTALL_TARGETS := install-$(BIN_PROGRAM)
endif
endif
endif
all: $(BUILD_TARGETS)
install: $(INSTALL_TARGETS)
$(BIN_PROGRAM): $($(BIN_PROGRAM)_OBJS) $(LIBPV)
skip-$(BIN_PROGRAM):
echo " SKIP $(BIN_PROGRAM) due to unresolved dependencies"
clean:
$(RM) -f -- $($(BIN_PROGRAM)_OBJS) $(BIN_PROGRAM) .check-dep-$(BIN_PROGRAM) .detect-openssl.dep.c
install-$(BIN_PROGRAM): $(BIN_PROGRAM)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(INSTALL) -c $^ $(DESTDIR)$(USRBINDIR)
.PHONY: all install clean skip-$(BIN_PROGRAM) install-$(BIN_PROGRAM)
$($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
.detect-openssl.dep.c:
echo "#include <openssl/evp.h>" > $@
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
echo " #error openssl version 1.1.1 is required" >> $@
echo "#endif" >> $@
echo "static void __attribute__((unused)) test(void) {" >> $@
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
echo " EVP_MD_CTX_free(ctx);" >> $@
echo "}" >> $@
.check-dep-$(BIN_PROGRAM): .detect-openssl.dep.c
$(call check_dep, \
"$(BIN_PROGRAM)", \
"glib.h", \
"glib2-devel / libglib2.0-dev", \
"HAVE_GLIB2=0")
$(call check_dep, \
"$(BIN_PROGRAM)", \
$^, \
"openssl-devel / libssl-dev version >= 1.1.1", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(BIN_PROGRAM)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

View File

@@ -1,423 +0,0 @@
/*
* Attestation Request Control Block related functions
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include <openssl/evp.h>
#include <stdlib.h>
#include "libpv/crypto.h"
#include "libpv/hash.h"
#include "arcb.h"
#include "common.h"
#include "log.h"
#define ARVN_VERSION_1 0x0100
#define MAX_ARL 0x2000
typedef struct arcb_v1_hdr {
uint64_t reserved0; /* 0x0000 */
be32_t arvn; /* 0x0008 */
be32_t arl; /* 0x000c */
uint8_t iv[ARCB_V1_IV_SIZE]; /* 0x0010 */
uint32_t reserved1c; /* 0x001c */
uint8_t reserved20[7]; /* 0x0020 */
uint8_t nks; /* 0x0027 */
uint32_t reserved28; /* 0x0028 */
be32_t sea; /* 0x002c */
be64_t paf; /* 0x0030 */
be32_t mai; /* 0x0038 */
uint32_t reserved3c; /* 0x003c */
PvEcdhPubKey cpk; /* 0x0040 */
} __packed arcb_v1_hdr_t;
G_STATIC_ASSERT(sizeof(arcb_v1_hdr_t) == 0xe0);
typedef struct arcb_v1_key_slot {
uint8_t phkh[ARCB_V1_PHKH_SIZE];
uint8_t warpk[ARCB_V1_ATTEST_PROT_KEY_SIZE];
uint8_t kst[ARCB_V1_TAG_SIZE];
} __packed arcb_v1_key_slot_t;
G_STATIC_ASSERT(sizeof(arcb_v1_key_slot_t) == 0x50);
struct arcb_v1 {
/* authenticated data */
uint32_t arvn;
uint32_t mai;
uint64_t paf;
GBytes *iv;
EVP_PKEY *evp_cust_pub_key;
GSList *host_key_slots;
/* confidential data */
GBytes *confidential_measurement_key;
GBytes *confidential_optional_nonce;
GBytes *confidential_att_req_prot_key;
};
void arcb_v1_clear_free(arcb_v1_t *arcb)
{
if (!arcb)
return;
g_slist_free_full(arcb->host_key_slots, g_free);
g_bytes_unref(arcb->confidential_measurement_key);
g_bytes_unref(arcb->confidential_optional_nonce);
g_bytes_unref(arcb->confidential_att_req_prot_key);
g_bytes_unref(arcb->iv);
EVP_PKEY_free(arcb->evp_cust_pub_key);
g_free(arcb);
}
static void arcb_v1_set_paf(arcb_v1_t *arcb, const uint64_t paf, GError **error)
{
const uint64_t known_flags = ARCB_V1_PAF_ALL & ~ARCB_V1_PAF_NONCE;
if ((paf & ARCB_V1_PAF_NONCE) != 0) {
g_set_error(error, ARCB_ERROR, ARCB_ERR_INVALID_PAF,
_("The given paf (%#.16lx) specifies the NONCE flag (%#.16lx)."), paf,
ARCB_V1_PAF_NONCE);
return;
}
if ((paf & ~known_flags) != 0)
pvattest_log_warning(
_("The given paf (%#.16lx) specifies unknown flags. Use at your own risk!"),
paf, known_flags);
arcb->paf = paf;
}
arcb_v1_t *arcb_v1_new(GBytes *arpk, GBytes *iv, uint32_t mai, EVP_PKEY *evp_cpk, GBytes *mkey,
uint64_t paf, GError **error)
{
g_autoptr(arcb_v1_t) arcb = g_new0(arcb_v1_t, 1);
g_assert(g_bytes_get_size(iv) == ARCB_V1_IV_SIZE);
g_assert(g_bytes_get_size(arpk) == ARCB_V1_ATTEST_PROT_KEY_SIZE);
g_assert(g_bytes_get_size(mkey) == HMAC_SHA512_KEY_SIZE);
pv_wrapped_g_assert(arpk);
pv_wrapped_g_assert(iv);
pv_wrapped_g_assert(evp_cpk);
pv_wrapped_g_assert(mkey);
arcb->arvn = ARVN_VERSION_1;
arcb->mai = mai;
arcb_v1_set_paf(arcb, paf, error);
if (*error)
return NULL;
arcb->iv = g_bytes_ref(iv);
if (EVP_PKEY_up_ref(evp_cpk) != 1)
g_abort();
arcb->evp_cust_pub_key = evp_cpk;
arcb->confidential_att_req_prot_key = g_bytes_ref(arpk);
arcb->confidential_measurement_key = g_bytes_ref(mkey);
return g_steal_pointer(&arcb);
}
int arcb_v1_add_key_slot(arcb_v1_t *arcb, EVP_PKEY *evp_host, GError **error)
{
g_autoptr(GBytes) warpk = NULL, tag = NULL, phkh = NULL;
g_autoptr(GBytes) exchange_key = NULL, iv = NULL;
g_autofree arcb_v1_key_slot_t *key_slot = NULL;
g_autofree PvEcdhPubKey *ecdh_host = NULL;
g_autofree uint8_t *iv_raw = NULL;
PvCipherParms parms;
int64_t gcm_rc;
g_assert(arcb->confidential_att_req_prot_key);
pv_wrapped_g_assert(arcb);
pv_wrapped_g_assert(evp_host);
/* encrypt (=wrap) attestation request protection key, store warpk + tag */
exchange_key = pv_derive_exchange_key(arcb->evp_cust_pub_key, evp_host, error);
if (!exchange_key)
return -1;
iv_raw = g_malloc0(ARCB_V1_IV_SIZE);
iv = g_bytes_new_take(g_steal_pointer(&iv_raw), ARCB_V1_IV_SIZE);
if (!iv)
g_abort();
parms.key = exchange_key;
parms.iv = iv;
parms.cipher = EVP_aes_256_gcm();
parms.tag_size = ARCB_V1_TAG_SIZE;
gcm_rc = pv_gcm_encrypt(arcb->confidential_att_req_prot_key, NULL, &parms, &warpk, &tag,
error);
if (gcm_rc != ARCB_V1_ATTEST_PROT_KEY_SIZE)
return -1;
/* calculate public host key hash */
ecdh_host = pv_evp_pkey_to_ecdh_pub_key(evp_host, error);
if (!ecdh_host)
return -1;
phkh = pv_sha256_hash(ecdh_host->data, sizeof(ecdh_host->data), error);
if (!phkh)
return -1;
/* copy to list */
g_assert(g_bytes_get_size(warpk) == sizeof(key_slot->warpk));
g_assert(g_bytes_get_size(tag) == sizeof(key_slot->kst));
g_assert(g_bytes_get_size(phkh) == sizeof(key_slot->phkh));
key_slot = g_malloc0(sizeof(*key_slot));
pv_gbytes_memcpy(key_slot->warpk, sizeof(key_slot->warpk), warpk, NULL);
pv_gbytes_memcpy(key_slot->kst, sizeof(key_slot->warpk), tag, NULL);
pv_gbytes_memcpy(key_slot->phkh, sizeof(key_slot->warpk), phkh, NULL);
arcb->host_key_slots = g_slist_prepend(arcb->host_key_slots, g_steal_pointer(&key_slot));
return 0;
}
void arcb_v1_set_nonce(arcb_v1_t *arcb, GBytes *nonce)
{
pv_wrapped_g_assert(arcb);
pv_wrapped_g_assert(nonce);
arcb_v1_rm_nonce(arcb);
g_assert(!arcb->confidential_optional_nonce);
g_assert(g_bytes_get_size(nonce) == ARCB_V1_NONCE_SIZE);
arcb->confidential_optional_nonce = g_bytes_ref(nonce);
arcb->paf |= ARCB_V1_PAF_NONCE;
}
void arcb_v1_rm_nonce(arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
if (!arcb->confidential_optional_nonce)
return;
g_bytes_unref(arcb->confidential_optional_nonce);
arcb->confidential_optional_nonce = NULL;
arcb->paf &= ~ARCB_V1_PAF_NONCE;
}
GBytes *arcb_v1_serialize(const arcb_v1_t *arcb, GError **error)
{
pv_wrapped_g_assert(arcb);
g_autoptr(GByteArray) arcb_gba = NULL;
g_autoptr(GBytes) confidential_area = NULL;
g_autoptr(GBytes) aad = NULL;
g_autoptr(GBytes) art = NULL;
g_autoptr(GBytes) encrypted_area = NULL;
g_autoptr(GBytes) result = NULL;
g_autofree PvEcdhPubKey *ecdh_cpk = NULL;
PvCipherParms parms = {
.cipher = EVP_aes_256_gcm(),
.tag_size = AES_256_GCM_TAG_SIZE,
};
size_t att_req_len = 0, nks = 0, sea = 0;
arcb_v1_hdr_t hdr = {
.arvn = GUINT32_TO_BE(arcb->arvn),
.paf = GUINT64_TO_BE(arcb->paf),
.mai = GUINT32_TO_BE(arcb->mai),
};
g_assert(arcb->host_key_slots);
/* calculate sizes */
nks = g_slist_length(arcb->host_key_slots);
g_assert(nks < 0xFF);
sea = g_bytes_get_size(arcb->confidential_measurement_key);
if (arcb->confidential_optional_nonce)
sea += g_bytes_get_size(arcb->confidential_optional_nonce);
g_assert(sea == HMAC_SHA512_KEY_SIZE || sea == HMAC_SHA512_KEY_SIZE + ARCB_V1_NONCE_SIZE);
att_req_len = sizeof(hdr) + nks * sizeof(arcb_v1_key_slot_t) + HMAC_SHA512_KEY_SIZE +
ARCB_V1_TAG_SIZE;
if (arcb->confidential_optional_nonce)
att_req_len += ARCB_V1_NONCE_SIZE;
g_assert(att_req_len <= MAX_ARL);
/* copy plain data to contiguous memory */
hdr.arl = GUINT32_TO_BE((uint32_t)att_req_len);
pv_gbytes_memcpy(hdr.iv, ARCB_V1_IV_SIZE, arcb->iv, NULL);
hdr.nks = (uint8_t)nks;
hdr.sea = GUINT32_TO_BE((uint32_t)sea);
ecdh_cpk = pv_evp_pkey_to_ecdh_pub_key(arcb->evp_cust_pub_key, error);
memcpy(&hdr.cpk, ecdh_cpk, sizeof(*ecdh_cpk));
arcb_gba = g_byte_array_sized_new((guint)att_req_len);
g_byte_array_append(arcb_gba, (const uint8_t *)&hdr, sizeof(hdr));
for (GSList *elem = arcb->host_key_slots; elem; elem = elem->next)
g_byte_array_append(arcb_gba, elem->data, sizeof(arcb_v1_key_slot_t));
/* encrypt the confidential data */
confidential_area = secure_gbytes_concat(arcb->confidential_measurement_key,
arcb->confidential_optional_nonce);
parms.key = arcb->confidential_att_req_prot_key;
parms.iv = arcb->iv;
aad = g_bytes_new(arcb_gba->data, arcb_gba->len);
pv_gcm_encrypt(confidential_area, aad, &parms, &encrypted_area, &art, error);
if (*error)
return NULL;
g_byte_array_append(arcb_gba, g_bytes_get_data(encrypted_area, NULL), (guint)sea);
g_byte_array_append(arcb_gba, g_bytes_get_data(art, NULL), ARCB_V1_TAG_SIZE);
result = g_byte_array_free_to_bytes(arcb_gba);
arcb_gba = NULL;
return g_steal_pointer(&result);
}
uint32_t arcb_v1_get_required_measurement_size(const arcb_v1_t *arcb, GError **error)
{
pv_wrapped_g_assert(arcb);
switch (arcb->mai) {
case MAI_HMAC_SHA512:
return HMAC_SHA512_KEY_SIZE;
default:
g_set_error(error, ARCB_ERROR, ARCB_ERR_INVALID_MAI,
_("Unknown measurement algorithm ID specified (%#x)."), arcb->mai);
return 0;
}
}
uint32_t arcb_v1_get_required_additional_size(const arcb_v1_t *arcb)
{
uint32_t size = 0;
pv_wrapped_g_assert(arcb);
if (arcb_v1_additional_has_phkh_image(arcb))
size += ARCB_V1_PHKH_SIZE;
if (arcb_v1_additional_has_phkh_attest(arcb))
size += ARCB_V1_PHKH_SIZE;
return size;
}
gboolean arcb_v1_use_nonce(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
return arcb->confidential_optional_nonce != NULL;
}
gboolean arcb_v1_additional_has_phkh_image(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
return (arcb->paf & ARCB_V1_PAF_AAD_PHKH_HEADER) != 0;
}
gboolean arcb_v1_additional_has_phkh_attest(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
return (arcb->paf & ARCB_V1_PAF_AAD_PHKH_ATTEST) != 0;
}
GBytes *arcb_v1_get_measurement_key(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
return g_bytes_ref(arcb->confidential_measurement_key);
}
GBytes *arcb_v1_get_nonce(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
if (arcb->confidential_optional_nonce)
return g_bytes_ref(arcb->confidential_optional_nonce);
return NULL;
}
GBytes *arcb_v1_get_arp_key(const arcb_v1_t *arcb)
{
pv_wrapped_g_assert(arcb);
return g_bytes_ref(arcb->confidential_att_req_prot_key);
}
static gboolean is_v1_arcb(size_t aad_size, size_t sea, size_t arl, size_t serialized_arcb_size,
uint32_t arcb_version, gboolean has_nonce)
{
gboolean result = aad_size + sea + ARCB_V1_TAG_SIZE == arl;
result &= arl <= serialized_arcb_size;
result &= arcb_version == ARVN_VERSION_1;
result &= has_nonce ? sea == HMAC_SHA512_KEY_SIZE + ARCB_V1_NONCE_SIZE :
sea == HMAC_SHA512_KEY_SIZE;
return result;
}
gboolean arcb_v1_verify_serialized_arcb(GBytes *serialized_arcb, GBytes *arpk,
GBytes **measurement_key, GBytes **optional_nonce,
GError **error)
{
g_autoptr(GBytes) encr = NULL, decr = NULL, aad = NULL, tag = NULL, iv = NULL;
const struct arcb_v1_hdr *serialized_arcb_hdr;
const uint8_t *encr_u8, *aad_u8, *tag_u8;
const uint8_t *serialized_arcb_u8;
size_t serialized_arcb_size;
uint32_t arcb_version, mai;
size_t aad_size, arl, sea;
PvCipherParms parms;
gboolean has_nonce;
uint64_t paf;
pv_wrapped_g_assert(serialized_arcb);
pv_wrapped_g_assert(arpk);
serialized_arcb_u8 = g_bytes_get_data(serialized_arcb, &serialized_arcb_size);
serialized_arcb_hdr = (const arcb_v1_hdr_t *)serialized_arcb_u8;
arl = GUINT32_FROM_BE(serialized_arcb_hdr->arl);
arcb_version = GUINT32_FROM_BE(serialized_arcb_hdr->arvn);
mai = GUINT32_FROM_BE(serialized_arcb_hdr->mai);
aad_u8 = serialized_arcb_u8;
aad_size = sizeof(*serialized_arcb_hdr) +
serialized_arcb_hdr->nks * sizeof(arcb_v1_key_slot_t);
encr_u8 = aad_u8 + aad_size;
sea = GUINT32_FROM_BE(serialized_arcb_hdr->sea);
tag_u8 = encr_u8 + sea;
paf = GUINT64_FROM_BE(serialized_arcb_hdr->paf);
has_nonce = (paf & ARCB_V1_PAF_NONCE) != 0;
if (!is_v1_arcb(aad_size, sea, arl, serialized_arcb_size, arcb_version, has_nonce)) {
g_set_error(error, ARCB_ERROR, ARCB_ERR_INVALID_ARCB,
_("The provided attestation request is not valid"));
return FALSE;
}
if (mai != MAI_HMAC_SHA512) {
g_set_error(error, ARCB_ERROR, ARCB_ERR_INVALID_MAI,
_("Unsupported measurement argument ID (%#x)"), mai);
return FALSE;
}
aad = g_bytes_new(aad_u8, aad_size);
encr = g_bytes_new(encr_u8, sea);
tag = g_bytes_new(tag_u8, ARCB_V1_TAG_SIZE);
iv = g_bytes_new(serialized_arcb_hdr->iv, sizeof(serialized_arcb_hdr->iv));
parms.cipher = EVP_aes_256_gcm();
parms.tag_size = AES_256_GCM_TAG_SIZE;
parms.key = arpk;
parms.iv = iv;
pv_gcm_decrypt(encr, aad, tag, &parms, &decr, error);
if (*error) {
GError *tmp_error = NULL;
g_set_error(&tmp_error, ARCB_ERROR, ARCB_ERR_INVALID_ARCB,
_("Cannot verify the attestation request: %s"), (*error)->message);
g_clear_error(error);
g_propagate_error(error, tmp_error);
return FALSE;
}
if (measurement_key)
*measurement_key = g_bytes_new(g_bytes_get_data(decr, NULL), HMAC_SHA512_KEY_SIZE);
if (optional_nonce && has_nonce)
*optional_nonce =
g_bytes_new((uint8_t *)g_bytes_get_data(decr, NULL) + HMAC_SHA512_KEY_SIZE,
ARCB_V1_NONCE_SIZE);
return TRUE;
}

View File

@@ -1,152 +0,0 @@
/*
* Attestation Request Control Block related functions
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PVATTEST_ARCB_H
#define PVATTEST_ARCB_H
/* Must be included before any other header */
#include "config.h"
#include "libpv/glib-helper.h"
#include "lib/zt_common.h"
#include "libpv/crypto.h"
#include "libpv/macros.h"
#include "types.h"
#define MAI_HMAC_RESERVED_INVALID 0
#define MAI_HMAC_SHA512 0x1
#define HMAC_SHA512_KEY_SIZE 64
#define ARCB_V1_ATTEST_PROT_KEY_SIZE 32
#define ARCB_V1_NONCE_SIZE 16
#define ARCB_V1_TAG_SIZE 16
#define ARCB_V1_IV_SIZE 12
#define ARCB_V1_PHKH_SIZE 32
/* Optional nonce in ARCB */
#define ARCB_V1_PAF_NONCE PV_MSB(1)
/* Public host key hash used to unseal SE header added to additional data to be measured */
#define ARCB_V1_PAF_AAD_PHKH_HEADER PV_MSB(2)
/* Public host key hash used to unseal this attestation added to additional data to be measured */
#define ARCB_V1_PAF_AAD_PHKH_ATTEST PV_MSB(3)
/* Temporary backup-host-key use allowed */
#define ARCB_V1_PAF_TMP_BACKUP_ALLOWED PV_MSB(62)
/* Global not-host-specific key allowed */
#define ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED PV_MSB(63)
#define ARCB_V1_PAF_ALL \
(ARCB_V1_PAF_NONCE | ARCB_V1_PAF_AAD_PHKH_HEADER | ARCB_V1_PAF_AAD_PHKH_ATTEST | \
ARCB_V1_PAF_TMP_BACKUP_ALLOWED | ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED)
typedef struct arcb_v1 arcb_v1_t;
/** arcb_v1_new:
*
* @arpk: Attestation Request Protection key. AES-GCM-256 key to
* protect Measurement Key and Nonce.
* Must be ´ARCB_V1_ATTEST_PROT_KEY_SIZE´ bytes long.
* @iv: IV for protecting Measuremt Key and Nonce.
* Should be random for each new ARPK.
* Must be ´ARCB_V1_IV_SIZE´ bytes long.
* @mai: Measurement Algorithm Identifier for the attestation measurement.
* See ´enum mai´
* @evp_cpk: Customer key in EVP_PKEY format. Must contain private and public key pair.
* @mkey: Measurement key to calculate the Measurement.
* Must be ´HMAC_SHA512_KEY_SIZE´ bytes long.
* @paf: Plain text Attestation Flags. See ´enum plaintext_attestattion_flags´.
* ´ARCB_V1_PAF_NONCE´ must not be set.
* @error: GError. *error will != NULL if error occours.
*
* arpk, mkey, and iv must me correct size
* If not this is considered as a programming error (No warning;
* Results in Assertion or undefined behavior).
*
* GBytes will be ref'ed.
*
* All numbers must be in system byte order and will be converted to big endian
* if needed.
*
* Returns: (nullable) (transfer full): new ARCB context.
*/
arcb_v1_t *arcb_v1_new(GBytes *arpk, GBytes *iv, uint32_t mai, EVP_PKEY *evp_cpk, GBytes *mkey,
uint64_t paf, GError **error) PV_NONNULL(1, 2, 4, 5);
void arcb_v1_clear_free(arcb_v1_t *arcb);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(arcb_v1_t, arcb_v1_clear_free)
/** arcb_v1_add_key_slot:
*
* @arcb: ARCB context.
* @evp_host: Host public key.
* @error: GError. *error will != NULL if error occours.
*
* Builds a key slot. Calculates exchange key, wraps ARPK with the exchange key.
* Calculates the public host key hash. Calculates the key slot tag.
* Adds it to the ARCB.
*
* Returns: 0 in case of success, -1 otherwise
*/
int arcb_v1_add_key_slot(arcb_v1_t *arcb, EVP_PKEY *evp_host, GError **error) PV_NONNULL(1, 2);
void arcb_v1_set_nonce(arcb_v1_t *arcb, GBytes *nonce) PV_NONNULL(1, 2);
void arcb_v1_rm_nonce(arcb_v1_t *arcb) PV_NONNULL(1);
/** arcb_v1_serialize:
*
* @arcb: ARCB context.
* @error: GError. *error will != NULL if error occurs.
*
* Will create a valid ARCB for the UV. Including encrypting confidential data.
* At least one key_slot must be added beforehand.
*
* Returns: (nullable) (transfer full): The serialized ARCB which can be added to the
* Retrieve Attestation Measurement UVC as GBytes.
*/
GBytes *arcb_v1_serialize(const arcb_v1_t *arcb, GError **error) PV_NONNULL(1, 2);
uint32_t arcb_v1_get_required_measurement_size(const arcb_v1_t *arcb, GError **error)
PV_NONNULL(1, 2);
uint32_t arcb_v1_get_required_additional_size(const arcb_v1_t *arcb) PV_NONNULL(1);
gboolean arcb_v1_use_nonce(const arcb_v1_t *arcb) PV_NONNULL(1);
gboolean arcb_v1_additional_has_phkh_image(const arcb_v1_t *arcb) PV_NONNULL(1);
gboolean arcb_v1_additional_has_phkh_attest(const arcb_v1_t *arcb) PV_NONNULL(1);
GBytes *arcb_v1_get_measurement_key(const arcb_v1_t *arcb) PV_NONNULL(1);
GBytes *arcb_v1_get_nonce(const arcb_v1_t *arcb) PV_NONNULL(1);
GBytes *arcb_v1_get_arp_key(const arcb_v1_t *arcb) PV_NONNULL(1);
/** arcb_v1_verify_serialized_arcb:
*
* @serialized_arcb: binary ARCB in UV readable format.
* @arpk: Attestation Request Protection key that was used to create serialized_arpk
* @measurement_key: Output parameter: decrypted measurement key if no error.
* May be NULL if not interested for this output.
* @optional_nonce: Output parameter: decrypted nonce if no error.
* May be NULL if not interested for this output.
* @error: GError. *error will != NULL if error occurs.
*
*
* Checks if sizes are sound and flags are known by this implementation.
* Decrypts Measurement key and nonce (if given) and verifies ARCB tag.
*
* Returns: TRUE if ARCB is valid, including matching ARCB tag. Otherwise FALSE.
*
*/
gboolean arcb_v1_verify_serialized_arcb(GBytes *serialized_arcb, GBytes *arpk,
GBytes **measurement_key, GBytes **optional_nonce,
GError **error) PV_NONNULL(1, 2);
#define ARCB_ERROR g_quark_from_static_string("pv-arcb_error-quark")
typedef enum arcb_error {
ARCB_ERR_INVALID_ARCB,
ARCB_ERR_INVALID_PAF,
ARCB_ERR_INVALID_MAI,
ARCB_ERR_UNABLE_ENCR_ARPK,
} arcb_error_e;
#endif /* PVATTEST_ARCB_H */

View File

@@ -1,674 +0,0 @@
/*
* Definitions used for parsing arguments.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include "argparse.h"
#include "log.h"
#include "common.h"
#define DEFAULT_OUTPUT_FILE_NAME "attest.bin"
#define DEFAULT_OPTION_PHKH_IMG FALSE
#define DEFAULT_OPTION_PHKH_ATT FALSE
#define DEFAULT_OPTION_NO_VERIFY FALSE
#define DEFAULT_OPTION_ONLINE TRUE
#define DEFAULT_OPTION_NONCE TRUE
static pvattest_config_t pvattest_config = {
.general = {
.log_level = PVATTEST_LOG_LVL_DEFAULT,
},
.create = {
.output_path = NULL,
.host_key_document_paths = NULL,
.crl_paths = NULL,
.root_ca_path = NULL,
.certificate_paths = NULL,
.arp_key_out_path = NULL,
.phkh_img = DEFAULT_OPTION_PHKH_IMG,
.phkh_att = DEFAULT_OPTION_PHKH_ATT,
.online = DEFAULT_OPTION_ONLINE,
.use_nonce = DEFAULT_OPTION_NONCE,
.paf = 0,
.x_aad_size = -1,
},
.perform = {
.output_path = NULL,
.input_path = NULL,
},
.verify = {
.input_path = NULL,
.output_path = NULL,
.hdr_path = NULL,
.arp_key_in_path = NULL,
.output_fmt = VERIFY_FMT_YAML,
},
};
typedef gboolean (*verify_options_fn_t)(GError **);
static gboolean check_for_non_null(const void *ptr, const char *msg, GError **error)
{
if (!ptr) {
g_set_error(error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARG, "%s", msg);
return FALSE;
}
return TRUE;
}
static gboolean _check_for_invalid_path(const char *path, gboolean must_exist, GError **error)
{
int cached_errno = 0;
g_assert(path);
if (must_exist) {
if (access(path, F_OK | R_OK) != 0)
cached_errno = errno;
}
if (cached_errno) {
g_set_error(error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARG, "Cannot access '%s': %s",
path, g_strerror(cached_errno));
return FALSE;
}
return TRUE;
}
static gboolean check_for_optional_invalid_path(const char *path, gboolean must_exist,
GError **error)
{
if (!path)
return TRUE;
return _check_for_invalid_path(path, must_exist, error);
}
static gboolean check_for_invalid_path(const char *path, gboolean must_exist, const char *null_msg,
GError **error)
{
if (!check_for_non_null(path, null_msg, error))
return FALSE;
return _check_for_invalid_path(path, must_exist, error);
}
static gboolean _check_file_list(char **path_list, gboolean must_exist, GError **error)
{
char *path = NULL;
for (char **path_it = path_list; path_it != NULL && *path_it != NULL; path_it++) {
path = *path_it;
if (!_check_for_invalid_path(path, must_exist, error))
return FALSE;
}
return TRUE;
}
static gboolean check_optional_file_list(char **path_list, gboolean must_exist, GError **error)
{
if (!path_list)
return TRUE;
return _check_file_list(path_list, must_exist, error);
}
static gboolean check_file_list(char **path_list, gboolean must_exist, const char *null_msg,
GError **error)
{
if (!check_for_non_null(path_list, null_msg, error))
return FALSE;
return _check_file_list(path_list, must_exist, error);
}
static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
{
uint64_t value;
gchar *end;
g_assert(dst);
if (!g_str_is_ascii(nptr)) {
g_set_error(
error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARG,
_("Invalid value: '%s'. A hexadecimal value is required, for example '0xcfe'"),
nptr);
return FALSE;
}
value = g_ascii_strtoull(nptr, &end, 16);
if ((value == G_MAXUINT64 && errno == ERANGE) || (end && *end != '\0')) {
g_set_error(
error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARG,
_("Invalid value: '%s'. A hexadecimal value is required, for example '0xcfe'"),
nptr);
return FALSE;
}
*dst = value;
return TRUE;
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
/************************* SHARED OPTIONS *************************************/
/* NOTE REQUIRED */
#define _entry_host_key_document(__arg_data, __indent) \
{ \
.long_name = "host-key-document", .short_name = 'k', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
.description = \
"FILE specifies a host-key document. At least one is required.\n" __indent \
"Specify this option multiple times to enable the request for\n" __indent \
"more than one host.\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_certs(__arg_data, __indent) \
{ \
.long_name = "cert", .short_name = 'C', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
.description = "FILE contains a certificate that is used to\n" __indent \
"establish a chain of trust for the verification\n" __indent \
"of the host-key documents. The IBM Z signing\n" __indent \
"key and intermediate CA certificate (signed\n" __indent \
"by the root CA) are required.\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_crls(__arg_data, __indent) \
{ \
.long_name = "crl", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
.description = "FILE contains a certificate revocation list (optional).\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_root_ca(__arg_data, __indent) \
{ \
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
.description = "Use FILE as the trusted root CA instead the\n" __indent \
"root CAs that are installed on the system (optional).\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_guest_hdr(__arg_data, __indent) \
{ \
.long_name = "hdr", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "FILE specifies the header of the guest image.\n" __indent \
"Exactly one is required.\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_input(__arg_data, __additional_text, __indent) \
{ \
.long_name = "input", .short_name = 'i', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "FILE specifies the " __additional_text " as input.\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_output(__arg_data, __additional_text, __indent) \
{ \
.long_name = "output", .short_name = 'o', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "FILE specifies the output for the " __additional_text "\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_att_prot_key_save(__arg_data, __indent) \
{ \
.long_name = "arpk", .short_name = 'a', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = \
"Save the protection key as GCM-AES256 key in FILE\n" __indent \
"Do not publish this key, otherwise your attestation is compromised.\n", \
.arg_description = "FILE", \
}
/* NOTE REQUIRED */
#define _entry_att_prot_key_load(__arg_data, __indent) \
{ \
.long_name = "arpk", .short_name = 'a', .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "Use FILE to specify the GCM-AES256 key to decrypt\n" __indent \
"the attestation request.\n" __indent \
"Delete this key after verification.\n", \
.arg_description = "FILE", \
}
#define _entry_phkh_img(__arg_data, __indent) \
{ \
.long_name = "x-phkh-img", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
.description = "Add the public host key hash of the\n" __indent \
"image header used to decrypt\n" __indent \
"the secure guest to the measurement. (optional)\n" \
}
#define _entry_phkh_att(__arg_data, __indent) \
{ \
.long_name = "x-phkh-att", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
.description = "Add the public host key hash of the\n" __indent \
"attestation header used to decrypt\n" __indent \
"the attestation request to the measurement. (optional)\n" \
}
#define _entry_no_verify(__arg_data, __indent) \
{ \
.long_name = "no-verify", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
.description = "Disable the host-key document verification.\n" __indent \
"(optional)\n", \
}
#define _entry_offline_maps_to_online(__arg_data, __indent) \
{ \
.long_name = "offline", .short_name = 0, .flags = G_OPTION_FLAG_REVERSE, \
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
.description = "Don't download CRLs. (optional)\n", \
}
#define _entry_verbose(__indent) \
{ \
.long_name = "verbose", .short_name = 'V', .flags = G_OPTION_FLAG_NO_ARG, \
.arg = G_OPTION_ARG_CALLBACK, .arg_data = &increase_log_lvl, \
.description = "Provide more detailed output. (optional)\n", \
.arg_description = NULL, \
}
#define _entry_x_paf(__arg_data, __indent) \
{ \
.long_name = "x-paf", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_CALLBACK, .arg_data = __arg_data, \
.description = "Specify the Plain text Attestation Flags\n" __indent \
"as a hexadecimal value. Flags that change\n" __indent \
"the paf (--phkh-*) take precedence over\n" __indent \
"this flag.\n" __indent \
"Setting the nonce paf is not allowed here.\n" __indent \
"(optional, default 0x0)\n", \
.arg_description = "HEX", \
}
#define _entry_x_no_nonce(__arg_data, __indent) \
{ \
.long_name = "x-no-nonce", .short_name = 0, .flags = G_OPTION_FLAG_REVERSE, \
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
.description = "Do not use a nonce in the request.\n" __indent \
"(optional, not recommended)\n" \
}
#define _entry_x_aad_size(__arg_data, __indent) \
{ \
.long_name = "x-add-size", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_INT, .arg_data = __arg_data, \
.description = "Specify the size of the additional area\n" __indent \
"Overwrite every flag that changes\n" __indent \
"this size implicitly. No verification is performed!\n" __indent \
"Ignored if negative.\n" __indent "(optional, default ignored)\n", \
.arg_description = "INT" \
}
#define _entry_x_user_data(__arg_data, __indent) \
{ \
.long_name = "x-user-data", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
.description = "Use FILE to specify the user data.\n", .arg_description = "FILE", \
}
#define _entry__verify_format(__indent) \
{ \
.long_name = "format", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
.arg = G_OPTION_ARG_CALLBACK, .arg_data = &set_verify_output_format, \
.description = "Define the output format.\n" __indent \
"Defaults to 'yaml'. (possible values: 'yaml')\n", \
.arg_description = "FORMAT", \
}
static gboolean increase_log_lvl(G_GNUC_UNUSED const char *option_name,
G_GNUC_UNUSED const char *value, G_GNUC_UNUSED void *data,
G_GNUC_UNUSED GError **error)
{
pvattest_log_increase_log_lvl(&pvattest_config.general.log_level);
return TRUE;
}
static gboolean set_verify_output_format(const char *option_name, const char *value,
G_GNUC_UNUSED void *data, GError **error)
{
if (!g_strcmp0(value, "yaml")) {
pvattest_config.verify.output_fmt = VERIFY_FMT_YAML;
} else {
g_set_error(error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED,
_("Found value '%s' for option '%s', but only 'yaml' is allowed."),
value, option_name);
return FALSE;
}
return TRUE;
}
static gboolean create_set_paf(G_GNUC_UNUSED const char *option_name, const char *value,
G_GNUC_UNUSED void *data, GError **error)
{
return hex_str_toull(value, &pvattest_config.create.paf, error);
}
/***************************** GENERAL OPTIONS ********************************/
static gboolean print_version = FALSE;
static GOptionEntry general_options[] = {
{
.long_name = "version",
.short_name = 'v',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = &print_version,
.description = "Print the version and exit.\n",
.arg_description = NULL,
},
_entry_verbose(""),
{ NULL },
};
/************************* CREATE ATTESTATION OPTIONS *************************/
#define create_indent " "
static GOptionEntry create_options[] = {
_entry_host_key_document(&pvattest_config.create.host_key_document_paths, create_indent),
_entry_certs(&pvattest_config.create.certificate_paths, create_indent),
_entry_crls(&pvattest_config.create.crl_paths, create_indent),
_entry_root_ca(&pvattest_config.create.root_ca_path, create_indent),
_entry_output(&pvattest_config.create.output_path, "attestation request", create_indent),
_entry_att_prot_key_save(&pvattest_config.create.arp_key_out_path, create_indent),
_entry_no_verify(&pvattest_config.create.no_verify, create_indent),
_entry_offline_maps_to_online(&pvattest_config.create.online, create_indent),
_entry_verbose(create_indent),
{ NULL }
};
static GOptionEntry experimental_create_options[] = {
_entry_x_no_nonce(&pvattest_config.create.use_nonce, create_indent),
_entry_x_paf(&create_set_paf, create_indent),
_entry_x_aad_size(&pvattest_config.create.x_aad_size, create_indent),
_entry_phkh_img(&pvattest_config.create.phkh_img, create_indent),
_entry_phkh_att(&pvattest_config.create.phkh_att, create_indent),
{ NULL }
};
static gboolean verify_create(GError **error)
{
if (!check_file_list(pvattest_config.create.host_key_document_paths, TRUE,
_("Specify --host-key-document at least once."), error))
return FALSE;
if (!pvattest_config.create.no_verify) {
if (!check_file_list(
pvattest_config.create.certificate_paths, TRUE,
_("Either specify the IBM Z signing key and"
" intermediate CA certificate\nby using the '--cert' option, or"
" use the '--no-verify' flag to disable the\nhost-key document"
" verification completely (at your own risk).\n"
"Only use this option in test environments or if"
" you trust the unverified document."),
error))
return FALSE;
}
if (!check_for_invalid_path(pvattest_config.create.arp_key_out_path, FALSE,
_("Missing argument for --arpk."), error))
return FALSE;
if (!check_for_invalid_path(pvattest_config.create.output_path, FALSE,
_("Missing argument for --output."), error))
return FALSE;
if (!check_optional_file_list(pvattest_config.create.crl_paths, TRUE, error))
return FALSE;
if (!check_for_optional_invalid_path(pvattest_config.create.root_ca_path, TRUE, error))
return FALSE;
return TRUE;
};
/************************* MEASUREMENT OPTIONS ********************************/
#define perform_indent " "
static GOptionEntry perform_options[] = {
_entry_input(&pvattest_config.perform.input_path, "attestation request", perform_indent),
_entry_output(&pvattest_config.perform.output_path, "attestation result", perform_indent),
_entry_verbose(perform_indent),
{ NULL },
};
static GOptionEntry experimental_perform_options[] = {
_entry_x_user_data(&pvattest_config.perform.user_data_path, perform_indent),
{ NULL },
};
static gboolean verify_perform(GError **error)
{
if (!check_for_invalid_path(pvattest_config.perform.input_path, TRUE,
_("Missing argument for --input."), error))
return FALSE;
if (!check_for_invalid_path(pvattest_config.perform.output_path, FALSE,
_("Missing argument for --output."), error))
return FALSE;
if (!check_for_optional_invalid_path(pvattest_config.perform.user_data_path, TRUE, error))
return FALSE;
return TRUE;
}
/************************* VERIFY OPTIONS ************************************/
#define verify_indent " "
static GOptionEntry verify_options[] = {
_entry_input(&pvattest_config.verify.input_path, "attestation result", verify_indent),
_entry_output(&pvattest_config.verify.output_path,
"verification result.\n" verify_indent "(optional)", verify_indent),
_entry_guest_hdr(&pvattest_config.verify.hdr_path, verify_indent),
_entry_att_prot_key_load(&pvattest_config.verify.arp_key_in_path, verify_indent),
_entry_verbose(verify_indent),
_entry__verify_format(verify_indent),
{ NULL },
};
static gboolean verify_verify(GError **error)
{
if (!check_for_invalid_path(pvattest_config.verify.input_path, TRUE,
_("Missing argument for --input."), error))
return FALSE;
if (!check_for_invalid_path(pvattest_config.verify.hdr_path, TRUE,
_("Missing argument for --hdr."), error))
return FALSE;
if (!check_for_invalid_path(pvattest_config.verify.arp_key_in_path, TRUE,
_("Missing argument for --arpk."), error))
return FALSE;
return TRUE;
}
/************************** OPTIONS END ***************************************/
#pragma GCC diagnostic pop
static char summary[] =
"\n"
"Create, perform, and verify attestation measurements for IBM Secure Execution guest"
" systems.\n"
"\n"
"COMMANDS\n"
" create On a trusted system, creates an attestation request.\n"
" perform On the SE-guest to be attested, sends the attestation request\n"
" to the Ultravisor and receives the answer.\n"
#ifndef PVATTEST_COMPILE_PERFORM
" (not supported on this platform)\n"
#endif /* PVATTEST_COMPILE_PERFORM */
" verify On a trusted system, compares the one from your trusted system.\n"
" If they differ, the Secure Execution guest might not be compromised\n"
"\n"
"Use '" GETTEXT_PACKAGE " [COMMAND] -h' to get detailed help\n";
static char create_summary[] =
"Create attestation measurement requests to attest an\n"
"IBM Secure Execution guest. Only build attestation requests in a trusted\n"
"environment such as your Workstation.\n"
"To avoid compromising the attestation do not publish the\n"
"protection key and delete it after verification.\n"
"Every 'create' will generate a new, random protection key.\n";
static char perform_summary[] =
#ifndef PVATTEST_COMPILE_PERFORM
"This system does NOT support 'perform'.\n"
#endif /* PVATTEST_COMPILE_PERFORM */
"Perform a measurement of this IBM Secure Execution guest using '/dev/uv'.\n";
static char verify_summary[] =
"Verify that a previously generated attestation measurement of an\n"
"IBM Secure Execution guest yielded the expected results.\n"
"Verify attestation requests only in a trusted environment, such as your workstation.";
static void print_version_and_exit(void)
{
printf("%s version %s\n", GETTEXT_PACKAGE, RELEASE_STRING);
printf("%s\n", COPYRIGHT_NOTICE);
exit(EXIT_SUCCESS);
}
static GOptionContext *create_ctx(GOptionEntry *options, GOptionEntry *experimental_options,
const char *param_name, const char *opt_summary)
{
GOptionContext *ret = g_option_context_new(param_name);
GOptionGroup *x_group = NULL;
g_option_context_add_main_entries(ret, options, NULL);
g_option_context_set_summary(ret, opt_summary);
if (experimental_options) {
x_group = g_option_group_new(
"experimental",
"Experimental Options; Do not use in a production environment",
"Show experimental options", NULL, NULL);
g_option_group_add_entries(x_group, experimental_options);
g_option_context_add_group(ret, x_group);
}
return ret;
}
enum pvattest_command pvattest_parse(int *argc, char **argvp[], pvattest_config_t **config,
GError **error)
{
g_autoptr(GOptionContext) main_context = NULL, subc_context = NULL;
char **argv = *argvp;
enum pvattest_command subc = PVATTEST_SUBC_INVALID;
verify_options_fn_t verify_options_fn = NULL;
pv_wrapped_g_assert(argc);
pv_wrapped_g_assert(argvp);
pv_wrapped_g_assert(config);
/*
* First parse until the first non dash argument. This must be one of the commands.
* (strict POSIX parsing)
*/
main_context = g_option_context_new(
"COMMAND [OPTIONS] - create, perform, and verify attestation measurements");
g_option_context_set_strict_posix(main_context, TRUE);
g_option_context_add_main_entries(main_context, general_options, NULL);
g_option_context_set_summary(main_context, summary);
if (!g_option_context_parse(main_context, argc, argvp, error))
return PVATTEST_SUBC_INVALID;
if (print_version)
print_version_and_exit();
/*
* Parse depending on the specified command
*/
else if (g_strcmp0(argv[1], PVATTEST_SUBC_STR_CREATE) == 0) {
subc_context =
create_ctx(create_options, experimental_create_options,
"create [OPTIONS] - create an attestation measurement request",
create_summary);
subc = PVATTEST_SUBC_CREATE;
verify_options_fn = &verify_create;
} else if (g_strcmp0(argv[1], PVATTEST_SUBC_STR_PERFORM) == 0) {
subc_context =
create_ctx(perform_options, experimental_perform_options,
"perform [OPTIONS] - perform an attestation measurement request",
perform_summary);
subc = PVATTEST_SUBC_PERFORM;
verify_options_fn = &verify_perform;
#ifndef PVATTEST_COMPILE_PERFORM
g_set_error(error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARG,
_("This system does not support the 'perform' command."));
return PVATTEST_SUBC_INVALID;
#endif /* PVATTEST_COMPILE_PERFORM */
} else if (g_strcmp0(argv[1], PVATTEST_SUBC_STR_VERIFY) == 0) {
subc_context = create_ctx(verify_options, NULL,
"verify [OPTIONS] - verify an attestation measurement",
verify_summary);
subc = PVATTEST_SUBC_VERIFY;
verify_options_fn = &verify_verify;
} else {
if (argv[1])
g_set_error(error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARGV,
_("Invalid command specified: %s."), argv[1]);
else
g_set_error(error, PVATTEST_ERROR, PVATTEST_ERR_INV_ARGV,
_("No command specified."));
return PVATTEST_SUBC_INVALID;
}
g_assert(verify_options_fn);
if (!g_option_context_parse(subc_context, argc, argvp, error))
return PVATTEST_SUBC_INVALID;
if (!verify_options_fn(error))
return PVATTEST_SUBC_INVALID;
*config = &pvattest_config;
return subc;
}
static void pvattest_parse_clear_create_config(pvattest_create_config_t *config)
{
if (!config)
return;
g_strfreev(config->host_key_document_paths);
g_strfreev(config->certificate_paths);
g_free(config->arp_key_out_path);
g_free(config->output_path);
}
static void pvattest_parse_clear_perform_config(pvattest_perform_config_t *config)
{
if (!config)
return;
g_free(config->input_path);
g_free(config->output_path);
}
static void pvattest_parse_clear_verify_config(pvattest_verify_config_t *config)
{
if (!config)
return;
g_free(config->input_path);
g_free(config->output_path);
g_free(config->hdr_path);
g_free(config->arp_key_in_path);
}
void pvattest_parse_clear_config(pvattest_config_t *config)
{
if (!config)
return;
pvattest_parse_clear_create_config(&config->create);
pvattest_parse_clear_perform_config(&config->perform);
pvattest_parse_clear_verify_config(&config->verify);
}

View File

@@ -1,113 +0,0 @@
/*
* Definitions used for parsing arguments.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PVATTEST_ARGPARSE_H
#define PVATTEST_ARGPARSE_H
/* Must be included before any other header */
#include "config.h"
#include <stdint.h>
#include "libpv/glib-helper.h"
#include "libpv/macros.h"
#define PVATTEST_SUBC_STR_CREATE "create"
#define PVATTEST_SUBC_STR_PERFORM "perform"
#define PVATTEST_SUBC_STR_VERIFY "verify"
enum pvattest_command {
PVATTEST_SUBC_INVALID,
PVATTEST_SUBC_CREATE,
PVATTEST_SUBC_PERFORM,
PVATTEST_SUBC_VERIFY,
};
typedef struct {
int log_level;
} pvattest_general_config_t;
typedef struct {
char **host_key_document_paths;
char **certificate_paths;
char **crl_paths;
char *root_ca_path;
char *arp_key_out_path;
char *output_path;
gboolean phkh_img;
gboolean phkh_att;
gboolean no_verify;
gboolean online;
/* experimental flags */
gboolean use_nonce; /* default TRUE */
uint64_t paf; /* default 0 */
int x_aad_size; /* default -1 -> ignore */
} pvattest_create_config_t;
typedef struct {
char *output_path;
char *input_path;
/* experimental flags */
char *user_data_path; /* default NULL */
} pvattest_perform_config_t;
enum verify_output_format {
VERIFY_FMT_HUMAN,
VERIFY_FMT_YAML,
};
typedef struct {
char *input_path;
char *output_path;
enum verify_output_format output_fmt;
char *hdr_path;
char *arp_key_in_path;
} pvattest_verify_config_t;
typedef struct {
pvattest_general_config_t general;
pvattest_create_config_t create;
pvattest_perform_config_t perform;
pvattest_verify_config_t verify;
} pvattest_config_t;
/**
* pvattest_parse_clear_config:
*
* @config: struct to be cleared
*
* clears but not frees all config.
* all non config members such like char* will be freed.
*/
void pvattest_parse_clear_config(pvattest_config_t *config);
/**
* pvattest_parse:
*
* @argc: ptr to argument count
* @argv: ptr to argument vector
* @config: output: ptr to parsed config. Target is statically allocated.
* You are responsible for freeing all non config ptrs.
* use #pvattest_parse_clear_config for that.
*
* Will not return if verbose or help parsed.
*
* Returns: selected command as enum
*/
enum pvattest_command pvattest_parse(int *argc, char **argvp[], pvattest_config_t **config,
GError **error) PV_NONNULL(1, 2, 3);
#define PVATTEST_ERROR g_quark_from_static_string("pv-pvattest_error-quark")
typedef enum {
PVATTEST_ERR_INV_ARGV,
PVATTEST_ERR_INV_ARG,
} pv_pvattest_error_e;
#endif /* PVATTEST_ARGPARSE_H */

View File

@@ -1,148 +0,0 @@
/*
* Attestation related functions
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include "libpv/cert.h"
#include "libpv/hash.h"
#include "libpv/se-hdr.h"
#include "exchange_format.h"
#include "attestation.h"
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->pld) == sizeof(((struct pv_hdr_head *)0)->pld));
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->ald) == sizeof(((struct pv_hdr_head *)0)->ald));
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->tld) == sizeof(((struct pv_hdr_head *)0)->tld));
G_STATIC_ASSERT(sizeof(((att_meas_ctx_t *)0)->tag) == sizeof(((struct pv_hdr *)0)->tag));
struct att_meas_sizes {
uint16_t user_data_len;
uint16_t zeros;
uint32_t additional_data_len;
} __packed;
G_STATIC_ASSERT(sizeof(struct att_meas_sizes) == 8);
/*
* All optional arguments may be NULL
* user_data is up to 256 bytes long, or NULL.
* nonce is 16 bytes long or NULL.
* additional_data is up to 32768 bytes long or NULL.
*/
GBytes *att_gen_measurement_hmac_sha512(const att_meas_ctx_t *meas_ctx, GBytes *measurement_key,
GBytes *optional_user_data, GBytes *optional_nonce,
GBytes *optional_additional_data, GError **error)
{
struct att_meas_sizes meas_sizes = {};
g_autoptr(HMAC_CTX) hmac_ctx = NULL;
size_t additional_data_size = 0;
size_t user_data_size = 0;
size_t nonce_size = 0;
pv_wrapped_g_assert(meas_ctx);
pv_wrapped_g_assert(measurement_key);
if (optional_user_data)
user_data_size = g_bytes_get_size(optional_user_data);
if (optional_additional_data)
additional_data_size = g_bytes_get_size(optional_additional_data);
if (optional_nonce)
nonce_size = g_bytes_get_size(optional_nonce);
/* checks for these sizes resulting in GErrors are done before */
g_assert(user_data_size <= PVATTEST_USER_DATA_MAX_SIZE);
g_assert(additional_data_size <= PVATTEST_ADDITIONAL_MAX_SIZE);
g_assert(nonce_size == 0 || nonce_size == ARCB_V1_NONCE_SIZE);
pv_wrapped_g_assert(meas_ctx);
pv_wrapped_g_assert(measurement_key);
hmac_ctx = pv_hmac_ctx_new(measurement_key, EVP_sha512(), error);
if (!hmac_ctx)
return NULL;
meas_sizes.user_data_len = GUINT16_TO_BE((uint16_t)user_data_size);
meas_sizes.zeros = 0;
meas_sizes.additional_data_len = GUINT32_TO_BE((uint32_t)additional_data_size);
if (pv_hmac_ctx_update_raw(hmac_ctx, meas_ctx, sizeof(*meas_ctx), error) != 0)
return NULL;
/* add the sizes of user and additional data. */
if (pv_hmac_ctx_update_raw(hmac_ctx, &meas_sizes, sizeof(meas_sizes), error))
return NULL;
/* update optional data. if NULL passed (or size = 0) nothing will happen to the HMAC_CTX */
if (pv_hmac_ctx_update(hmac_ctx, optional_user_data, error) != 0)
return NULL;
if (pv_hmac_ctx_update(hmac_ctx, optional_nonce, error) != 0)
return NULL;
if (pv_hmac_ctx_update(hmac_ctx, optional_additional_data, error) != 0)
return NULL;
return pv_hamc_ctx_finalize(hmac_ctx, error);
}
att_meas_ctx_t *att_extract_from_hdr(GBytes *se_hdr, GError **error)
{
g_autofree att_meas_ctx_t *meas = NULL;
const struct pv_hdr *hdr = NULL;
size_t se_hdr_tag_offset;
size_t se_hdr_size;
uint8_t *hdr_u8;
pv_wrapped_g_assert(se_hdr);
hdr = g_bytes_get_data(se_hdr, &se_hdr_size);
hdr_u8 = (uint8_t *)hdr;
if (se_hdr_size < PV_V1_PV_HDR_MIN_SIZE) {
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_HDR,
_("Invalid SE header provided."));
return NULL;
}
if (GUINT32_FROM_BE(hdr->head.phs) != se_hdr_size ||
GUINT64_FROM_BE(hdr->head.magic) != PV_MAGIC_NUMBER) {
g_set_error(error, ATT_ERROR, ATT_ERR_INVALID_HDR,
_("Invalid SE header provided."));
return NULL;
}
se_hdr_tag_offset = GUINT32_FROM_BE(hdr->head.phs) - sizeof(hdr->tag);
meas = g_new0(att_meas_ctx_t, 1);
memcpy(meas->pld, hdr->head.pld, sizeof(meas->pld));
memcpy(meas->ald, hdr->head.ald, sizeof(meas->ald));
memcpy(meas->tld, hdr->head.tld, sizeof(meas->tld));
memcpy(meas->tag, hdr_u8 + se_hdr_tag_offset, sizeof(meas->tag));
return g_steal_pointer(&meas);
}
void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid)
{
pv_wrapped_g_assert(meas_ctx);
pv_wrapped_g_assert(config_uid);
g_assert(g_bytes_get_size(config_uid) == ATT_CONFIG_UID_SIZE);
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid, NULL);
}
gboolean att_verify_measurement(const GBytes *calculated_measurement,
const GBytes *uvio_measurement, GError **error)
{
pv_wrapped_g_assert(calculated_measurement);
pv_wrapped_g_assert(uvio_measurement);
if (g_bytes_compare(calculated_measurement, uvio_measurement) != 0) {
g_set_error(error, ATT_ERROR, ATT_ERR_MEASUREMENT_VERIFICATION_FAILED,
_("Calculated and received attestation measurement are not equal."));
return FALSE;
}
return TRUE;
}

View File

@@ -1,99 +0,0 @@
/*
* Attestation related functions and definitions.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PVATTEST_ATTESTATION_H
#define PVATTEST_ATTESTATION_H
/* Must be included before any other header */
#include "config.h"
#include <openssl/sha.h>
#include "libpv/glib-helper.h"
#include "libpv/crypto.h"
#include "libpv/cert.h"
#include "common.h"
#include "types.h"
#include "arcb.h"
#define ATT_CONFIG_UID_SIZE 16
typedef struct {
uint8_t pld[SHA512_DIGEST_LENGTH];
uint8_t ald[SHA512_DIGEST_LENGTH];
uint8_t tld[SHA512_DIGEST_LENGTH];
uint8_t tag[AES_256_GCM_TAG_SIZE];
uint8_t config_uid[ATT_CONFIG_UID_SIZE];
} __packed att_meas_ctx_t;
G_STATIC_ASSERT(sizeof(att_meas_ctx_t) == 224);
/**
* att_gen_measurement_hmac_sha512:
*
* @meas_ctx: measurement context.
* @measurement_key: AES-256-GCM key for generating the measurement calculation.
* @optional_user_data: NULL or up to 256 bytes GBytes.
* @optional_nonce: NULL or a nonce of exactly `ARCB_V1_NONCE_SIZE` bytes
* @optional_additional_data: NULL or up to 0x8000 bytes of GBytes.
* @error: GError. *error will != NULL if error occurs.
*
* Calculates the measurement value.
* If the input data is the same which the UV used in the Retrieve Attestation Measurement
* the result should be identical to the data in the ´Measurement Data Address´ UVC.
*
* Returns: (nullable) (transfer full): a hmac_sha512 of the given data.
*/
GBytes *att_gen_measurement_hmac_sha512(const att_meas_ctx_t *meas_ctx, GBytes *measurement_key,
GBytes *optional_user_data, GBytes *optional_nonce,
GBytes *optional_additional_data, GError **error)
PV_NONNULL(1, 2);
/**
* att_extract_from_hdr:
*
* @se_hdr: binary SE guest header.
* @error: GError. *error will != NULL if error occurs.
*
* Verifies that SE header size and magic ,but no cryptographical verification.
* Then, find and extracts pld, ald, tld, and SE tagi and adds it to the context.
*
* Returns: new attestation measurement context.
*/
att_meas_ctx_t *att_extract_from_hdr(GBytes *se_hdr, GError **error) PV_NONNULL(1);
/** att_add_uid:
*
* @meas_ctx: measurement context.
* @config_uid: pointer to config UID. Must be `ATT_CONFIG_UID_SIZE` bytes long.
*
* Copies the config UID to the measurement context.
* Wrong size is considered as a Programming error.
*/
void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid) PV_NONNULL(1, 2);
/** att_verify_measurement:
*
* @calculated_measurement: measurement calculated by a trusted system
* @uvio_measurement: measurement generated by an UV
* @error: GError. *error will != NULL if error occurs.
*
* Returns: TRUE if measurements are identical, otherwise FALSE
*/
gboolean att_verify_measurement(const GBytes *calculated_measurement,
const GBytes *uvio_measurement, GError **error) PV_NONNULL(1, 2);
#define ATT_ERROR g_quark_from_static_string("pv-att_error-quark")
typedef enum att_error {
ATT_ERR_INVALID_HDR,
ATT_ERR_INVALID_USER_DATA,
ATT_ERR_MEASUREMENT_VERIFICATION_FAILED,
ATT_ERR_PHKH_NO_FIT_IN_USER_DATA,
ATT_ERR_PHKH_NO_MATCH,
} att_error_e;
#endif /* PVATTEST_ATTESTATION_H */

View File

@@ -1,47 +0,0 @@
/*
* Common functions for pvattest.
*
* Copyright IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include <stdio.h>
#include <sys/stat.h>
#include "libpv/glib-helper.h"
#include "types.h"
#include "common.h"
gboolean wrapped_g_file_set_content(const char *filename, GBytes *bytes, mode_t mode,
GError **error)
{
const void *data;
size_t size;
gboolean rc;
data = g_bytes_get_data(bytes, &size);
rc = g_file_set_contents(filename, data, (ssize_t)size, error);
if (rc && mode != 0666)
chmod(filename, mode);
return rc;
}
GBytes *secure_gbytes_concat(GBytes *lh, GBytes *rh)
{
g_autoptr(GByteArray) lha = NULL;
if (!lh && !rh)
return NULL;
if (!lh)
return g_bytes_ref(rh);
if (!rh)
return g_bytes_ref(lh);
lha = g_bytes_unref_to_array(g_bytes_ref(lh));
g_byte_array_append(lha, g_bytes_get_data(rh, NULL), (guint)g_bytes_get_size(rh));
return pv_sec_gbytes_new(lha->data, lha->len);
}

View File

@@ -1,37 +0,0 @@
/*
* Common functions for pvattest.
*
* IBM Corp. 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PVATTEST_COMMON_H
#define PVATTEST_COMMON_H
/* Must be included before any other header */
#include "config.h"
#include <stdio.h>
#include "libpv/glib-helper.h"
#include <glib/gi18n.h>
#include "libpv/macros.h"
#include "lib/zt_common.h"
#include "types.h"
#define COPYRIGHT_NOTICE "Copyright IBM Corp. 2022"
#define AES_256_GCM_TAG_SIZE 16
gboolean wrapped_g_file_set_content(const char *filename, GBytes *bytes, mode_t mode,
GError **error);
/**
* just ref's up if one of them is NULL.
* If both NULL returns NULL.
* Otherwise returns lh ++ rh
*/
GBytes *secure_gbytes_concat(GBytes *lh, GBytes *rh);
#endif /* PVATTEST_COMMON_H */

Some files were not shown because too many files have changed in this diff Show More