forked from pool/s390-tools
Accepting request 854129 from Base:System
OBS-URL: https://build.opensuse.org/request/show/854129 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/s390-tools?expand=0&rev=34
This commit is contained in:
commit
26a26a5a1d
@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd1883e12f9da16be6b081508108abd3ce8cd80168efe4cd339ba33837f8f4aa
|
||||
size 1164539
|
3
s390-tools-2.15.1.tar.gz
Normal file
3
s390-tools-2.15.1.tar.gz
Normal file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8dc1180031018756ccd5acf6c26c4175bcac79e512e8a2ea8569fdf5d3f9bd6c
|
||||
size 1390556
|
@ -1,436 +0,0 @@
|
||||
From d6582bbaf0f3986a42f562046dc0caa9de89c75e Mon Sep 17 00:00:00 2001
|
||||
From: Hannes Reinecke <hare@suse.de>
|
||||
Date: Fri, 6 Oct 2017 08:58:17 +0200
|
||||
Subject: [PATCH] dasdfmt: Allow multiple device arguments
|
||||
|
||||
Allow the user to specify several devices as arguments to dasdfmt.
|
||||
|
||||
Signed-off-by: Hannes Reinecke <hare@suse.com>
|
||||
---
|
||||
dasdfmt/dasdfmt.8 | 5 +-
|
||||
dasdfmt/dasdfmt.c | 175 ++++++++++++++++++++++++++++++------------------------
|
||||
2 files changed, 100 insertions(+), 80 deletions(-)
|
||||
|
||||
diff --git a/dasdfmt/dasdfmt.8 b/dasdfmt/dasdfmt.8
|
||||
index 99da9ed..e7fc501 100644
|
||||
--- a/dasdfmt/dasdfmt.8
|
||||
+++ b/dasdfmt/dasdfmt.8
|
||||
@@ -11,14 +11,15 @@ dasdfmt \- formatting of DASD (ECKD) disk drives.
|
||||
.br
|
||||
[-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 [\fIdevice\fR]
|
||||
|
||||
.SH DESCRIPTION
|
||||
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
|
||||
+\fBdasdfmt\fR formats one or several DASD (ECKD) disk drive to prepare it
|
||||
for usage with Linux for S/390.
|
||||
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
|
||||
(e.g. '/dev/dasd/0.0.b100/disc').
|
||||
+It is possible to specify up to 512 devices.
|
||||
.br
|
||||
|
||||
\fBWARNING\fR: Careless usage of \fBdasdfmt\fR can result in
|
||||
diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c
|
||||
index b79cff0..607fd1c 100644
|
||||
--- a/dasdfmt/dasdfmt.c
|
||||
+++ b/dasdfmt/dasdfmt.c
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "dasdfmt.h"
|
||||
|
||||
+#define MAX_DEVICES 512
|
||||
#define BUSIDSIZE 8
|
||||
#define SEC_PER_DAY (60 * 60 * 24)
|
||||
#define SEC_PER_HOUR (60 * 60)
|
||||
@@ -463,44 +464,40 @@ static void program_interrupt_signal(int sig)
|
||||
/*
|
||||
* check given device name for blanks and some special characters
|
||||
*/
|
||||
-static void get_device_name(char *devname,
|
||||
- int optind, int argc, char *argv[])
|
||||
+static void get_device_name(char **devname, int numdev,
|
||||
+ char argv[])
|
||||
{
|
||||
struct util_proc_dev_entry dev_entry;
|
||||
struct stat dev_stat;
|
||||
|
||||
- if (optind + 1 < argc)
|
||||
- ERRMSG_EXIT(EXIT_MISUSE,
|
||||
- "%s: More than one device specified!\n", prog_name);
|
||||
-
|
||||
- if (optind >= argc)
|
||||
- ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
|
||||
- prog_name);
|
||||
-
|
||||
- if (strlen(argv[optind]) >= PATH_MAX)
|
||||
+ if (strlen(argv) >= PATH_MAX)
|
||||
ERRMSG_EXIT(EXIT_MISUSE, "%s: device name too long!\n",
|
||||
prog_name);
|
||||
- strcpy(devname, argv[optind]);
|
||||
|
||||
- if (stat(devname, &dev_stat) != 0)
|
||||
- ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for "
|
||||
- "device node %s: %s\n", prog_name, devname,
|
||||
- strerror(errno));
|
||||
+ devname[numdev] = argv;
|
||||
+ if (stat(devname[numdev], &dev_stat) != 0)
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE,
|
||||
+ "%s: Could not get information for "
|
||||
+ "device node %s: %s\n", prog_name,
|
||||
+ devname[numdev], strerror(errno));
|
||||
|
||||
if (minor(dev_stat.st_rdev) & PARTN_MASK) {
|
||||
- ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. "
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE,
|
||||
+ "%s: Unable to format partition %s. "
|
||||
"Please specify a device.\n", prog_name,
|
||||
- devname);
|
||||
+ devname[numdev]);
|
||||
}
|
||||
|
||||
- if (util_proc_dev_get_entry(dev_stat.st_rdev, 1, &dev_entry) == 0) {
|
||||
+ if (util_proc_dev_get_entry(dev_stat.st_rdev, 1,
|
||||
+ &dev_entry) == 0) {
|
||||
if (strncmp(dev_entry.name, "dasd", 4) != 0)
|
||||
ERRMSG_EXIT(EXIT_MISUSE,
|
||||
"%s: Unsupported device type '%s'.\n",
|
||||
prog_name, dev_entry.name);
|
||||
} else {
|
||||
- printf("%s WARNING: Unable to get driver name for device node %s",
|
||||
- prog_name, devname);
|
||||
+ printf("%s WARNING: Unable to get driver name"
|
||||
+ " for device node %s",
|
||||
+ prog_name, devname[numdev]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,7 +515,7 @@ static void get_blocksize(const char *de
|
||||
/*
|
||||
* Check whether a specified blocksize matches the blocksize of the device
|
||||
*/
|
||||
-static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize)
|
||||
+static void check_blocksize(dasdfmt_info_t *info, char *dev_filename, unsigned int blksize)
|
||||
{
|
||||
unsigned int dev_blksize;
|
||||
|
||||
@@ -756,7 +753,7 @@ static void check_hashmarks(dasdfmt_info
|
||||
* This function checks whether a range of tracks is in regular format
|
||||
* with the specified block size.
|
||||
*/
|
||||
-static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
|
||||
+static format_check_t check_track_format(dasdfmt_info_t *info, char *dev_filename, format_data_t *p)
|
||||
{
|
||||
format_check_t cdata = {
|
||||
.expect = {
|
||||
@@ -812,7 +809,7 @@ static int process_tracks(dasdfmt_info_t
|
||||
step.stop_unit = cur_trk + step_value - 1;
|
||||
|
||||
if (info->check) {
|
||||
- cdata = check_track_format(info, &step);
|
||||
+ cdata = check_track_format(info, dev_filename, &step);
|
||||
if (cdata.result) {
|
||||
cyl = cur_trk / heads + 1;
|
||||
draw_progress(info, cyl, cylinders, 1);
|
||||
@@ -858,7 +855,7 @@ static void check_disk_format(dasdfmt_in
|
||||
return;
|
||||
}
|
||||
|
||||
- check_blocksize(info, check_params->blksize);
|
||||
+ check_blocksize(info, dev_filename, check_params->blksize);
|
||||
check_layout(info, check_params->intensity);
|
||||
|
||||
/*
|
||||
@@ -1188,7 +1185,7 @@ static void dasdfmt_write_labels(dasdfmt
|
||||
* that the device is formatted to a certain extent. Otherwise the
|
||||
* process is terminated.
|
||||
*/
|
||||
-static void dasdfmt_find_start(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
+static void dasdfmt_find_start(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
|
||||
unsigned heads, format_data_t *format_params)
|
||||
{
|
||||
format_check_t cdata;
|
||||
@@ -1197,11 +1194,11 @@ static void dasdfmt_find_start(dasdfmt_i
|
||||
unsigned int right = (cylinders * heads) - 1;
|
||||
unsigned int first = left;
|
||||
|
||||
- check_blocksize(info, format_params->blksize);
|
||||
+ check_blocksize(info, dev_filename, format_params->blksize);
|
||||
|
||||
format_params->start_unit = 0;
|
||||
format_params->stop_unit = 4;
|
||||
- cdata = check_track_format(info, format_params);
|
||||
+ cdata = check_track_format(info, dev_filename, format_params);
|
||||
|
||||
if (cdata.result) {
|
||||
evaluate_format_error(info, &cdata, heads);
|
||||
@@ -1217,7 +1214,7 @@ static void dasdfmt_find_start(dasdfmt_i
|
||||
|
||||
format_params->start_unit = middle;
|
||||
format_params->stop_unit = middle;
|
||||
- cdata = check_track_format(info, format_params);
|
||||
+ cdata = check_track_format(info, dev_filename, format_params);
|
||||
if (cdata.blksize != format_params->blksize) {
|
||||
first = middle;
|
||||
right = middle - 1;
|
||||
@@ -1266,6 +1263,7 @@ static void dasdfmt_release_space(dasdfm
|
||||
}
|
||||
|
||||
static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
||||
+ char *dev_filename,
|
||||
unsigned int cylinders,
|
||||
unsigned int heads, format_data_t *p)
|
||||
{
|
||||
@@ -1324,7 +1322,7 @@ static void dasdfmt_prepare_and_format(d
|
||||
/*
|
||||
* This function will start the expand format process.
|
||||
*/
|
||||
-static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
+static void dasdfmt_expand_format(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
|
||||
unsigned int heads, format_data_t *p)
|
||||
{
|
||||
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||
@@ -1351,7 +1349,7 @@ static void dasdfmt_expand_format(dasdfm
|
||||
* This function will only format the first two tracks of a DASD.
|
||||
* The rest of the DASD is untouched and left as is.
|
||||
*/
|
||||
-static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||
+static void dasdfmt_quick_format(dasdfmt_info_t *info, char *dev_filename, unsigned int cylinders,
|
||||
unsigned int heads, format_data_t *p)
|
||||
{
|
||||
format_check_t cdata = { .expect = {0}, 0 };
|
||||
@@ -1363,18 +1361,18 @@ static void dasdfmt_quick_format(dasdfmt
|
||||
} else if (info->ese) {
|
||||
printf("Skipping format check due to thin-provisioned device.\n");
|
||||
} else {
|
||||
- check_blocksize(info, p->blksize);
|
||||
+ check_blocksize(info, dev_filename, p->blksize);
|
||||
|
||||
printf("Checking the format of selected tracks...\n");
|
||||
|
||||
/* Check device format on the first and last 3 regular tracks */
|
||||
tmp.start_unit = 2;
|
||||
tmp.stop_unit = 4;
|
||||
- cdata = check_track_format(info, &tmp);
|
||||
+ cdata = check_track_format(info, dev_filename, &tmp);
|
||||
if (!cdata.result) {
|
||||
tmp.start_unit = (cylinders * heads) - 3;
|
||||
tmp.stop_unit = (cylinders * heads) - 1;
|
||||
- cdata = check_track_format(info, &tmp);
|
||||
+ cdata = check_track_format(info, dev_filename, &tmp);
|
||||
}
|
||||
if (cdata.result) {
|
||||
evaluate_format_error(info, &cdata, heads);
|
||||
@@ -1419,7 +1417,7 @@ static void do_format_dasd(dasdfmt_info_
|
||||
p->stop_unit = 1;
|
||||
break;
|
||||
case EXPAND: /* only the end of the disk */
|
||||
- dasdfmt_find_start(info, cylinders, heads, p);
|
||||
+ dasdfmt_find_start(info, devname, cylinders, heads, p);
|
||||
p->stop_unit = (cylinders * heads) - 1;
|
||||
break;
|
||||
}
|
||||
@@ -1468,24 +1466,24 @@ static void do_format_dasd(dasdfmt_info_
|
||||
|
||||
switch (mode) {
|
||||
case FULL:
|
||||
- dasdfmt_prepare_and_format(info, cylinders, heads, p);
|
||||
+ dasdfmt_prepare_and_format(info, devname, cylinders, heads, p);
|
||||
break;
|
||||
case QUICK:
|
||||
dasdfmt_release_space(info);
|
||||
- dasdfmt_quick_format(info, cylinders, heads, p);
|
||||
+ dasdfmt_quick_format(info, devname, cylinders, heads, p);
|
||||
break;
|
||||
case EXPAND:
|
||||
- dasdfmt_expand_format(info, cylinders, heads, p);
|
||||
+ dasdfmt_expand_format(info, devname, cylinders, heads, p);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Finished formatting the device.\n");
|
||||
|
||||
if (!(info->writenolabel || mode == EXPAND))
|
||||
- dasdfmt_write_labels(info, vlabel, cylinders, heads);
|
||||
+ dasdfmt_write_labels(info, devname, vlabel, cylinders, heads);
|
||||
|
||||
printf("Rereading the partition table... ");
|
||||
- err = dasd_reread_partition_table(dev_filename, 5);
|
||||
+ err = dasd_reread_partition_table(devname, 5);
|
||||
if (err != 0) {
|
||||
ERRMSG("%s: error during rereading the partition "
|
||||
"table: %s.\n", prog_name, strerror(err));
|
||||
@@ -1508,23 +1506,88 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
||||
mode = info->ese ? QUICK : FULL;
|
||||
}
|
||||
|
||||
+void do_dasdfmt(char *dev_filename, dasdfmt_info_t info,
|
||||
+ volume_label_t *orig_vlabel, format_data_t format_params)
|
||||
+{
|
||||
+ volume_label_t vlabel;
|
||||
+ char old_volser[7];
|
||||
+ char str[ERR_LENGTH];
|
||||
+ unsigned int cylinders, heads; int rc;
|
||||
+
|
||||
+ filedes = open(dev_filename, O_RDWR);
|
||||
+ if (filedes == -1)
|
||||
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
|
||||
+ prog_name, dev_filename, strerror(errno));
|
||||
+ close(filedes);
|
||||
+
|
||||
+ rc = dasd_get_info(dev_filename, &info.dasd_info);
|
||||
+ if (rc != 0)
|
||||
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
||||
+ "device information for %s failed (%s).\n",
|
||||
+ prog_name, dev_filename, strerror(rc));
|
||||
+
|
||||
+ memcpy(&vlabel, orig_vlabel, sizeof(vlabel));
|
||||
+ /* Either let the user specify the blksize or get it from the kernel */
|
||||
+ if (!info.blksize_specified) {
|
||||
+ if (!(mode == FULL ||
|
||||
+ info.dasd_info.format == DASD_FORMAT_NONE)
|
||||
+ || info.check)
|
||||
+ get_blocksize(dev_filename, &format_params.blksize);
|
||||
+ else
|
||||
+ format_params = ask_user_for_blksize(format_params);
|
||||
+ }
|
||||
+
|
||||
+ if (info.keep_volser) {
|
||||
+ if (info.labelspec) {
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options "
|
||||
+ "are mutually exclusive\n", prog_name);
|
||||
+ }
|
||||
+ if (!(format_params.intensity & DASD_FMT_INT_COMPAT)) {
|
||||
+ printf("WARNING: VOLSER cannot be kept "
|
||||
+ "when using the ldl format!\n");
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
+ if (dasdfmt_get_volser(dev_filename,
|
||||
+ &info.dasd_info, old_volser) == 0)
|
||||
+ vtoc_volume_label_set_volser(&vlabel, old_volser);
|
||||
+ else
|
||||
+ ERRMSG_EXIT(EXIT_FAILURE,
|
||||
+ "%s: VOLSER not found on device %s\n",
|
||||
+ prog_name, dev_filename);
|
||||
+ }
|
||||
+
|
||||
+ check_disk(&info, dev_filename);
|
||||
+
|
||||
+ if (check_param(str, ERR_LENGTH, &format_params) < 0)
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
|
||||
+
|
||||
+ set_geo(&info, &cylinders, &heads);
|
||||
+ set_label(&info, &vlabel, &format_params, cylinders);
|
||||
+
|
||||
+ if (info.check)
|
||||
+ check_disk_format(&info, cylinders, heads, &format_params);
|
||||
+ else
|
||||
+ do_format_dasd(&info, dev_filename, &vlabel,
|
||||
+ &format_params, cylinders, heads);
|
||||
+
|
||||
+}
|
||||
+
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
dasdfmt_info_t info = {
|
||||
.dasd_info = {0},
|
||||
};
|
||||
volume_label_t vlabel;
|
||||
- char old_volser[7];
|
||||
|
||||
- char str[ERR_LENGTH];
|
||||
+ char *dev_filename[MAX_DEVICES];
|
||||
char buf[7];
|
||||
|
||||
char *blksize_param_str = NULL;
|
||||
char *reqsize_param_str = NULL;
|
||||
char *hashstep_str = NULL;
|
||||
|
||||
- int rc;
|
||||
- unsigned int cylinders, heads;
|
||||
+ int rc, numdev = 0, i;
|
||||
|
||||
/* Establish a handler for interrupt signals. */
|
||||
signal(SIGTERM, program_interrupt_signal);
|
||||
@@ -1686,59 +1751,24 @@ int main(int argc, char *argv[])
|
||||
if (info.print_hashmarks)
|
||||
PARSE_PARAM_INTO(info.hashstep, hashstep_str, 10, "hashstep");
|
||||
|
||||
- get_device_name(dev_filename, optind, argc, argv);
|
||||
-
|
||||
- rc = dasd_get_info(dev_filename, &info.dasd_info);
|
||||
- if (rc != 0)
|
||||
- ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
||||
- "device information failed (%s).\n",
|
||||
- prog_name, strerror(rc));
|
||||
-
|
||||
- info.ese = dasd_sys_ese(dev_filename);
|
||||
- eval_format_mode(&info);
|
||||
-
|
||||
- /* Either let the user specify the blksize or get it from the kernel */
|
||||
- if (!info.blksize_specified) {
|
||||
- if (!(mode == FULL ||
|
||||
- info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
|
||||
- get_blocksize(dev_filename, &format_params.blksize);
|
||||
- else
|
||||
- format_params = ask_user_for_blksize(format_params);
|
||||
- }
|
||||
-
|
||||
- if (info.keep_volser) {
|
||||
- if (info.labelspec) {
|
||||
- ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options "
|
||||
- "are mutually exclusive\n", prog_name);
|
||||
- }
|
||||
- if (!(format_params.intensity & DASD_FMT_INT_COMPAT)) {
|
||||
- printf("WARNING: VOLSER cannot be kept "
|
||||
- "when using the ldl format!\n");
|
||||
- exit(1);
|
||||
- }
|
||||
-
|
||||
- if (dasdfmt_get_volser(dev_filename,
|
||||
- &info.dasd_info, old_volser) == 0)
|
||||
- vtoc_volume_label_set_volser(&vlabel, old_volser);
|
||||
- else
|
||||
- ERRMSG_EXIT(EXIT_FAILURE,
|
||||
- "%s: VOLSER not found on device %s\n",
|
||||
- prog_name, dev_filename);
|
||||
+ while (optind < argc) {
|
||||
+ if (optind >= argc)
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
|
||||
+ prog_name);
|
||||
+
|
||||
+ info.ese = dasd_sys_ese(dev_filename[numdev]);
|
||||
+ eval_format_mode(&info);
|
||||
+
|
||||
+ get_device_name(dev_filename, numdev, argv[optind]);
|
||||
+ optind++;
|
||||
+ numdev++;
|
||||
}
|
||||
|
||||
- check_disk(&info, dev_filename);
|
||||
-
|
||||
- if (check_param(str, ERR_LENGTH, &format_params) < 0)
|
||||
- ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str);
|
||||
-
|
||||
- set_geo(&info, &cylinders, &heads);
|
||||
- set_label(&info, &vlabel, &format_params, cylinders);
|
||||
-
|
||||
- if (info.check)
|
||||
- check_disk_format(&info, cylinders, heads, &format_params);
|
||||
- else
|
||||
- do_format_dasd(&info, dev_filename, &vlabel,
|
||||
- &format_params, cylinders, heads);
|
||||
+ if (!numdev)
|
||||
+ ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n",
|
||||
+ prog_name);
|
||||
|
||||
+ for (i = 0; i < numdev; i++)
|
||||
+ do_dasdfmt(dev_filename[i], info, &vlabel, format_params);
|
||||
return 0;
|
||||
}
|
||||
--
|
||||
1.7.12.4
|
||||
|
@ -1,21 +1,6 @@
|
||||
From c261ec990a8259f2540089827309b918e1c31590 Mon Sep 17 00:00:00 2001
|
||||
From: Hannes Reinecke <hare@suse.de>
|
||||
Date: Fri, 22 Nov 2013 15:34:22 +0100
|
||||
Subject: [PATCH] dumpconf: Use compatible sysconfig layout
|
||||
|
||||
SUSE is quite restrictive on how the sysconfig
|
||||
should look like.
|
||||
|
||||
Signed-off-by: Hannes Reinecke <hare@suse.de>
|
||||
---
|
||||
etc/sysconfig/dumpconf | 134 ++++++++++++++++++++++++++++++++++---------------
|
||||
1 file changed, 93 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/etc/sysconfig/dumpconf b/etc/sysconfig/dumpconf
|
||||
index a3639cf..76f9040 100644
|
||||
--- a/etc/sysconfig/dumpconf
|
||||
+++ b/etc/sysconfig/dumpconf
|
||||
@@ -1,61 +1,113 @@
|
||||
--- a/etc/sysconfig/dumpconf 2020-10-15 09:56:15.000000000 -0400
|
||||
+++ b/etc/sysconfig/dumpconf 2020-10-27 18:47:23.267333389 -0400
|
||||
@@ -1,71 +1,137 @@
|
||||
+## Path: System/Dumpconf
|
||||
+## Description: Configures the actions which should be performed after a kernel panic
|
||||
+## Type: list(stop,dump,vmcmd,reipl,dump_reipl)
|
||||
@ -26,7 +11,7 @@ index a3639cf..76f9040 100644
|
||||
-#
|
||||
-# Configures the actions which should be performed after a kernel panic
|
||||
-# and on PSW restart.
|
||||
+# Define the action that should be taken if a panic happens.
|
||||
+# Define the action that should be taken if a kernel panic happens.
|
||||
#
|
||||
# The following actions are supported:
|
||||
#
|
||||
@ -67,16 +52,16 @@ index a3639cf..76f9040 100644
|
||||
-# Dump on CCW device (DASD) and re-IPL after dump is complete.
|
||||
-# The re-IPL device, as specified under "/sys/firmware/reipl", is used.
|
||||
-# The activation of dumpconf is delayed by 5 minutes.
|
||||
+## Type: list(ccw,fcp)
|
||||
+## Type: list(ccw,fcp,nvme)
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
+# Define the type, ccw for DASD and fcp for zFCP.
|
||||
#
|
||||
-# ON_PANIC=dump_reipl
|
||||
-# DUMP_TYPE=ccw
|
||||
-# DEVICE=0.0.4e13
|
||||
-# DELAY_MINUTES=5
|
||||
+# Define the type, ccw for DASD, fcp for zFCP, or nvme for NVMe Disk.
|
||||
+#
|
||||
+DUMP_TYPE=""
|
||||
|
||||
+## Type: string
|
||||
@ -100,68 +85,99 @@ index a3639cf..76f9040 100644
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
#
|
||||
-# Dump on nvme device (NVMe Disk)
|
||||
+# Define the WWPN for a zFCP dump device.
|
||||
#
|
||||
-# Use VMDUMP
|
||||
-# ON_PANIC=dump
|
||||
-# DUMP_TYPE=nvme
|
||||
-# FID=0x00000300
|
||||
-# NSID=0x00000001
|
||||
-# BOOTPROG=3
|
||||
-# BR_LBA=0
|
||||
+# For example: WWPN=0x5005076303004711
|
||||
#
|
||||
-# ON_PANIC=vmcmd
|
||||
-# VMCMD_1="MESSAGE * Starting VMDUMP"
|
||||
-# VMCMD_2="VMDUMP"
|
||||
-# VMCMD_3="IPL 4711"
|
||||
+#
|
||||
+WWPN=""
|
||||
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
#
|
||||
-# Use VMDUMP
|
||||
+# Define the LUN for a zFCP dump device.
|
||||
+#
|
||||
#
|
||||
-# ON_PANIC=vmcmd
|
||||
-# VMCMD_1="MESSAGE * Starting VMDUMP"
|
||||
-# VMCMD_2="VMDUMP"
|
||||
-# VMCMD_3="IPL 4711"
|
||||
+# For example: LUN=0x4711000000000000
|
||||
+#
|
||||
+LUN=""
|
||||
+
|
||||
|
||||
+## Type: integer(0:30)
|
||||
+## Default: "0"
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
#
|
||||
-# Stop Linux (default)
|
||||
+# Define the Boot program selector for a zFCP dump device.
|
||||
+#
|
||||
#
|
||||
-# ON_PANIC=stop
|
||||
+# A decimal value between 0 and 30 specifying the program to be loaded from
|
||||
+# the FCP-I/O device.
|
||||
+#
|
||||
+BOOTPROG="0"
|
||||
+
|
||||
+## Type: string
|
||||
+## Default: "0"
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
+# Define the Boot record logical block address for a zFCP dump device.
|
||||
#
|
||||
-# Stop Linux (default)
|
||||
+# The hexadecimal digits designating the logical-block address of the boot record of the FCP-I/O device.
|
||||
+# It must be a value from 0-FFFFFFFF FFFFFFFF. For values longer than 8 hex characters at least one separator
|
||||
+# blank is required after the 8th character.
|
||||
#
|
||||
-# ON_PANIC=stop
|
||||
+BR_LBA="0"
|
||||
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## Default: "0"
|
||||
+## ServiceRestart: dumpconf
|
||||
#
|
||||
-# Re-IPL Linux
|
||||
-# The re-IPL device, as specified under "/sys/firmware/reipl", is used.
|
||||
-# Since the DELAY_MINUTES keyword is omitted, there is no delay and
|
||||
-# dumpconf becomes active immediately during system startup.
|
||||
+# Define the Boot record logical block address for a zFCP dump device.
|
||||
#
|
||||
-# ON_PANIC=reipl
|
||||
+# The hexadecimal digits designating the logical-block address of the boot record of the FCP-I/O device.
|
||||
+# It must be a value from 0-FFFFFFFF FFFFFFFF. For values longer than 8 hex characters at least one separator
|
||||
+# blank is required after the 8th character.
|
||||
+#
|
||||
+BR_LBA="0"
|
||||
+
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
+# Define the Function ID for NVMe dump device.
|
||||
+#
|
||||
+# The hexadecimal digits designating the Function ID for the NMVe disk.
|
||||
+#
|
||||
+# For example: FID=0x00000300
|
||||
+#
|
||||
+FID=""
|
||||
+
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
+# Define the Namespace ID for the NVMe dump device
|
||||
+#
|
||||
+# The hexadecimal digits designating the Namespace ID for the NMVe disk.
|
||||
+#
|
||||
+# For example: NSID=0x00000001
|
||||
+#
|
||||
+NSID=""
|
||||
+
|
||||
+## Type: string
|
||||
+## Default: ""
|
||||
+## ServiceRestart: dumpconf
|
||||
+#
|
||||
+# VMCMD_<X>
|
||||
+# Specifies a CP command, <X> is a number from one to eight. You can
|
||||
+# specify up to eight CP commands that are executed in case of a kernel
|
||||
+# panic. Note that VM commands, device adresses, and VM guest names
|
||||
+# must be uppercase.
|
||||
#
|
||||
-# ON_PANIC=reipl
|
||||
+#
|
||||
+VMCMD_1=""
|
||||
+VMCMD_2=""
|
||||
+VMCMD_3=""
|
||||
@ -170,6 +186,3 @@ index a3639cf..76f9040 100644
|
||||
+VMCMD_6=""
|
||||
+VMCMD_7=""
|
||||
+VMCMD_8=""
|
||||
--
|
||||
1.8.1.4
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- a/zdev/dracut/95zdev/module-setup.sh 2019-01-10 11:39:08.000000000 -0500
|
||||
+++ b/zdev/dracut/95zdev/module-setup.sh 2019-01-14 13:28:33.983461097 -0500
|
||||
@@ -32,7 +32,7 @@
|
||||
installkernel() {
|
||||
# Add modules for all device types supported by chzdev (required for
|
||||
# auto-configuration)
|
||||
- instmods lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
+ instmods ctcm lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod \
|
||||
dasd_diag_mod zfcp
|
||||
}
|
||||
|
@ -1,442 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184585] cpumf/data: Add new deflate counters for IBM z15
|
||||
From: Thomas Richter <tmricht@linux.ibm.com>
|
||||
|
||||
Description: lscpumf: New z15 CPU-MF counters not available
|
||||
Symptom: Command lscpumf -c does not show the new
|
||||
deflate counters on IBM z15.
|
||||
Problem: The new counter names have not been published
|
||||
in document SA23-2261-06 by the time te code was
|
||||
release.
|
||||
Solution: Add the definition for the new deflate counters.
|
||||
Reproduction: Run command lscpumf -c and check for counters
|
||||
rf7, rfc, r107 and r108.
|
||||
Upstream-ID: 5d2871d626de6c2b3ab6b12783b87a8b3564cb56
|
||||
Problem-ID: 184585
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
cpumf/data: Add new deflate counters for IBM z15
|
||||
|
||||
Add support for new deflate counters:
|
||||
- Counter 247: cycles CPU spent obtaining access to Deflate unit
|
||||
- Counter 252: cycles CPU is using Deflate unit
|
||||
- Counter 264: Increments by one for every DEFLATE CONVERSION CALL
|
||||
instruction executed.
|
||||
- Counter 265: Increments by one for every DEFLATE CONVERSION CALL
|
||||
instruction executed that ended in Condition Codes
|
||||
0, 1 or 2.
|
||||
|
||||
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
|
||||
---
|
||||
cpumf/Makefile | 3
|
||||
cpumf/data/cpum-cf-extended-z15.ctr | 376 ++++++++++++++++++++++++++++++++++++
|
||||
cpumf/data/cpum-cf-hw-counter.map | 5
|
||||
3 files changed, 380 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/cpumf/Makefile
|
||||
+++ b/cpumf/Makefile
|
||||
@@ -9,7 +9,8 @@ DATA_FILES = cpum-cf-hw-counter.map \
|
||||
cpum-cf-csvn-12345.ctr cpum-cf-csvn-6.ctr \
|
||||
cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
|
||||
cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr \
|
||||
- cpum-cf-extended-z13.ctr cpum-cf-extended-z14.ctr
|
||||
+ cpum-cf-extended-z13.ctr cpum-cf-extended-z14.ctr \
|
||||
+ cpum-cf-extended-z15.ctr
|
||||
LIB_FILES = bin/cpumf_helper
|
||||
USRBIN_SCRIPTS = bin/lscpumf
|
||||
USRSBIN_SCRIPTS = bin/chcpumf
|
||||
--- /dev/null
|
||||
+++ b/cpumf/data/cpum-cf-extended-z15.ctr
|
||||
@@ -0,0 +1,376 @@
|
||||
+# Counter decriptions for the
|
||||
+# IBM z14 extended counter and MT-diagnostic counter set
|
||||
+#
|
||||
+# Notes for transactional-execution mode symbolic names:
|
||||
+# TX .. transactional-execution mode
|
||||
+# NC .. nonconstrained
|
||||
+# C .. constrained
|
||||
+#
|
||||
+# Undefined counters in the extended counter set:
|
||||
+# 142
|
||||
+# 158-161
|
||||
+# 176-223
|
||||
+# 227-231
|
||||
+# 233-242
|
||||
+# 246-255
|
||||
+# Undefined counters in the MT-diagnostic counter set:
|
||||
+# 450-495
|
||||
+#
|
||||
+#
|
||||
+# Extended Counter Set
|
||||
+# ---------------------------------------------------------------------
|
||||
+Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||
+Short-Description:L1D Read-only Exclusive Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache where the line was
|
||||
+originally in a Read-Only state in the cache but has been updated
|
||||
+to be in the Exclusive state that allows stores to the cache line
|
||||
+.
|
||||
+Counter:129 Name:DTLB2_WRITES
|
||||
+Short-Description:DTLB2 Writes
|
||||
+Description:
|
||||
+A translation has been written into The Translation Lookaside
|
||||
+Buffer 2 (TLB2) and the request was made by the data cache
|
||||
+.
|
||||
+Counter:130 Name:DTLB2_MISSES
|
||||
+Short-Description:DTLB2 Misses
|
||||
+Description:
|
||||
+A TLB2 miss is in progress for a request made by the data cache.
|
||||
+Incremented by one for every TLB2 miss in progress for the Level-1
|
||||
+Data cache on this cycle
|
||||
+.
|
||||
+Counter:131 Name:DTLB2_HPAGE_WRITES
|
||||
+Short-Description:DTLB2 One-Megabyte Page Writes
|
||||
+Description:
|
||||
+A translation entry was written into the Combined Region and Segment
|
||||
+Table Entry array in the Level-2 TLB for a one-megabyte page
|
||||
+.
|
||||
+Counter:132 Name:DTLB2_GPAGE_WRITES
|
||||
+Short-Description:DTLB2 Two-Gigabyte Page Writes
|
||||
+Description:
|
||||
+A translation entry for a two-gigabyte page was written into the
|
||||
+Level-2 TLB
|
||||
+.
|
||||
+Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||
+Short-Description:L1D L2D Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the
|
||||
+returned cache line was sourced from the Level-2 Data cache
|
||||
+.
|
||||
+Counter:134 Name:ITLB2_WRITES
|
||||
+Short-Description:ITLB2 Writes
|
||||
+Description:
|
||||
+A translation entry has been written into the Translation Lookaside
|
||||
+Buffer 2 (TLB2) and the request was made by the instruction cache
|
||||
+.
|
||||
+Counter:135 Name:ITLB2_MISSES
|
||||
+Short-Description:ITLB2 Misses
|
||||
+Description:
|
||||
+A TLB2 miss is in progress for a request made by the instruction cache.
|
||||
+Incremented by one for every TLB2 miss in progress for the Level-1
|
||||
+Instruction cache in a cycle
|
||||
+.
|
||||
+Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||
+Short-Description:L1I L2I Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from the Level-2 Instruction cache
|
||||
+.
|
||||
+Counter:137 Name:TLB2_PTE_WRITES
|
||||
+Short-Description:TLB2 PTE Writes
|
||||
+Description:
|
||||
+A translation entry was written into the Page Table Entry array in the
|
||||
+Level-2 TLB
|
||||
+.
|
||||
+Counter:138 Name:TLB2_CRSTE_WRITES
|
||||
+Short-Description:TLB2 CRSTE Writes
|
||||
+Description:
|
||||
+Translation entries were written into the Combined Region and Segment
|
||||
+Table Entry array and the Page Table Entry array in the Level-2 TLB
|
||||
+.
|
||||
+Counter:139 Name:TLB2_ENGINES_BUSY
|
||||
+Short-Description:TLB2 Engines Busy
|
||||
+Description:
|
||||
+The number of Level-2 TLB translation engines busy in a cycle
|
||||
+.
|
||||
+Counter:140 Name:TX_C_TEND
|
||||
+Short-Description:Completed TEND instructions in constrained TX mode
|
||||
+Description:
|
||||
+A TEND instruction has completed in a constrained transactional-execution
|
||||
+mode
|
||||
+.
|
||||
+Counter:141 Name:TX_NC_TEND
|
||||
+Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||
+Description:
|
||||
+A TEND instruction has completed in a non-constrained
|
||||
+transactional-execution mode
|
||||
+.
|
||||
+Counter:143 Name:L1C_TLB2_MISSES
|
||||
+Short-Description:L1C TLB2 Misses
|
||||
+Description:
|
||||
+Increments by one for any cycle where a level-1 cache or level-2 TLB miss
|
||||
+is in progress
|
||||
+.
|
||||
+Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||
+Short-Description:L1D On-Chip L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||
+.
|
||||
+Counter:145 Name:L1D_ONCHIP_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1D On-Chip Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from On-Chip memory
|
||||
+.
|
||||
+Counter:146 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||
+.
|
||||
+Counter:147 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1D On-Cluster L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from On-Cluster Level-3 cache withountervention
|
||||
+.
|
||||
+Counter:148 Name:L1D_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1D On-Cluster Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an On-Cluster memory
|
||||
+.
|
||||
+Counter:149 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1D On-Cluster L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an On-Cluster Level-3 cache with intervention
|
||||
+.
|
||||
+Counter:150 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1D Off-Cluster L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an Off-Cluster Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:151 Name:L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1D Off-Cluster Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from Off-Cluster memory
|
||||
+.
|
||||
+Counter:152 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1D Off-Cluster L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an Off-Cluster Level-3 cache with intervention
|
||||
+.
|
||||
+Counter:153 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1D Off-Drawer L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an Off-Drawer Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:154 Name:L1D_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from Off-Drawer memory
|
||||
+.
|
||||
+Counter:155 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1D Off-Drawer L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from an Off-Drawer Level-3 cache with intervention
|
||||
+.
|
||||
+Counter:156 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||
+Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from On-Drawer Level-4 cache
|
||||
+.
|
||||
+Counter:157 Name:L1D_OFFDRAWER_L4_SOURCED_WRITES
|
||||
+Short-Description:L1D Off-Drawer L4 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from Off-Drawer Level-4 cache
|
||||
+.
|
||||
+Counter:158 Name:L1D_ONCHIP_L3_SOURCED_WRITES_RO
|
||||
+Short-Description:L1D On-Chip L3 Sourced Writes read-only
|
||||
+Description:
|
||||
+A directory write to the Level-1 Data cache directory where the returned
|
||||
+cache line was sourced from On-Chip L3 but a read-only invalidate was
|
||||
+done to remove other copies of the cache line
|
||||
+.
|
||||
+Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||
+Short-Description:L1I On-Chip L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache ine was sourced from an On-Chip Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:163 Name:L1I_ONCHIP_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1I On-Chip Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache ine was sourced from On-Chip memory
|
||||
+.
|
||||
+Counter:164 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache ine was sourced from an On-Chip Level-3 cache with
|
||||
+intervention
|
||||
+.
|
||||
+Counter:165 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1I On-Cluster L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an On-Cluster Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:166 Name:L1I_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1I On-Cluster Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an On-Cluster memory
|
||||
+.
|
||||
+Counter:167 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1I On-Cluster L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from On-Cluster Level-3 cache with
|
||||
+intervention
|
||||
+.
|
||||
+Counter:168 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1I Off-Cluster L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an Off-Cluster Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:169 Name:L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1I Off-Cluster Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from Off-Cluster memory
|
||||
+.
|
||||
+Counter:170 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1I Off-Cluster L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an Off-Cluster Level-3 cache with
|
||||
+intervention
|
||||
+.
|
||||
+Counter:171 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES
|
||||
+Short-Description:L1I Off-Drawer L3 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an Off-Drawer Level-3 cache without
|
||||
+intervention
|
||||
+.
|
||||
+Counter:172 Name:L1I_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||
+Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from Off-Drawer memory
|
||||
+.
|
||||
+Counter:173 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||
+Short-Description:L1I Off-Drawer L3 Sourced Writes with Intervention
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from an Off-Drawer Level-3 cache with
|
||||
+intervention
|
||||
+.
|
||||
+Counter:174 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||
+Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from On-Drawer Level-4 cache
|
||||
+.
|
||||
+Counter:175 Name:L1I_OFFDRAWER_L4_SOURCED_WRITES
|
||||
+Short-Description:L1I Off-Drawer L4 Sourced Writes
|
||||
+Description:
|
||||
+A directory write to the Level-1 Instruction cache directory where the
|
||||
+returned cache line was sourced from Off-Drawer Level-4 cache
|
||||
+.
|
||||
+Counter:224 Name:BCD_DFP_EXECUTION_SLOTS
|
||||
+Short-Description:BCD DFP Execution Slots
|
||||
+Description:
|
||||
+Count of floating point execution slots used for finished Binary Coded
|
||||
+Decimal to Decimal Floating Point conversions. Instructions: CDZT,
|
||||
+CXZT, CZDT, CZXT
|
||||
+.
|
||||
+Counter:225 Name:VX_BCD_EXECUTION_SLOTS
|
||||
+Short-Description:VX BCD Execution Slots
|
||||
+Description:
|
||||
+Count of floating point execution slots used for finished vector arithmetic
|
||||
+Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP,
|
||||
+VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG
|
||||
+.
|
||||
+Counter:226 Name:DECIMAL_INSTRUCTIONS
|
||||
+Short-Description:Decimal Instructions
|
||||
+Description:
|
||||
+Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED,
|
||||
+EDMK, MP, SRP, SP, ZAP
|
||||
+.
|
||||
+Counter:232 Name:LAST_HOST_TRANSLATIONS
|
||||
+Short-Description:Last host translation done
|
||||
+Description:
|
||||
+Last Host Translation done
|
||||
+.
|
||||
+Counter:243 Name:TX_NC_TABORT
|
||||
+Short-Description:Aborted transactions in non-constrained TX mode
|
||||
+Description:
|
||||
+A transaction abort has occurred in a non-constrained
|
||||
+transactional-execution mode
|
||||
+.
|
||||
+Counter:244 Name:TX_C_TABORT_NO_SPECIAL
|
||||
+Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||
+Description:
|
||||
+A transaction abort has occurred in a constrained transactional-execution
|
||||
+mode and the CPU is not using any special logic to allow the transaction
|
||||
+to complete
|
||||
+.
|
||||
+Counter:245 Name:TX_C_TABORT_SPECIAL
|
||||
+Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||
+Description:
|
||||
+A transaction abort has occurred in a constrained transactional-execution
|
||||
+mode and the CPU is using special logic to allow the transaction to
|
||||
+complete
|
||||
+.
|
||||
+Counter:247 Name:DFLT_ACCESS
|
||||
+Short-Description:Cycles CPU spent obtaining access to Deflate unit
|
||||
+Description:
|
||||
+Cycles CPU spent obtaining access to Deflate unit
|
||||
+.
|
||||
+Counter:252 Name:DFLT_CYCLES
|
||||
+Short-Description:Cycles CPU is using Deflate unit
|
||||
+Description:
|
||||
+Cycles CPU is using Deflate unit
|
||||
+.
|
||||
+Counter:264 Name:DFLT_CC
|
||||
+Short-Description:Increments by one for every DEFLATE CONVERSION CALL instruction executed
|
||||
+Description:
|
||||
+Increments by one for every DEFLATE CONVERSION CALL instruction executed
|
||||
+.
|
||||
+Counter:265 Name:DFLT_CCERROR
|
||||
+Short-Description:Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2
|
||||
+Description:
|
||||
+Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2
|
||||
+.
|
||||
+#
|
||||
+# MT-diagnostic counter set
|
||||
+# ---------------------------------------------------------------------
|
||||
+Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||
+Short-Description:Cycle count with one thread active
|
||||
+Description:
|
||||
+Cycle count with one thread active
|
||||
+.
|
||||
+Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||
+Short-Description:Cycle count with two threads active
|
||||
+Description:
|
||||
+Cycle count with two threads active
|
||||
+.
|
||||
--- a/cpumf/data/cpum-cf-hw-counter.map
|
||||
+++ b/cpumf/data/cpum-cf-hw-counter.map
|
||||
@@ -28,7 +28,6 @@
|
||||
2965 => 'cpum-cf-extended-z13.ctr',
|
||||
3906 => 'cpum-cf-extended-z14.ctr',
|
||||
3907 => 'cpum-cf-extended-z14.ctr',
|
||||
- # Identical with z14
|
||||
- 8561 => 'cpum-cf-extended-z14.ctr',
|
||||
- 8562 => 'cpum-cf-extended-z14.ctr',
|
||||
+ 8561 => 'cpum-cf-extended-z15.ctr',
|
||||
+ 8562 => 'cpum-cf-extended-z15.ctr',
|
||||
};
|
@ -1,63 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184396] zipl: Add missing options to help output
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: fix secure boot config handling
|
||||
Symptom: The config file parsing for secure boot worked not as
|
||||
it was expected to be. For example a config section
|
||||
setting was not evaluated properly.
|
||||
It is not possible to specify command line option -S
|
||||
without other options.
|
||||
Additionally the man page showed an invalid example.
|
||||
Problem: The config file parsing was not implemented properly.
|
||||
Solution: The hierarchy of the secure boot settings in the config
|
||||
file is:
|
||||
defaultboot > menu > section
|
||||
Allow that --secure or -S is specified on command line
|
||||
without the need to allow all options on the command
|
||||
line. Also ensure that the command line option
|
||||
overrules the config option and correctly ensure that
|
||||
secure boot is only set for SCSI devices.
|
||||
Fix man page example.
|
||||
Reproduction: Run zipl with a secure= setting in a configuration
|
||||
section or specify -S on command line.
|
||||
Upstream-ID: dcce14923c3e9615df53773d1d8a3a22cbb23b96
|
||||
Problem-ID: 184396
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Add missing options to help output
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
zipl/src/zipl.c | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/src/zipl.c
|
||||
+++ b/zipl/src/zipl.c
|
||||
@@ -68,6 +68,8 @@ static const char* usage_text[] = {
|
||||
"-P, --parameters PARMLINE Use specified kernel PARMLINE",
|
||||
"-T, --tape TAPEDEV Install bootloader on tape device TAPEDEV",
|
||||
"-s, --segment SEGMENT,ADDR Install a segment from file SEGMENT",
|
||||
+"-k, --kdump=auto Install a kdump kernel that can be used as a",
|
||||
+" stand-alone dump tool",
|
||||
"-d, --dumpto DUMPDEV[,SIZE] Install a system dump record on tape device",
|
||||
" or disk partition DUMPDEV",
|
||||
"-M, --mvdump DEVLIST[,SIZE] Install a multi-volume dump record on each",
|
||||
@@ -78,7 +80,12 @@ static const char* usage_text[] = {
|
||||
"-n, --noninteractive Answer all confirmation questions with 'yes'",
|
||||
"-V, --verbose Provide more verbose output",
|
||||
"-a, --add-files Add all referenced files to bootmap file",
|
||||
-" --dry-run Simulate run but don't modify IPL records"
|
||||
+" --dry-run Simulate run but don't modify IPL records",
|
||||
+"-S, --secure SWITCH Control the zIPL secure boot support.",
|
||||
+" auto (default):",
|
||||
+" Write signatures if available and supported",
|
||||
+" 1: Write signatures regardless of support",
|
||||
+" 0: Do not write signatures"
|
||||
};
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: fix -Wdiscarded-qualifiers
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: bbc46edaf53c2c148b5c94a2414f6847f67f856a
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: fix -Wdiscarded-qualifiers
|
||||
|
||||
Reported by GCC 9.2.1 when building with '-Wdiscarded-qualifiers'.
|
||||
|
||||
job.c: In function 'get_job_from_config_file':
|
||||
job.c:1810:14: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/src/job.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/src/job.c
|
||||
+++ b/zipl/src/job.c
|
||||
@@ -1796,7 +1796,7 @@ get_job_from_config_file(struct command_
|
||||
{
|
||||
struct scan_token* scan;
|
||||
struct scan_token* new_scan;
|
||||
- char* filename;
|
||||
+ const char *filename;
|
||||
char *blsdir;
|
||||
char* source;
|
||||
int rc, scan_size;
|
@ -1,319 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184060] zipl/libc: Introduce vsnprintf
|
||||
From: Philipp Rudo <prudo@linux.ibm.com>
|
||||
|
||||
Description: zipl/libc: Fix potential buffer overflow in printf
|
||||
Symptom: Crash of the zipl boot loader during boot.
|
||||
Problem: The zipl boot loaders have their own minimalistic libc
|
||||
implementation. In it printf and sprintf use vsprintf for string
|
||||
formatting. Per definition vsprintf assumes that the buffer it
|
||||
writes to is large enough to contain the formatted string and
|
||||
performs no size checks. This is problematic for the boot
|
||||
loaders because the buffer they use are often allocated on the
|
||||
stack. Thus even small changes to the string format can
|
||||
potentially cause buffer overflows on the stack.
|
||||
Solution: Implement vsnprintf and make use of it.
|
||||
Reproduction: Use printf to print a string with >81 characters (exact number
|
||||
depends on the stack layout/compiler used).
|
||||
Upstream-ID: 6fe9e6c55c69c14971dca55551009f5060418aae
|
||||
Problem-ID: 184060
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: Introduce vsnprintf
|
||||
|
||||
The zipl boot loaders have their own minimalistic libc implementation.
|
||||
In it printf and sprintf use vsprintf for string formatting. Per
|
||||
definition vsprintf assumes that the buffer it writes to is large enough
|
||||
to contain the formatted string and performs no size checks. This is
|
||||
problematic for the boot loaders because the buffer they use are often
|
||||
allocated on the stack. Thus even small changes to the string format can
|
||||
potentially cause buffer overflows on the stack with the well known
|
||||
consequences. Protect against such errors by implementing vsnprintf.
|
||||
Later patches will make use of it.
|
||||
|
||||
This implementation of vsnprintf only supports a small subset of format
|
||||
options defined in the C standard. In particular it allows the
|
||||
specifiers:
|
||||
* %s (strings)
|
||||
* %o (unsigned int octal)
|
||||
* %u (unsigned int decimal)
|
||||
* %x (unsigned int hexadecimal)
|
||||
|
||||
Integer specifiers (o, u, and x) always use the long form, i.e. assume the
|
||||
argument to be of type 'unsigned long int'. The length modified 'l' can
|
||||
be given but is ignored.
|
||||
|
||||
Furthermore, it is possible to provide the optional field width (aligned
|
||||
to the right only) and precision as decimal integer (i.e. not via '*')
|
||||
as well as the flag for zero padding integers (i.e. '0').
|
||||
|
||||
The implementation was heavily inspired by the implementation in
|
||||
lib/vsprintf.c from the Linux kernel tree.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 248 insertions(+)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -218,6 +218,254 @@ unsigned long ebcstrtoul(char *nptr, cha
|
||||
return val;
|
||||
}
|
||||
|
||||
+static int skip_atoi(const char **c)
|
||||
+{
|
||||
+ int i = 0;
|
||||
+
|
||||
+ do {
|
||||
+ i = i*10 + *((*c)++) - '0';
|
||||
+ } while (isdigit(**c));
|
||||
+
|
||||
+ return i;
|
||||
+}
|
||||
+
|
||||
+enum format_type {
|
||||
+ FORMAT_TYPE_NONE,
|
||||
+ FORMAT_TYPE_STR,
|
||||
+ FORMAT_TYPE_ULONG,
|
||||
+};
|
||||
+
|
||||
+struct printf_spec {
|
||||
+ unsigned int type:8; /* format_type enum */
|
||||
+ signed int field_width:24; /* width of output field */
|
||||
+ unsigned int zeropad:1; /* pad numbers with zero */
|
||||
+ unsigned int base:8; /* number base, 8, 10 or 16 only */
|
||||
+ signed int precision:16; /* # of digits/chars */
|
||||
+};
|
||||
+
|
||||
+#define FIELD_WIDTH_MAX ((1 << 23) - 1)
|
||||
+
|
||||
+static int format_decode(const char *fmt, struct printf_spec *spec)
|
||||
+{
|
||||
+ const char *start = fmt;
|
||||
+
|
||||
+ spec->type = FORMAT_TYPE_NONE;
|
||||
+ while (*fmt) {
|
||||
+ if (*fmt == '%')
|
||||
+ break;
|
||||
+ fmt++;
|
||||
+ }
|
||||
+
|
||||
+ /* return current non-format string */
|
||||
+ if (fmt != start || !*fmt)
|
||||
+ return fmt - start;
|
||||
+
|
||||
+ /* first char is '%', skip it */
|
||||
+ fmt++;
|
||||
+ if (*fmt == '0') {
|
||||
+ spec->zeropad = 1;
|
||||
+ fmt++;
|
||||
+ }
|
||||
+
|
||||
+ spec->field_width = -1;
|
||||
+ if (isdigit(*fmt))
|
||||
+ spec->field_width = skip_atoi(&fmt);
|
||||
+
|
||||
+ spec->precision = -1;
|
||||
+ if (*fmt == '.') {
|
||||
+ fmt++;
|
||||
+ if (isdigit(*fmt))
|
||||
+ spec->precision = skip_atoi(&fmt);
|
||||
+ }
|
||||
+
|
||||
+ /* always use long form, i.e. ignore long qualifier */
|
||||
+ if (*fmt == 'l')
|
||||
+ fmt++;
|
||||
+
|
||||
+ switch (*fmt) {
|
||||
+ case 's':
|
||||
+ spec->type = FORMAT_TYPE_STR;
|
||||
+ break;
|
||||
+
|
||||
+ case 'o':
|
||||
+ spec->base = 8;
|
||||
+ spec->type = FORMAT_TYPE_ULONG;
|
||||
+ break;
|
||||
+
|
||||
+ case 'u':
|
||||
+ spec->base = 10;
|
||||
+ spec->type = FORMAT_TYPE_ULONG;
|
||||
+ break;
|
||||
+
|
||||
+ case 'x':
|
||||
+ spec->base = 16;
|
||||
+ spec->type = FORMAT_TYPE_ULONG;
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ libc_stop(EINTERNAL);
|
||||
+ }
|
||||
+
|
||||
+ return ++fmt - start;
|
||||
+}
|
||||
+
|
||||
+static char *string(char *buf, char *end, const char *s,
|
||||
+ struct printf_spec *spec)
|
||||
+{
|
||||
+ int limit = spec->precision;
|
||||
+ int len = 0;
|
||||
+ int spaces;
|
||||
+
|
||||
+ /* Copy string to buffer */
|
||||
+ while (limit--) {
|
||||
+ char c = *s++;
|
||||
+ if (!c)
|
||||
+ break;
|
||||
+ if (buf < end)
|
||||
+ *buf = c;
|
||||
+ buf++;
|
||||
+ len++;
|
||||
+ }
|
||||
+
|
||||
+ /* right align if necessary */
|
||||
+ if (len < spec->field_width && buf < end) {
|
||||
+ spaces = spec->field_width - len;
|
||||
+ if (spaces >= end - buf)
|
||||
+ spaces = end - buf;
|
||||
+ memmove(buf + spaces, buf, len);
|
||||
+ memset(buf, ' ', spaces);
|
||||
+ buf += spaces;
|
||||
+ }
|
||||
+
|
||||
+ return buf;
|
||||
+}
|
||||
+
|
||||
+static char *number(char *buf, char *end, unsigned long val,
|
||||
+ struct printf_spec *spec)
|
||||
+{
|
||||
+ /* temporary buffer to prepare the string.
|
||||
+ * Worst case: base = 8 -> 3 bits per char -> 2.67 chars per byte */
|
||||
+ char tmp[3 * sizeof(val)];
|
||||
+ static const char vec[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
+ int field_width = spec->field_width;
|
||||
+ int precision = spec->precision;
|
||||
+ int len;
|
||||
+
|
||||
+ /* prepare string in reverse order */
|
||||
+ len = 0;
|
||||
+ while (val) {
|
||||
+ tmp[len++] = vec[val % spec->base];
|
||||
+ val /= spec->base;
|
||||
+ }
|
||||
+
|
||||
+ if (len > precision)
|
||||
+ precision = len;
|
||||
+
|
||||
+ field_width -= precision;
|
||||
+ while (field_width-- > 0) {
|
||||
+ char c = spec->zeropad ? '0' : ' ';
|
||||
+ if (buf < end)
|
||||
+ *buf = c;
|
||||
+ buf++;
|
||||
+ }
|
||||
+
|
||||
+ /* needed if no field width but a precision is given */
|
||||
+ while (len < precision--) {
|
||||
+ if (buf < end)
|
||||
+ *buf = '0';
|
||||
+ buf++;
|
||||
+ }
|
||||
+
|
||||
+ while (len-- > 0) {
|
||||
+ if (buf < end)
|
||||
+ *buf = tmp[len];
|
||||
+ buf++;
|
||||
+ }
|
||||
+
|
||||
+ return buf;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * vsnprintf - Format string and place in a buffer
|
||||
+ *
|
||||
+ * This funcion only supports a subset of format options defined in the
|
||||
+ * C standard, i.e.
|
||||
+ * specifiers:
|
||||
+ * * %s (strings)
|
||||
+ * * %o (unsigned int octal)
|
||||
+ * * %u (unsigned int decimal)
|
||||
+ * * %x (unsigned int hexadecimal)
|
||||
+ *
|
||||
+ * length modifier:
|
||||
+ * * 'l' (ignored, see below)
|
||||
+ *
|
||||
+ * flag:
|
||||
+ * * '0' (zero padding for integers)
|
||||
+ *
|
||||
+ * precision and field width as integers, i.e. _not_ by asterix '*'.
|
||||
+ *
|
||||
+ * The integer specifiers (o, u and, x) always use the long form, i.e.
|
||||
+ * assume the argument to be of type 'unsigned long int'.
|
||||
+ *
|
||||
+ * Returns the number of characters the function would have generated for
|
||||
+ * the given input (excluding the trailing '\0'. If the return value is
|
||||
+ * greater than or equal @size the resulting string is trunctuated.
|
||||
+ */
|
||||
+static int vsnprintf(char *buf, unsigned long size, const char *fmt,
|
||||
+ va_list args)
|
||||
+{
|
||||
+ struct printf_spec spec = {0};
|
||||
+ char *str, *end;
|
||||
+
|
||||
+ str = buf;
|
||||
+ end = buf + size;
|
||||
+
|
||||
+ /* use negative (large positive) buffer sizes as indication for
|
||||
+ * unknown/unlimited buffer sizes. */
|
||||
+ if (end < buf) {
|
||||
+ end = ((void *)-1);
|
||||
+ size = end - buf;
|
||||
+ }
|
||||
+
|
||||
+ while (*fmt) {
|
||||
+ const char *old_fmt = fmt;
|
||||
+ int read = format_decode(fmt, &spec);
|
||||
+ int copy;
|
||||
+
|
||||
+ fmt += read;
|
||||
+
|
||||
+ switch (spec.type) {
|
||||
+ case FORMAT_TYPE_NONE:
|
||||
+ copy = read;
|
||||
+ if (str < end) {
|
||||
+ if (copy > end - str)
|
||||
+ copy = end - str;
|
||||
+ memcpy(str, old_fmt, copy);
|
||||
+ }
|
||||
+ str += read;
|
||||
+ break;
|
||||
+
|
||||
+ case FORMAT_TYPE_STR:
|
||||
+ str = string(str, end, va_arg(args, char *), &spec);
|
||||
+ break;
|
||||
+
|
||||
+ case FORMAT_TYPE_ULONG:
|
||||
+ str = number(str, end, va_arg(args, unsigned long),
|
||||
+ &spec);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (size) {
|
||||
+ if (str < end)
|
||||
+ *str = '\0';
|
||||
+ else
|
||||
+ end[-1] = '\0';
|
||||
+ }
|
||||
+ return str - buf;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Convert string to number with given base
|
||||
*/
|
@ -1,72 +0,0 @@
|
||||
Subject: [PATCH] [BZ 186940] zipl/libc: libc_stop move 'noreturn' to declaration
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: Fix KVM IPL without bootindex
|
||||
Symptom: Failed IPL on KVM when no bootindex is specified.
|
||||
Problem: Without bootindex specified there is no IPL parmblock
|
||||
on KVM which can be read by the stage3 loader.
|
||||
Solution: In case diag308 gives a response code 0x102 the stage3
|
||||
loader can safely assume that no secure IPL is required
|
||||
since no IPL report block exists.
|
||||
Reproduction: IPL on KVM without 'bootindex=' attached.
|
||||
Upstream-ID: c9066bf5497300db5e0ba11bf111683ea225d8c8
|
||||
Problem-ID: 186940
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: libc_stop move 'noreturn' to declaration
|
||||
|
||||
Commit 86856f98dbe3 ("zipl: Make use of __noreturn macro") moved the
|
||||
'noreturn' attribute from declaration to definition. With this the
|
||||
compiler can no longer optimize when the function is called in a
|
||||
separate source file. Move the attribute back to the declaration
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 3 +--
|
||||
zipl/boot/libc.h | 4 +++-
|
||||
2 files changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
-#include "lib/zt_common.h"
|
||||
#include "boot/s390.h"
|
||||
|
||||
#include "error.h"
|
||||
@@ -501,7 +500,7 @@ void initialize(void)
|
||||
/*
|
||||
* Load disabled wait PSW with reason code in address field
|
||||
*/
|
||||
-void __noreturn libc_stop(unsigned long reason)
|
||||
+void libc_stop(unsigned long reason)
|
||||
{
|
||||
struct psw_t psw;
|
||||
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
#define NULL ((void *) 0)
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
@@ -56,7 +58,7 @@ char *strcpy(char *, const char *);
|
||||
unsigned long get_zeroed_page(void);
|
||||
void free_page(unsigned long);
|
||||
void initialize(void);
|
||||
-void libc_stop(unsigned long);
|
||||
+void libc_stop(unsigned long) __noreturn;
|
||||
void start(void);
|
||||
void pgm_check_handler(void);
|
||||
void pgm_check_handler_fn(void);
|
@ -1,795 +0,0 @@
|
||||
Subject: zkey: Separate and rework CCA host library loading
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 95c7258ea783c5bd6aa12fc0e3d5fbe65647af03
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Separate and rework CCA host library loading
|
||||
|
||||
As preparation for future changes, rework the loading of the
|
||||
CCA host library so that the exported symbols are not passed
|
||||
individually to the functions that use it. Pass a structure
|
||||
that contains all entry points of all loaded CCA functions
|
||||
instead. This will make it easier to add further CCA functions
|
||||
at a later time.
|
||||
|
||||
Also add a version query for the CCA host library since some
|
||||
future functions might be dependent on the library version.
|
||||
|
||||
While at it, separate the CCA related functions and definitions,
|
||||
and move them into a separate source file (cca.h/cca.h).
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/Makefile | 11 +-
|
||||
zkey/cca.c | 215 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/cca.h | 54 ++++++++++++
|
||||
zkey/keystore.c | 26 ++---
|
||||
zkey/keystore.h | 3
|
||||
zkey/pkey.c | 142 --------------------------------
|
||||
zkey/pkey.h | 17 ---
|
||||
zkey/zkey-cryptsetup.c | 15 +--
|
||||
zkey/zkey.c | 19 +---
|
||||
9 files changed, 306 insertions(+), 196 deletions(-)
|
||||
|
||||
--- a/zkey/Makefile
|
||||
+++ b/zkey/Makefile
|
||||
@@ -64,18 +64,19 @@ zkey-cryptsetup-skip-jsonc:
|
||||
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
-zkey.o: zkey.c pkey.h misc.h
|
||||
+zkey.o: zkey.c pkey.h cca.h misc.h
|
||||
pkey.o: pkey.c pkey.h
|
||||
+cca.o: cca.c cca.h pkey.h
|
||||
properties.o: check-dep-zkey properties.c properties.h
|
||||
-keystore.o: keystore.c keystore.h properties.h
|
||||
-zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h
|
||||
+keystore.o: keystore.c keystore.h properties.h pkey.h cca.h
|
||||
+zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h cca.h misc.h
|
||||
|
||||
zkey: LDLIBS = -ldl -lcrypto
|
||||
-zkey: zkey.o pkey.o properties.o keystore.o $(libs)
|
||||
+zkey: zkey.o pkey.o cca.o properties.o keystore.o $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
|
||||
-zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs)
|
||||
+zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
install-common:
|
||||
--- /dev/null
|
||||
+++ b/zkey/cca.c
|
||||
@@ -0,0 +1,215 @@
|
||||
+/*
|
||||
+ * zkey - Generate, re-encipher, and validate secure keys
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2019
|
||||
+ *
|
||||
+ * 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 <dlfcn.h>
|
||||
+#include <err.h>
|
||||
+#include <errno.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+#include <stdint.h>
|
||||
+#include <sys/types.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include "lib/util_panic.h"
|
||||
+
|
||||
+#include "cca.h"
|
||||
+#include "pkey.h"
|
||||
+
|
||||
+#define pr_verbose(verbose, fmt...) do { \
|
||||
+ if (verbose) \
|
||||
+ warnx(fmt); \
|
||||
+ } while (0)
|
||||
+
|
||||
+/*
|
||||
+ * Definitions for the CCA library
|
||||
+ */
|
||||
+#define CCA_LIBRARY_NAME "libcsulcca.so"
|
||||
+#define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards"
|
||||
+
|
||||
+/**
|
||||
+ * Prints CCA return and reason code information for certain known CCA
|
||||
+ * error situations.
|
||||
+ *
|
||||
+ * @param return_code the CCA return code
|
||||
+ * @param reason_code the CCA reason code
|
||||
+ */
|
||||
+static void print_CCA_error(int return_code, int reason_code)
|
||||
+{
|
||||
+ switch (return_code) {
|
||||
+ case 8:
|
||||
+ switch (reason_code) {
|
||||
+ case 48:
|
||||
+ warnx("The secure key has a CCA master key "
|
||||
+ "verification pattern that is not valid");
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ case 12:
|
||||
+ switch (reason_code) {
|
||||
+ case 764:
|
||||
+ warnx("The CCA master key is not loaded and "
|
||||
+ "therefore a secure key cannot be enciphered");
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Returns the version, release and modification number of the used CCA library.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int get_cca_version(struct cca_lib *cca, bool verbose)
|
||||
+{
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ unsigned char version_data[20];
|
||||
+ long return_code, reason_code;
|
||||
+ long version_data_length;
|
||||
+ long exit_data_len = 0;
|
||||
+ char date[20];
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ memset(version_data, 0, sizeof(version_data));
|
||||
+ version_data_length = sizeof(version_data);
|
||||
+ cca->dll_CSUACFV(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &version_data_length, version_data);
|
||||
+ pr_verbose(verbose, "CSUACFV (Cryptographic Facility Version) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ version_data[sizeof(version_data) - 1] = '\0';
|
||||
+ pr_verbose(verbose, "CCA Version string: %s", version_data);
|
||||
+
|
||||
+ if (sscanf((char *)version_data, "%u.%u.%uz%s", &cca->version.ver,
|
||||
+ &cca->version.rel, &cca->version.mod, date) != 4) {
|
||||
+ warnx("CCA library version is invalid: %s", version_data);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Loads the CCA library and provides the entry point of the CSNBKTC function.
|
||||
+ *
|
||||
+ * @param[out] cca on return this contains the address of the CCA
|
||||
+ * library and certain CCA symbols. dlclose() should
|
||||
+ * be used to free the library when no longer needed.
|
||||
+ * @param verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, -ELIBACC in case of library load errors
|
||||
+ */
|
||||
+int load_cca_library(struct cca_lib *cca, bool verbose)
|
||||
+{
|
||||
+ util_assert(cca != NULL, "Internal error: caa is NULL");
|
||||
+
|
||||
+ /* Load the CCA library */
|
||||
+ cca->lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
|
||||
+ if (cca->lib_csulcca == NULL) {
|
||||
+ pr_verbose(verbose, "%s", dlerror());
|
||||
+ warnx("The command requires the IBM CCA Host Libraries and "
|
||||
+ "Tools.\nFor the supported environments and downloads, "
|
||||
+ "see:\n%s", CCA_WEB_PAGE);
|
||||
+ return -ELIBACC;
|
||||
+ }
|
||||
+
|
||||
+ /* Get the Cryptographic Facility Version function */
|
||||
+ cca->dll_CSUACFV = (t_CSUACFV)dlsym(cca->lib_csulcca, "CSUACFV");
|
||||
+
|
||||
+ /* Get the Key Token Change function */
|
||||
+ cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC");
|
||||
+
|
||||
+ if (cca->dll_CSUACFV == NULL ||
|
||||
+ cca->dll_CSNBKTC == NULL) {
|
||||
+ pr_verbose(verbose, "%s", dlerror());
|
||||
+ warnx("The command requires the IBM CCA Host Libraries and "
|
||||
+ "Tools.\nFor the supported environments and downloads, "
|
||||
+ "see:\n%s", CCA_WEB_PAGE);
|
||||
+ dlclose(cca->lib_csulcca);
|
||||
+ cca->lib_csulcca = NULL;
|
||||
+ return -ELIBACC;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "CCA library '%s' has been loaded successfully",
|
||||
+ CCA_LIBRARY_NAME);
|
||||
+
|
||||
+ return get_cca_version(cca, verbose);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Re-enciphers a secure key.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA libraray structure
|
||||
+ * @param[in] secure_key a buffer containing the secure key
|
||||
+ * @param[in] secure_key_size the size of the secure key
|
||||
+ * @param[in] method the re-enciphering method. METHOD_OLD_TO_CURRENT
|
||||
+ * or METHOD_CURRENT_TO_NEW.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, -EIO in case of an error
|
||||
+ */
|
||||
+int key_token_change(struct cca_lib *cca,
|
||||
+ u8 *secure_key, unsigned int secure_key_size,
|
||||
+ char *method, bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count;
|
||||
+ unsigned char rule_array[2 * 8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+ util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
+ util_assert(secure_key_size > 0,
|
||||
+ "Internal error: secure_key_size is 0");
|
||||
+ util_assert(method != NULL, "Internal error: method is NULL");
|
||||
+
|
||||
+ memcpy(rule_array, method, 8);
|
||||
+ memcpy(rule_array + 8, "AES ", 8);
|
||||
+ rule_array_count = 2;
|
||||
+
|
||||
+ cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ secure_key);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' returned: "
|
||||
+ "return_code: %ld, reason_code: %ld", method, return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ if (secure_key_size == 2 * SECURE_KEY_SIZE) {
|
||||
+ cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ secure_key + SECURE_KEY_SIZE);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
|
||||
+ "returned: return_code: %ld, reason_code: %ld",
|
||||
+ method, return_code, reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/zkey/cca.h
|
||||
@@ -0,0 +1,54 @@
|
||||
+/*
|
||||
+ * zkey - Generate, re-encipher, and validate secure keys
|
||||
+ *
|
||||
+ * This header file defines the interface to the CCA host library.
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2019
|
||||
+ *
|
||||
+ * 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 CCA_H
|
||||
+#define CCA_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+#define METHOD_OLD_TO_CURRENT "RTCMK "
|
||||
+#define METHOD_CURRENT_TO_NEW "RTNMK "
|
||||
+
|
||||
+typedef void (*t_CSNBKTC)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ unsigned char *key_identifier);
|
||||
+
|
||||
+typedef void (*t_CSUACFV)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *version_data_length,
|
||||
+ unsigned char *version_data);
|
||||
+
|
||||
+struct cca_version {
|
||||
+ unsigned int ver;
|
||||
+ unsigned int rel;
|
||||
+ unsigned int mod;
|
||||
+};
|
||||
+
|
||||
+struct cca_lib {
|
||||
+ void *lib_csulcca;
|
||||
+ t_CSNBKTC dll_CSNBKTC;
|
||||
+ t_CSUACFV dll_CSUACFV;
|
||||
+ struct cca_version version;
|
||||
+};
|
||||
+
|
||||
+int load_cca_library(struct cca_lib *cca, bool verbose);
|
||||
+
|
||||
+int key_token_change(struct cca_lib *cca,
|
||||
+ u8 *secure_key, unsigned int secure_key_size,
|
||||
+ char *method, bool verbose);
|
||||
+
|
||||
+#endif
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "keystore.h"
|
||||
#include "pkey.h"
|
||||
+#include "cca.h"
|
||||
#include "properties.h"
|
||||
|
||||
struct key_filenames {
|
||||
@@ -2522,7 +2523,7 @@ struct reencipher_params {
|
||||
struct reencipher_info {
|
||||
struct reencipher_params params;
|
||||
int pkey_fd;
|
||||
- t_CSNBKTC dll_CSNBKTC;
|
||||
+ struct cca_lib *cca;
|
||||
unsigned long num_reenciphered;
|
||||
unsigned long num_failed;
|
||||
unsigned long num_skipped;
|
||||
@@ -2533,7 +2534,7 @@ struct reencipher_info {
|
||||
*
|
||||
* @param[in] keystore the keystore
|
||||
* @param[in] name the name of the key
|
||||
- * @param[in] dll_CSNBKTC the CCA key token change function
|
||||
+ * @param[in] cca the CCA library struct
|
||||
* @param[in] params reenciphering parameters
|
||||
* @param[in] secure_key a buffer containing the secure key
|
||||
* @param[in] secure_key_size the size of the secure key
|
||||
@@ -2544,7 +2545,7 @@ struct reencipher_info {
|
||||
*/
|
||||
static int _keystore_perform_reencipher(struct keystore *keystore,
|
||||
const char *name,
|
||||
- t_CSNBKTC dll_CSNBKTC,
|
||||
+ struct cca_lib *cca,
|
||||
struct reencipher_params *params,
|
||||
u8 *secure_key, size_t secure_key_size,
|
||||
bool is_old_mk)
|
||||
@@ -2584,8 +2585,7 @@ static int _keystore_perform_reencipher(
|
||||
"Secure key '%s' will be re-enciphered from OLD "
|
||||
"to the CURRENT CCA master key", name);
|
||||
|
||||
- rc = key_token_change(dll_CSNBKTC,
|
||||
- secure_key, secure_key_size,
|
||||
+ rc = key_token_change(cca, secure_key, secure_key_size,
|
||||
METHOD_OLD_TO_CURRENT,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
@@ -2602,8 +2602,7 @@ static int _keystore_perform_reencipher(
|
||||
if (params->inplace == -1)
|
||||
params->inplace = 0;
|
||||
|
||||
- rc = key_token_change(dll_CSNBKTC,
|
||||
- secure_key, secure_key_size,
|
||||
+ rc = key_token_change(cca, secure_key, secure_key_size,
|
||||
METHOD_CURRENT_TO_NEW,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
@@ -2696,10 +2695,9 @@ static int _keystore_process_reencipher(
|
||||
if (!params.complete) {
|
||||
printf("Re-enciphering key '%s'\n", name);
|
||||
|
||||
- rc = _keystore_perform_reencipher(keystore, name,
|
||||
- info->dll_CSNBKTC, ¶ms,
|
||||
- secure_key, secure_key_size,
|
||||
- is_old_mk);
|
||||
+ rc = _keystore_perform_reencipher(keystore, name, info->cca,
|
||||
+ ¶ms, secure_key,
|
||||
+ secure_key_size, is_old_mk);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
if (rc > 0) {
|
||||
@@ -2802,6 +2800,8 @@ out:
|
||||
* @param[in] inplace if true, the key will be re-enciphere in-place
|
||||
* @param[in] staged if true, the key will be re-enciphere not in-place
|
||||
* @param[in] complete if true, a pending re-encipherment is completed
|
||||
+ * @param[in] pkey_fd the file descriptor of /dev/pkey
|
||||
+ * @param[in] cca the CCA library struct
|
||||
* Note: if both from Old and toNew are FALSE, then the reencipherement mode is
|
||||
* detected automatically. If both are TRUE then the key is reenciphered
|
||||
* from the OLD to the NEW CCA master key.
|
||||
@@ -2814,7 +2814,7 @@ int keystore_reencipher_key(struct keyst
|
||||
const char *apqn_filter,
|
||||
bool from_old, bool to_new, bool inplace,
|
||||
bool staged, bool complete, int pkey_fd,
|
||||
- t_CSNBKTC dll_CSNBKTC)
|
||||
+ struct cca_lib *cca)
|
||||
{
|
||||
struct reencipher_info info;
|
||||
int rc;
|
||||
@@ -2830,7 +2830,7 @@ int keystore_reencipher_key(struct keyst
|
||||
info.params.inplace = 0;
|
||||
info.params.complete = complete;
|
||||
info.pkey_fd = pkey_fd;
|
||||
- info.dll_CSNBKTC = dll_CSNBKTC;
|
||||
+ info.cca = cca;
|
||||
info.num_failed = 0;
|
||||
info.num_reenciphered = 0;
|
||||
info.num_skipped = 0;
|
||||
--- a/zkey/keystore.h
|
||||
+++ b/zkey/keystore.h
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
+#include "cca.h"
|
||||
#include "pkey.h"
|
||||
|
||||
struct keystore {
|
||||
@@ -54,7 +55,7 @@ int keystore_reencipher_key(struct keyst
|
||||
const char *apqn_filter,
|
||||
bool from_old, bool to_new, bool inplace,
|
||||
bool staged, bool complete, int pkey_fd,
|
||||
- t_CSNBKTC dll_CSNBKTC);
|
||||
+ struct cca_lib *cca);
|
||||
|
||||
int keystore_copy_key(struct keystore *keystore, const char *name,
|
||||
const char *newname, const char *volumes);
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -44,57 +44,7 @@
|
||||
|
||||
#define MAX_CIPHER_LEN 32
|
||||
|
||||
-/*
|
||||
- * Definitions for the CCA library
|
||||
- */
|
||||
-#define CCA_LIBRARY_NAME "libcsulcca.so"
|
||||
-#define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards"
|
||||
-
|
||||
-#define DEFAULT_KEYBITS 256
|
||||
-
|
||||
-/**
|
||||
- * Loads the CCA library and provides the entry point of the CSNBKTC function.
|
||||
- *
|
||||
- * @param[out] lib_csulcca on return this contains the address of the CCA
|
||||
- * library. dlclose() should be used to free this
|
||||
- * when no longer needed.
|
||||
- * @param[out] dll_CSNBKTC on return this contains the address of the
|
||||
- * CSNBKTC function.
|
||||
- * @param verbose if true, verbose messages are printed
|
||||
- *
|
||||
- * @returns 0 on success, -ELIBACC in case of library load errors
|
||||
- */
|
||||
-int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose)
|
||||
-{
|
||||
- util_assert(lib_csulcca != NULL, "Internal error: lib_csulcca is NULL");
|
||||
- util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
|
||||
-
|
||||
- /* Load the CCA library */
|
||||
- *lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
|
||||
- if (*lib_csulcca == NULL) {
|
||||
- pr_verbose(verbose, "%s", dlerror());
|
||||
- warnx("The command requires the IBM CCA Host Libraries and "
|
||||
- "Tools.\nFor the supported environments and downloads, "
|
||||
- "see:\n%s", CCA_WEB_PAGE);
|
||||
- return -ELIBACC;
|
||||
- }
|
||||
-
|
||||
- /* Get the Key Token Change function */
|
||||
- *dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC");
|
||||
- if (*dll_CSNBKTC == NULL) {
|
||||
- pr_verbose(verbose, "%s", dlerror());
|
||||
- warnx("The command requires the IBM CCA Host Libraries and "
|
||||
- "Tools.\nFor the supported environments and downloads, "
|
||||
- "see:\n%s", CCA_WEB_PAGE);
|
||||
- dlclose(*lib_csulcca);
|
||||
- *lib_csulcca = NULL;
|
||||
- return -ELIBACC;
|
||||
- }
|
||||
-
|
||||
- pr_verbose(verbose, "CCA library '%s' has been loaded successfully",
|
||||
- CCA_LIBRARY_NAME);
|
||||
- return 0;
|
||||
-}
|
||||
+#define DEFAULT_KEYBITS 256
|
||||
|
||||
/**
|
||||
* Opens the pkey device and returns its file descriptor.
|
||||
@@ -523,96 +473,6 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
- * Prints CCA return and reason code information for certain known CCA
|
||||
- * error situations.
|
||||
- *
|
||||
- * @param return_code the CCA return code
|
||||
- * @param reason_code the CCA reason code
|
||||
- */
|
||||
-static void print_CCA_error(int return_code, int reason_code)
|
||||
-{
|
||||
- switch (return_code) {
|
||||
- case 8:
|
||||
- switch (reason_code) {
|
||||
- case 48:
|
||||
- warnx("The secure key has a CCA master key "
|
||||
- "verification pattern that is not valid");
|
||||
- break;
|
||||
- }
|
||||
- break;
|
||||
- case 12:
|
||||
- switch (reason_code) {
|
||||
- case 764:
|
||||
- warnx("The CCA master key is not loaded and "
|
||||
- "therefore a secure key cannot be enciphered");
|
||||
- break;
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
- * Re-enciphers a secure key.
|
||||
- *
|
||||
- * @param[in] dll_CSNBKTC the address of the CCA CSNBKTC function
|
||||
- * @param[in] secure_key a buffer containing the secure key
|
||||
- * @param[in] secure_key_size the size of the secure key
|
||||
- * @param[in] method the re-enciphering method. METHOD_OLD_TO_CURRENT
|
||||
- * or METHOD_CURRENT_TO_NEW.
|
||||
- * @param[in] verbose if true, verbose messages are printed
|
||||
- *
|
||||
- * @returns 0 on success, -EIO in case of an error
|
||||
- */
|
||||
-int key_token_change(t_CSNBKTC dll_CSNBKTC,
|
||||
- u8 *secure_key, unsigned int secure_key_size,
|
||||
- char *method, bool verbose)
|
||||
-{
|
||||
- long exit_data_len = 0, rule_array_count;
|
||||
- unsigned char rule_array[2 * 80] = { 0, };
|
||||
- unsigned char exit_data[4] = { 0, };
|
||||
- long return_code, reason_code;
|
||||
-
|
||||
- util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
|
||||
- util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
- util_assert(secure_key_size > 0,
|
||||
- "Internal error: secure_key_size is 0");
|
||||
- util_assert(method != NULL, "Internal error: method is NULL");
|
||||
-
|
||||
- memcpy(rule_array, method, 8);
|
||||
- memcpy(rule_array + 8, "AES ", 8);
|
||||
- rule_array_count = 2;
|
||||
-
|
||||
- dll_CSNBKTC(&return_code, &reason_code,
|
||||
- &exit_data_len, exit_data,
|
||||
- &rule_array_count, rule_array,
|
||||
- secure_key);
|
||||
-
|
||||
- pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' returned: "
|
||||
- "return_code: %ld, reason_code: %ld", method, return_code,
|
||||
- reason_code);
|
||||
- if (return_code != 0) {
|
||||
- print_CCA_error(return_code, reason_code);
|
||||
- return -EIO;
|
||||
- }
|
||||
-
|
||||
- if (secure_key_size == 2 * SECURE_KEY_SIZE) {
|
||||
- dll_CSNBKTC(&return_code, &reason_code,
|
||||
- &exit_data_len, exit_data,
|
||||
- &rule_array_count, rule_array,
|
||||
- secure_key + SECURE_KEY_SIZE);
|
||||
-
|
||||
- pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
|
||||
- "returned: return_code: %ld, reason_code: %ld",
|
||||
- method, return_code, reason_code);
|
||||
- if (return_code != 0) {
|
||||
- print_CCA_error(return_code, reason_code);
|
||||
- return -EIO;
|
||||
- }
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
* Validates an XTS secure key (the second part)
|
||||
*
|
||||
* @param[in] pkey_fd the pkey file descriptor
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -82,23 +82,10 @@ struct pkey_verifykey {
|
||||
|
||||
#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
|
||||
|
||||
-#define METHOD_OLD_TO_CURRENT "RTCMK "
|
||||
-#define METHOD_CURRENT_TO_NEW "RTNMK "
|
||||
-
|
||||
-typedef void (*t_CSNBKTC)(long *return_code,
|
||||
- long *reason_code,
|
||||
- long *exit_data_length,
|
||||
- unsigned char *exit_data,
|
||||
- long *rule_array_count,
|
||||
- unsigned char *rule_array,
|
||||
- unsigned char *key_identifier);
|
||||
-
|
||||
#define PAES_BLOCK_SIZE 16
|
||||
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
|
||||
#define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1)
|
||||
|
||||
-int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose);
|
||||
-
|
||||
int open_pkey_device(bool verbose);
|
||||
|
||||
int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
@@ -122,10 +109,6 @@ int validate_secure_key(int pkey_fd,
|
||||
size_t *clear_key_bitsize, int *is_old_mk,
|
||||
bool verbose);
|
||||
|
||||
-int key_token_change(t_CSNBKTC dll_CSNBKTC,
|
||||
- u8 *secure_key, unsigned int secure_key_size,
|
||||
- char *method, bool verbose);
|
||||
-
|
||||
int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "misc.h"
|
||||
#include "pkey.h"
|
||||
+#include "cca.h"
|
||||
|
||||
/* Detect if cryptsetup 2.1 or later is available */
|
||||
#ifdef CRYPT_LOG_DEBUG_JSON
|
||||
@@ -101,8 +102,7 @@ static struct zkey_cryptsetup_globals {
|
||||
bool batch_mode;
|
||||
bool debug;
|
||||
bool verbose;
|
||||
- void *lib_csulcca;
|
||||
- t_CSNBKTC dll_CSNBKTC;
|
||||
+ struct cca_lib cca;
|
||||
int pkey_fd;
|
||||
struct crypt_device *cd;
|
||||
} g = {
|
||||
@@ -1578,7 +1578,7 @@ static int reencipher_prepare(int token)
|
||||
util_print_indented(msg, 0);
|
||||
free(msg);
|
||||
|
||||
- rc = key_token_change(g.dll_CSNBKTC, (u8 *)key, keysize,
|
||||
+ rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
is_old_mk ? METHOD_OLD_TO_CURRENT :
|
||||
METHOD_CURRENT_TO_NEW,
|
||||
g.verbose);
|
||||
@@ -1700,7 +1700,7 @@ static int reencipher_complete(int token
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = key_token_change(g.dll_CSNBKTC, (u8 *)key, keysize,
|
||||
+ rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
METHOD_OLD_TO_CURRENT, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to re-encipher the secure volume key for "
|
||||
@@ -2288,8 +2288,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (command->need_cca_library) {
|
||||
- rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC,
|
||||
- g.verbose);
|
||||
+ rc = load_cca_library(&g.cca, g.verbose);
|
||||
if (rc != 0) {
|
||||
rc = EXIT_FAILURE;
|
||||
goto out;
|
||||
@@ -2331,8 +2330,8 @@ int main(int argc, char *argv[])
|
||||
rc = command->function();
|
||||
|
||||
out:
|
||||
- if (g.lib_csulcca)
|
||||
- dlclose(g.lib_csulcca);
|
||||
+ if (g.cca.lib_csulcca)
|
||||
+ dlclose(g.cca.lib_csulcca);
|
||||
if (g.pkey_fd >= 0)
|
||||
close(g.pkey_fd);
|
||||
if (g.cd)
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
+#include "cca.h"
|
||||
#include "keystore.h"
|
||||
#include "misc.h"
|
||||
#include "pkey.h"
|
||||
@@ -80,8 +81,7 @@ static struct zkey_globals {
|
||||
bool force;
|
||||
bool open;
|
||||
bool format;
|
||||
- void *lib_csulcca;
|
||||
- t_CSNBKTC dll_CSNBKTC;
|
||||
+ struct cca_lib cca;
|
||||
int pkey_fd;
|
||||
struct keystore *keystore;
|
||||
} g = {
|
||||
@@ -1194,8 +1194,7 @@ static int command_reencipher_file(void)
|
||||
pr_verbose("Secure key will be re-enciphered from OLD to the "
|
||||
"CURRENT CCA master key");
|
||||
|
||||
- rc = key_token_change(g.dll_CSNBKTC,
|
||||
- secure_key, secure_key_size,
|
||||
+ rc = key_token_change(&g.cca, secure_key, secure_key_size,
|
||||
METHOD_OLD_TO_CURRENT,
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
@@ -1209,8 +1208,7 @@ static int command_reencipher_file(void)
|
||||
pr_verbose("Secure key will be re-enciphered from CURRENT "
|
||||
"to the NEW CCA master key");
|
||||
|
||||
- rc = key_token_change(g.dll_CSNBKTC,
|
||||
- secure_key, secure_key_size,
|
||||
+ rc = key_token_change(&g.cca, secure_key, secure_key_size,
|
||||
METHOD_CURRENT_TO_NEW, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Re-encipher from CURRENT to NEW CCA "
|
||||
@@ -1270,7 +1268,7 @@ static int command_reencipher_repository
|
||||
|
||||
rc = keystore_reencipher_key(g.keystore, g.name, g.apqns, g.fromold,
|
||||
g.tonew, g.inplace, g.staged, g.complete,
|
||||
- g.pkey_fd, g.dll_CSNBKTC);
|
||||
+ g.pkey_fd, &g.cca);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1867,8 +1865,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (command->need_cca_library) {
|
||||
- rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC,
|
||||
- g.verbose);
|
||||
+ rc = load_cca_library(&g.cca, g.verbose);
|
||||
if (rc != 0) {
|
||||
rc = EXIT_FAILURE;
|
||||
goto out;
|
||||
@@ -1887,8 +1884,8 @@ int main(int argc, char *argv[])
|
||||
rc = command->function();
|
||||
|
||||
out:
|
||||
- if (g.lib_csulcca)
|
||||
- dlclose(g.lib_csulcca);
|
||||
+ if (g.cca.lib_csulcca)
|
||||
+ dlclose(g.cca.lib_csulcca);
|
||||
if (g.pkey_fd >= 0)
|
||||
close(g.pkey_fd);
|
||||
if (g.keystore)
|
@ -1,70 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184174] zpcictl: Initiate recover after reset
|
||||
From: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
Description: zpcictl: Initiate recover after reset
|
||||
Symptom: If a PCI function is reset using zpcictl --reset, the function
|
||||
is in an error state.
|
||||
Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI
|
||||
function in an error state.
|
||||
Solution: Initiate an OS level recovery by calling
|
||||
/sys/bus/devices/<dev>/recover after the SCLP reset.
|
||||
Reproduction: Call zpcictl --reset <dev>
|
||||
Under z/VM check the state of the function with 'vmcp q pcif'
|
||||
Upstream-ID: bc0d40c5803d4c5426b17b6d59aa0f1e46a2aacc
|
||||
Problem-ID: 184174
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zpcictl: Initiate recover after reset
|
||||
|
||||
After a zpcitctl --reset the PCI function is currently left in an error
|
||||
state. This seems unexpected, so follow the SCLP reset with an OS level
|
||||
recovery using /sys/bus/devices/<dev>/recover.
|
||||
|
||||
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
|
||||
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
---
|
||||
zpcictl/zpcictl.c | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
--- a/zpcictl/zpcictl.c
|
||||
+++ b/zpcictl/zpcictl.c
|
||||
@@ -163,6 +163,26 @@ static unsigned int sysfs_read_value(str
|
||||
return val;
|
||||
}
|
||||
|
||||
+static void sysfs_write_value(struct zpci_device *pdev, const char *attr,
|
||||
+ unsigned int val)
|
||||
+{
|
||||
+ char *path;
|
||||
+ FILE *fp;
|
||||
+
|
||||
+ path = util_path_sysfs("bus/pci/devices/%s/%s", pdev->slot, attr);
|
||||
+ fp = fopen(path, "w");
|
||||
+ if (!fp)
|
||||
+ fopen_err(path);
|
||||
+ if (fprintf(fp, "%x", val) < 0) {
|
||||
+ fclose(fp);
|
||||
+ warnx("Could not write to file %s: %s", path, strerror(errno));
|
||||
+ free(path);
|
||||
+ exit(EXIT_FAILURE);
|
||||
+ }
|
||||
+ fclose(fp);
|
||||
+ free(path);
|
||||
+}
|
||||
+
|
||||
static void sysfs_write_data(struct zpci_report_error *report, char *slot)
|
||||
{
|
||||
size_t r_size;
|
||||
@@ -297,6 +317,7 @@ static void sclp_issue_action(struct zpc
|
||||
static void sclp_reset_device(struct zpci_device *pdev)
|
||||
{
|
||||
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET);
|
||||
+ sysfs_write_value(pdev, "recover", 1);
|
||||
}
|
||||
|
||||
/*
|
@ -1,170 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184396] zipl: allow stand alone secure option on command line
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: fix secure boot config handling
|
||||
Symptom: The config file parsing for secure boot worked not as
|
||||
it was expected to be. For example a config section
|
||||
setting was not evaluated properly.
|
||||
It is not possible to specify command line option -S
|
||||
without other options.
|
||||
Additionally the man page showed an invalid example.
|
||||
Problem: The config file parsing was not implemented properly.
|
||||
Solution: The hierarchy of the secure boot settings in the config
|
||||
file is:
|
||||
defaultboot > menu > section
|
||||
Allow that --secure or -S is specified on command line
|
||||
without the need to allow all options on the command
|
||||
line. Also ensure that the command line option
|
||||
overrules the config option and correctly ensure that
|
||||
secure boot is only set for SCSI devices.
|
||||
Fix man page example.
|
||||
Reproduction: Run zipl with a secure= setting in a configuration
|
||||
section or specify -S on command line.
|
||||
Upstream-ID: 27f6c0a167da8d08f7f3343360528528f85d661f
|
||||
Problem-ID: 184396
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: allow stand alone secure option on command line
|
||||
|
||||
Allow that --secure or -S is specified on command line without the need to
|
||||
allow all options on the command line.
|
||||
Also ensure that the command line option overrules the config option and
|
||||
correctly ensure that secure boot is only set for SCSI devices.
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
zipl/src/bootmap.c | 6 ++++++
|
||||
zipl/src/job.c | 52 +++++++++++++++++++++++++---------------------------
|
||||
2 files changed, 31 insertions(+), 27 deletions(-)
|
||||
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -1133,6 +1133,12 @@ bootmap_create(struct job_data *job, dis
|
||||
disk_get_type_name(info->type));
|
||||
goto out_disk_free_info;
|
||||
}
|
||||
+ /* Check if secure boot was enabled only for SCSI */
|
||||
+ if (job->is_secure == SECURE_BOOT_ENABLED &&
|
||||
+ info->type != disk_type_scsi) {
|
||||
+ error_reason("Secure boot forced for non-SCSI disk type");
|
||||
+ goto out_disk_free_info;
|
||||
+ }
|
||||
if (verbose) {
|
||||
printf("Target device information\n");
|
||||
disk_print_info(info);
|
||||
--- a/zipl/src/job.c
|
||||
+++ b/zipl/src/job.c
|
||||
@@ -72,6 +72,7 @@ struct command_line {
|
||||
int add_files;
|
||||
int dry_run;
|
||||
int force;
|
||||
+ int is_secure;
|
||||
enum scan_section_type type;
|
||||
};
|
||||
|
||||
@@ -89,6 +90,22 @@ store_option(struct command_line* cmdlin
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+set_secure_ipl(char *keyword, int *is_secure)
|
||||
+{
|
||||
+ if (strcmp(keyword, "auto") == 0) {
|
||||
+ *is_secure = SECURE_BOOT_AUTO;
|
||||
+ } else if (strcmp(keyword, "0") == 0) {
|
||||
+ *is_secure = SECURE_BOOT_DISABLED;
|
||||
+ } else if (strcmp(keyword, "1") == 0) {
|
||||
+ *is_secure = SECURE_BOOT_ENABLED;
|
||||
+ } else {
|
||||
+ error_reason("Invalid secure boot setting '%s'",
|
||||
+ keyword);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
static int
|
||||
get_command_line(int argc, char* argv[], struct command_line* line)
|
||||
@@ -217,9 +234,7 @@ get_command_line(int argc, char* argv[],
|
||||
cmdline.menu = optarg;
|
||||
break;
|
||||
case 'S':
|
||||
- is_keyword = 1;
|
||||
- rc = store_option(&cmdline, scan_keyword_secure,
|
||||
- optarg);
|
||||
+ rc = set_secure_ipl(optarg, &cmdline.is_secure);
|
||||
break;
|
||||
case 'h':
|
||||
cmdline.help = 1;
|
||||
@@ -1270,27 +1285,6 @@ type_from_target(char *target, disk_type
|
||||
}
|
||||
|
||||
static int
|
||||
-set_secure_ipl(char *keyword, struct job_data *job)
|
||||
-{
|
||||
- if (strcmp(keyword, "auto") == 0) {
|
||||
- job->is_secure = SECURE_BOOT_AUTO;
|
||||
- } else if (strcmp(keyword, "0") == 0) {
|
||||
- job->is_secure = SECURE_BOOT_DISABLED;
|
||||
- } else if (strcmp(keyword, "1") == 0) {
|
||||
- if (job->target.targettype != disk_type_scsi) {
|
||||
- error_reason("Secure boot forced for non-SCSI disk type");
|
||||
- return -1;
|
||||
- }
|
||||
- job->is_secure = SECURE_BOOT_ENABLED;
|
||||
- } else {
|
||||
- error_reason("Invalid secure boot setting '%s'",
|
||||
- keyword);
|
||||
- return -1;
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static int
|
||||
get_job_from_section_data(char* data[], struct job_data* job, char* section)
|
||||
{
|
||||
int rc;
|
||||
@@ -1374,7 +1368,7 @@ get_job_from_section_data(char* data[],
|
||||
/* Fill in secure boot */
|
||||
if (data[(int) scan_keyword_secure] != NULL) {
|
||||
rc = set_secure_ipl(data[(int) scan_keyword_secure],
|
||||
- job);
|
||||
+ &job->is_secure);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
@@ -1538,7 +1532,7 @@ get_menu_job(struct scan_token* scan, ch
|
||||
case scan_keyword_secure:
|
||||
rc = set_secure_ipl(
|
||||
scan[i].content.keyword.value,
|
||||
- job);
|
||||
+ &job->is_secure);
|
||||
if (rc)
|
||||
return rc;
|
||||
break;
|
||||
@@ -1880,7 +1874,6 @@ job_get(int argc, char* argv[], struct j
|
||||
job->add_files = cmdline.add_files;
|
||||
job->data.mvdump.force = cmdline.force;
|
||||
job->dry_run = cmdline.dry_run;
|
||||
- job->is_secure = SECURE_BOOT_AUTO;
|
||||
/* Get job data from user input */
|
||||
if (cmdline.help) {
|
||||
job->command_line = 1;
|
||||
@@ -1899,6 +1892,11 @@ job_get(int argc, char* argv[], struct j
|
||||
job_free(job);
|
||||
return rc;
|
||||
}
|
||||
+ if (cmdline.is_secure)
|
||||
+ job->is_secure = cmdline.is_secure;
|
||||
+ else
|
||||
+ job->is_secure = job->is_secure ? : SECURE_BOOT_AUTO;
|
||||
+
|
||||
/* Check job data for validity */
|
||||
rc = check_job_data(job);
|
||||
if (rc) {
|
@ -1,102 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: fix -Waddress-of-packed-member
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: aa09b292483eb2d79247260fccc2b456dee01e8d
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: fix -Waddress-of-packed-member
|
||||
|
||||
Reported by GCC 9.2.1 when building with '-Waddress-of-packed-member'.
|
||||
|
||||
menu.c: In function 'menu_read':
|
||||
menu.c:30:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
30 | uint16_t *configs = __stage2_params.config;
|
||||
| ^~~~~~~~~~~~~~~
|
||||
menu.c: In function 'menu_list':
|
||||
menu.c:83:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
83 | uint16_t *configs = __stage2_params.config;
|
||||
| ^~~~~~~~~~~~~~~
|
||||
menu.c: In function 'menu':
|
||||
menu.c:139:22: warning: taking address of packed member of 'struct boot_stage2_params' may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
139 | uint16_t *configs = __stage2_params.config;
|
||||
| ^~~~~~~~~~~~~~~
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/menu.c | 13 +++++--------
|
||||
1 file changed, 5 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/zipl/boot/menu.c
|
||||
+++ b/zipl/boot/menu.c
|
||||
@@ -27,7 +27,6 @@ static void menu_prompt(int timeout)
|
||||
static int menu_read(void)
|
||||
{
|
||||
char *temp_area = (char *)get_zeroed_page();
|
||||
- uint16_t *configs = __stage2_params.config;
|
||||
int timeout, rc, i, count = 0;
|
||||
char *endptr;
|
||||
int value;
|
||||
@@ -60,7 +59,7 @@ static int menu_read(void)
|
||||
value = ebcstrtoul((char *)temp_area, &endptr, 10);
|
||||
|
||||
if ((endptr != temp_area) && (value < BOOT_MENU_ENTRIES - 1) &&
|
||||
- (configs[value] != 0)) {
|
||||
+ (__stage2_params.config[value] != 0)) {
|
||||
/* valid config found - finish */
|
||||
break;
|
||||
} else {
|
||||
@@ -80,14 +79,13 @@ out_free_page:
|
||||
|
||||
static int menu_list(void)
|
||||
{
|
||||
- uint16_t *configs = __stage2_params.config;
|
||||
char *name;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BOOT_MENU_ENTRIES; i++) {
|
||||
- if (configs[i] == 0)
|
||||
+ if (__stage2_params.config[i] == 0)
|
||||
continue;
|
||||
- name = configs[i] + ((void *)&__stage2_params);
|
||||
+ name = __stage2_params.config[i] + ((void *)&__stage2_params);
|
||||
printf("%s\n", name);
|
||||
if (i == 0)
|
||||
printf("\n");
|
||||
@@ -136,7 +134,6 @@ static int menu_param(unsigned long *val
|
||||
|
||||
int menu(void)
|
||||
{
|
||||
- uint16_t *configs = __stage2_params.config;
|
||||
unsigned long value = 0;
|
||||
char *cmd_line_extra;
|
||||
char endstring[15];
|
||||
@@ -181,11 +178,11 @@ int menu(void)
|
||||
|
||||
boot:
|
||||
/* sanity - config entry not valid */
|
||||
- if (configs[value] == 0)
|
||||
+ if (__stage2_params.config[value] == 0)
|
||||
panic(EINTERNAL, "%s", msg_econfig);
|
||||
|
||||
printf("Booting %s\n",
|
||||
- (char *)(configs[value] +
|
||||
+ (char *)(__stage2_params.config[value] +
|
||||
(void *)&__stage2_params + TEXT_OFFSET));
|
||||
|
||||
/* append 'BOOT_IMAGE=<num>' to parmline */
|
@ -1,63 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184060] zipl/libc: Fix potential buffer overflow in printf
|
||||
From: Philipp Rudo <prudo@linux.ibm.com>
|
||||
|
||||
Description: zipl/libc: Fix potential buffer overflow in printf
|
||||
Symptom: Crash of the zipl boot loader during boot.
|
||||
Problem: The zipl boot loaders have their own minimalistic libc
|
||||
implementation. In it printf and sprintf use vsprintf for string
|
||||
formatting. Per definition vsprintf assumes that the buffer it
|
||||
writes to is large enough to contain the formatted string and
|
||||
performs no size checks. This is problematic for the boot
|
||||
loaders because the buffer they use are often allocated on the
|
||||
stack. Thus even small changes to the string format can
|
||||
potentially cause buffer overflows on the stack.
|
||||
Solution: Implement vsnprintf and make use of it.
|
||||
Reproduction: Use printf to print a string with >81 characters (exact number
|
||||
depends on the stack layout/compiler used).
|
||||
Upstream-ID: 8874b908254c47c8a6fd7a1aca2c7371c11035c4
|
||||
Problem-ID: 184060
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: Fix potential buffer overflow in printf
|
||||
|
||||
Per definition vsprint assumes that the provided buffer it writes to is
|
||||
large enough to contain the formatted string. As printf uses a fixed
|
||||
sized buffer (81 bytes) and has no size checks the use of vsprintf can
|
||||
easily cause buffer overflows. Protect against these buffer overflows by
|
||||
using vsnprintf instead.
|
||||
|
||||
While at it fix a typo in the comment.
|
||||
|
||||
Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -530,7 +530,7 @@ void sprintf(char *str, const char *fmt,
|
||||
}
|
||||
|
||||
/*
|
||||
- * Print formated string
|
||||
+ * Print formatted string to console
|
||||
*/
|
||||
void printf(const char *fmt, ...)
|
||||
{
|
||||
@@ -538,7 +538,7 @@ void printf(const char *fmt, ...)
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
- vsprintf(buf, fmt, va);
|
||||
+ vsnprintf(buf, sizeof(buf), fmt, va);
|
||||
sclp_print(buf);
|
||||
va_end(va);
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
Subject: [PATCH] [BZ 186940] zipl/stage3: correctly handle diag308 response code
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: Fix KVM IPL without bootindex
|
||||
Symptom: Failed IPL on KVM when no bootindex is specified.
|
||||
Problem: Without bootindex specified there is no IPL parmblock
|
||||
on KVM which can be read by the stage3 loader.
|
||||
Solution: In case diag308 gives a response code 0x102 the stage3
|
||||
loader can safely assume that no secure IPL is required
|
||||
since no IPL report block exists.
|
||||
Reproduction: IPL on KVM without 'bootindex=' attached.
|
||||
Upstream-ID: b7f1977d3f9332f82e7f388fb18076b89b83944e
|
||||
Problem-ID: 186940
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/stage3: correctly handle diag308 response code
|
||||
|
||||
In case diag308 gives a response code 0x102 the stage3 loader can
|
||||
safely assume that no secure IPL is required since no IPL report
|
||||
block exists.
|
||||
|
||||
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
include/boot/s390.h | 1 +
|
||||
zipl/boot/stage3.c | 25 +++++++++++--------------
|
||||
2 files changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/include/boot/s390.h
|
||||
+++ b/include/boot/s390.h
|
||||
@@ -279,6 +279,7 @@ enum diag308_subcode {
|
||||
|
||||
enum diag308_rc {
|
||||
DIAG308_RC_OK = 0x0001,
|
||||
+ DIAG308_RC_NO_CONF = 0x0102,
|
||||
};
|
||||
|
||||
static __always_inline unsigned long diag308(unsigned long subcode, void *addr)
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -55,18 +55,6 @@ static inline void __noreturn start_kern
|
||||
while (1);
|
||||
}
|
||||
|
||||
-unsigned int store_ipl_parmblock(struct ipl_pl_hdr *pl_hdr)
|
||||
-{
|
||||
- int rc;
|
||||
-
|
||||
- rc = diag308(DIAG308_STORE, pl_hdr);
|
||||
- if (rc == DIAG308_RC_OK &&
|
||||
- pl_hdr->version <= IPL_MAX_SUPPORTED_VERSION)
|
||||
- return 0;
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
unsigned int
|
||||
is_verified_address(unsigned long image_addr)
|
||||
{
|
||||
@@ -124,9 +112,18 @@ secure_boot_enabled()
|
||||
unsigned int rc;
|
||||
|
||||
pl_hdr = (void *)get_zeroed_page();
|
||||
- if (!pl_hdr || store_ipl_parmblock(pl_hdr))
|
||||
+ switch (diag308(DIAG308_STORE, pl_hdr)) {
|
||||
+ case DIAG308_RC_OK:
|
||||
+ rc = pl_hdr->version <= IPL_MAX_SUPPORTED_VERSION &&
|
||||
+ !!(pl_hdr->flags & IPL_FLAG_SECURE);
|
||||
+ break;
|
||||
+ case DIAG308_RC_NO_CONF:
|
||||
+ rc = 0;
|
||||
+ break;
|
||||
+ default:
|
||||
panic(ESECUREBOOT, "%s", msg_sipl_noparm);
|
||||
- rc = !!(pl_hdr->flags & IPL_FLAG_SECURE);
|
||||
+ break;
|
||||
+ }
|
||||
free_page((unsigned long) pl_hdr);
|
||||
|
||||
return rc;
|
@ -1,297 +0,0 @@
|
||||
Subject: zkey: Move utility functions into separate source file
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 696e8458f0c117e3a084e1a083de89ec19baaff9
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Move utility functions into separate source file
|
||||
|
||||
As preparation for future changes, move a sysfs specific functions
|
||||
into a separate source file (utils.c).
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/Makefile | 5 +-
|
||||
zkey/keystore.c | 69 +----------------------------------
|
||||
zkey/utils.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 21 ++++++++++
|
||||
4 files changed, 136 insertions(+), 68 deletions(-)
|
||||
|
||||
--- a/zkey/Makefile
|
||||
+++ b/zkey/Makefile
|
||||
@@ -67,12 +67,13 @@ all: $(BUILD_TARGETS)
|
||||
zkey.o: zkey.c pkey.h cca.h misc.h
|
||||
pkey.o: pkey.c pkey.h
|
||||
cca.o: cca.c cca.h pkey.h
|
||||
+utils.o: utils.h
|
||||
properties.o: check-dep-zkey properties.c properties.h
|
||||
-keystore.o: keystore.c keystore.h properties.h pkey.h cca.h
|
||||
+keystore.o: keystore.c keystore.h properties.h pkey.h cca.h utils.h
|
||||
zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h cca.h misc.h
|
||||
|
||||
zkey: LDLIBS = -ldl -lcrypto
|
||||
-zkey: zkey.o pkey.o cca.o properties.o keystore.o $(libs)
|
||||
+zkey: zkey.o pkey.o cca.o properties.o keystore.o utils.o $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
-#include "lib/util_file.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_panic.h"
|
||||
#include "lib/util_path.h"
|
||||
@@ -35,6 +34,7 @@
|
||||
#include "pkey.h"
|
||||
#include "cca.h"
|
||||
#include "properties.h"
|
||||
+#include "utils.h"
|
||||
|
||||
struct key_filenames {
|
||||
char *skey_filename;
|
||||
@@ -1010,69 +1010,6 @@ free:
|
||||
return rc;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * Checks if the specified APQN is of type CCA and is online
|
||||
- *
|
||||
- * @param[in] card card number
|
||||
- * @param[in] domain the domain
|
||||
- *
|
||||
- * @returns 1 if its a CCA card and is online, 0 if offline and -1 if its
|
||||
- * not a CCA card.
|
||||
- */
|
||||
-static int _keystore_is_apqn_online(int card, int domain)
|
||||
-{
|
||||
- long int online;
|
||||
- char *dev_path;
|
||||
- char type[20];
|
||||
- int rc = 1;
|
||||
-
|
||||
- dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
|
||||
- if (!util_path_is_dir(dev_path)) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (online == 0) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (type[4] != 'C') {
|
||||
- rc = -1;
|
||||
- goto out;
|
||||
- }
|
||||
- free(dev_path);
|
||||
-
|
||||
- dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x", card,
|
||||
- card, domain);
|
||||
- if (!util_path_is_dir(dev_path)) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
- if (online == 0) {
|
||||
- rc = 0;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
-out:
|
||||
- free(dev_path);
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
struct apqn_check {
|
||||
bool noonlinecheck;
|
||||
bool nomsg;
|
||||
@@ -1124,7 +1061,7 @@ static int _keystore_apqn_check(const ch
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = _keystore_is_apqn_online(card, domain);
|
||||
+ rc = sysfs_is_apqn_online(card, domain);
|
||||
if (rc != 1) {
|
||||
if (info->nomsg == 0)
|
||||
warnx("The APQN %02x.%04x is %s", card, domain,
|
||||
@@ -2329,7 +2266,7 @@ static int _keystore_display_apqn_status
|
||||
if (sscanf(apqn_list[i], "%x.%x", &card, &domain) != 2)
|
||||
continue;
|
||||
|
||||
- rc = _keystore_is_apqn_online(card, domain);
|
||||
+ rc = sysfs_is_apqn_online(card, domain);
|
||||
if (rc != 1) {
|
||||
printf("WARNING: The APQN %02x.%04x associated with "
|
||||
"key '%s' is %s\n", card, domain, name,
|
||||
--- /dev/null
|
||||
+++ b/zkey/utils.c
|
||||
@@ -0,0 +1,109 @@
|
||||
+/*
|
||||
+ * zkey - Generate, re-encipher, and validate secure keys
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2019
|
||||
+ *
|
||||
+ * 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 <err.h>
|
||||
+#include <errno.h>
|
||||
+#include <stdbool.h>
|
||||
+#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
+#include <string.h>
|
||||
+#include <stdint.h>
|
||||
+#include <sys/types.h>
|
||||
+#include <unistd.h>
|
||||
+
|
||||
+#include "lib/util_path.h"
|
||||
+#include "lib/util_file.h"
|
||||
+
|
||||
+#include "utils.h"
|
||||
+
|
||||
+/**
|
||||
+ * Checks if the specified card is of type CCA and is online
|
||||
+ *
|
||||
+ * @param[in] card card number
|
||||
+ *
|
||||
+ * @returns 1 if its a CCA card and is online, 0 if offline and -1 if its
|
||||
+ * not a CCA card.
|
||||
+ */
|
||||
+int sysfs_is_card_online(int card)
|
||||
+{
|
||||
+ long int online;
|
||||
+ char *dev_path;
|
||||
+ char type[20];
|
||||
+ int rc = 1;
|
||||
+
|
||||
+ dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
|
||||
+ if (!util_path_is_dir(dev_path)) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (online == 0) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (type[4] != 'C') {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ free(dev_path);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Checks if the specified APQN is of type CCA and is online
|
||||
+ *
|
||||
+ * @param[in] card card number
|
||||
+ * @param[in] domain the domain
|
||||
+ *
|
||||
+ * @returns 1 if its a CCA card and is online, 0 if offline and -1 if its
|
||||
+ * not a CCA card.
|
||||
+ */
|
||||
+int sysfs_is_apqn_online(int card, int domain)
|
||||
+{
|
||||
+ long int online;
|
||||
+ char *dev_path;
|
||||
+ int rc = 1;
|
||||
+
|
||||
+ rc = sysfs_is_card_online(card);
|
||||
+ if (rc != 1)
|
||||
+ return rc;
|
||||
+
|
||||
+ dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x", card,
|
||||
+ card, domain);
|
||||
+ if (!util_path_is_dir(dev_path)) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (util_file_read_l(&online, 10, "%s/online", dev_path) != 0) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (online == 0) {
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ free(dev_path);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
--- /dev/null
|
||||
+++ b/zkey/utils.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * zkey - Generate, re-encipher, and validate secure keys
|
||||
+ *
|
||||
+ * This header file defines the interface to the CCA host library.
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2019
|
||||
+ *
|
||||
+ * 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 UTILS_H
|
||||
+#define UTILS_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+int sysfs_is_card_online(int card);
|
||||
+
|
||||
+int sysfs_is_apqn_online(int card, int domain);
|
||||
+
|
||||
+#endif
|
@ -1,51 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184174] zpcictl: Rename misleading sysfs_write_data
|
||||
From: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
Description: zpcictl: Initiate recover after reset
|
||||
Symptom: If a PCI function is reset using zpcictl --reset, the function
|
||||
is in an error state.
|
||||
Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI
|
||||
function in an error state.
|
||||
Solution: Initiate an OS level recovery by calling
|
||||
/sys/bus/devices/<dev>/recover after the SCLP reset.
|
||||
Reproduction: Call zpcictl --reset <dev>
|
||||
Under z/VM check the state of the function with 'vmcp q pcif'
|
||||
Upstream-ID: d77234ddb68719819c7e8380c71dbebc555539ab
|
||||
Problem-ID: 184174
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zpcictl: Rename misleading sysfs_write_data
|
||||
|
||||
To sysfs_report_error as it only writes to the report_error attribute.
|
||||
|
||||
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
|
||||
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
---
|
||||
zpcictl/zpcictl.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zpcictl/zpcictl.c
|
||||
+++ b/zpcictl/zpcictl.c
|
||||
@@ -183,7 +183,7 @@ static void sysfs_write_value(struct zpc
|
||||
free(path);
|
||||
}
|
||||
|
||||
-static void sysfs_write_data(struct zpci_report_error *report, char *slot)
|
||||
+static void sysfs_report_error(struct zpci_report_error *report, char *slot)
|
||||
{
|
||||
size_t r_size;
|
||||
char *path;
|
||||
@@ -308,7 +308,7 @@ static void sclp_issue_action(struct zpc
|
||||
sizeof(report.data.log_data));
|
||||
free(sdata);
|
||||
}
|
||||
- sysfs_write_data(&report, pdev->slot);
|
||||
+ sysfs_report_error(&report, pdev->slot);
|
||||
}
|
||||
|
||||
/*
|
@ -1,187 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184396] zipl: correct secure boot config handling
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: fix secure boot config handling
|
||||
Symptom: The config file parsing for secure boot worked not as
|
||||
it was expected to be. For example a config section
|
||||
setting was not evaluated properly.
|
||||
It is not possible to specify command line option -S
|
||||
without other options.
|
||||
Additionally the man page showed an invalid example.
|
||||
Problem: The config file parsing was not implemented properly.
|
||||
Solution: The hierarchy of the secure boot settings in the config
|
||||
file is:
|
||||
defaultboot > menu > section
|
||||
Allow that --secure or -S is specified on command line
|
||||
without the need to allow all options on the command
|
||||
line. Also ensure that the command line option
|
||||
overrules the config option and correctly ensure that
|
||||
secure boot is only set for SCSI devices.
|
||||
Fix man page example.
|
||||
Reproduction: Run zipl with a secure= setting in a configuration
|
||||
section or specify -S on command line.
|
||||
Upstream-ID: 6f9337d1016e00f360cf4a81d39a42df5184b3a2
|
||||
Problem-ID: 184396
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: correct secure boot config handling
|
||||
|
||||
The hierarchy of the secure boot settings in the config file should be:
|
||||
|
||||
defaultboot > menu > section
|
||||
|
||||
This patch implements this hierarchy and adds a check if a valid option is
|
||||
specified and prints an error message otherwise.
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
zipl/include/job.h | 1 +
|
||||
zipl/include/zipl.h | 1 +
|
||||
zipl/src/bootmap.c | 8 +++++++-
|
||||
zipl/src/job.c | 29 ++++++++++++++++++++++++++---
|
||||
4 files changed, 35 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/zipl/include/job.h
|
||||
+++ b/zipl/include/job.h
|
||||
@@ -94,6 +94,7 @@ struct job_menu_entry {
|
||||
char* name;
|
||||
enum job_id id;
|
||||
union job_menu_entry_data data;
|
||||
+ int is_secure;
|
||||
};
|
||||
|
||||
struct job_menu_data {
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -57,6 +57,7 @@
|
||||
|
||||
#define MAX_DUMP_VOLUMES 32
|
||||
|
||||
+#define SECURE_BOOT_UNDEFINED -1
|
||||
#define SECURE_BOOT_DISABLED 0
|
||||
#define SECURE_BOOT_ENABLED 1
|
||||
#define SECURE_BOOT_AUTO 2
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -945,6 +945,7 @@ build_program_table(int fd, struct job_d
|
||||
{
|
||||
disk_blockptr_t* table;
|
||||
int entries, component_header;
|
||||
+ int is_secure;
|
||||
int i;
|
||||
int rc;
|
||||
|
||||
@@ -1016,13 +1017,18 @@ build_program_table(int fd, struct job_d
|
||||
component_header_ipl;
|
||||
printf("\n");
|
||||
}
|
||||
+ if (job->is_secure != SECURE_BOOT_UNDEFINED)
|
||||
+ is_secure = job->is_secure;
|
||||
+ else
|
||||
+ is_secure =
|
||||
+ job->data.menu.entry[i].is_secure;
|
||||
rc = add_ipl_program(fd,
|
||||
&job->data.menu.entry[i].data.ipl,
|
||||
&table[job->data.menu.entry[i].pos],
|
||||
verbose || job->command_line,
|
||||
job->add_files, component_header,
|
||||
info, &job->target,
|
||||
- job->is_secure);
|
||||
+ is_secure);
|
||||
break;
|
||||
case job_print_usage:
|
||||
case job_print_version:
|
||||
--- a/zipl/src/job.c
|
||||
+++ b/zipl/src/job.c
|
||||
@@ -119,6 +119,7 @@ get_command_line(int argc, char* argv[],
|
||||
memset((void *) &cmdline, 0, sizeof(struct command_line));
|
||||
cmdline.type = section_invalid;
|
||||
is_keyword = 0;
|
||||
+ cmdline.is_secure = SECURE_BOOT_UNDEFINED;
|
||||
/* Process options */
|
||||
do {
|
||||
opt = getopt_long(argc, argv, option_string, options, NULL);
|
||||
@@ -1055,6 +1056,21 @@ check_job_mvdump_data(struct job_mvdump_
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+check_secure_boot(struct job_data *job)
|
||||
+{
|
||||
+ switch (job->is_secure) {
|
||||
+ case SECURE_BOOT_UNDEFINED:
|
||||
+ case SECURE_BOOT_DISABLED:
|
||||
+ case SECURE_BOOT_ENABLED:
|
||||
+ case SECURE_BOOT_AUTO:
|
||||
+ return 0;
|
||||
+ default:
|
||||
+ error_reason("Invalid secure boot setting '%d'",
|
||||
+ job->is_secure);
|
||||
+ return -1;
|
||||
+ }
|
||||
+}
|
||||
|
||||
static int
|
||||
check_job_data(struct job_data* job)
|
||||
@@ -1099,6 +1115,8 @@ check_job_data(struct job_data* job)
|
||||
case job_mvdump:
|
||||
rc = check_job_mvdump_data(&job->data.mvdump, job->name);
|
||||
}
|
||||
+ if (!rc)
|
||||
+ rc = check_secure_boot(job);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1594,6 +1612,7 @@ get_menu_job(struct scan_token* scan, ch
|
||||
sizeof(struct job_menu_entry) * job->data.menu.num);
|
||||
/* Fill in data */
|
||||
current = 0;
|
||||
+ job->data.menu.entry->is_secure = SECURE_BOOT_UNDEFINED;
|
||||
for (i=index+1; (scan[i].id != scan_id_empty) &&
|
||||
(scan[i].id != scan_id_section_heading) &&
|
||||
(scan[i].id != scan_id_menu_heading); i++) {
|
||||
@@ -1625,6 +1644,7 @@ get_menu_job(struct scan_token* scan, ch
|
||||
if (temp_job == NULL)
|
||||
return -1;
|
||||
memset((void *) temp_job, 0, sizeof(struct job_data));
|
||||
+ temp_job->is_secure = SECURE_BOOT_UNDEFINED;
|
||||
rc = get_job_from_section_data(data, temp_job,
|
||||
job->data.menu.entry[current].name);
|
||||
if (rc) {
|
||||
@@ -1637,6 +1657,8 @@ get_menu_job(struct scan_token* scan, ch
|
||||
job->data.menu.entry[current].id = job_ipl;
|
||||
job->data.menu.entry[current].data.ipl =
|
||||
temp_job->data.ipl;
|
||||
+ job->data.menu.entry[current].is_secure =
|
||||
+ temp_job->is_secure;
|
||||
memset((void *) &temp_job->data.ipl, 0,
|
||||
sizeof(struct job_ipl_data));
|
||||
break;
|
||||
@@ -1874,6 +1896,7 @@ job_get(int argc, char* argv[], struct j
|
||||
job->add_files = cmdline.add_files;
|
||||
job->data.mvdump.force = cmdline.force;
|
||||
job->dry_run = cmdline.dry_run;
|
||||
+ job->is_secure = SECURE_BOOT_UNDEFINED;
|
||||
/* Get job data from user input */
|
||||
if (cmdline.help) {
|
||||
job->command_line = 1;
|
||||
@@ -1892,10 +1915,10 @@ job_get(int argc, char* argv[], struct j
|
||||
job_free(job);
|
||||
return rc;
|
||||
}
|
||||
- if (cmdline.is_secure)
|
||||
+ if (cmdline.is_secure != SECURE_BOOT_UNDEFINED)
|
||||
job->is_secure = cmdline.is_secure;
|
||||
- else
|
||||
- job->is_secure = job->is_secure ? : SECURE_BOOT_AUTO;
|
||||
+ else if (job->id != job_menu && job->is_secure == SECURE_BOOT_UNDEFINED)
|
||||
+ job->is_secure = SECURE_BOOT_AUTO;
|
||||
|
||||
/* Check job data for validity */
|
||||
rc = check_job_data(job);
|
@ -1,236 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184060] zipl/libc: Replace sprintf with snprintf
|
||||
From: Philipp Rudo <prudo@linux.ibm.com>
|
||||
|
||||
Description: zipl/libc: Fix potential buffer overflow in printf
|
||||
Symptom: Crash of the zipl boot loader during boot.
|
||||
Problem: The zipl boot loaders have their own minimalistic libc
|
||||
implementation. In it printf and sprintf use vsprintf for string
|
||||
formatting. Per definition vsprintf assumes that the buffer it
|
||||
writes to is large enough to contain the formatted string and
|
||||
performs no size checks. This is problematic for the boot
|
||||
loaders because the buffer they use are often allocated on the
|
||||
stack. Thus even small changes to the string format can
|
||||
potentially cause buffer overflows on the stack.
|
||||
Solution: Implement vsnprintf and make use of it.
|
||||
Reproduction: Use printf to print a string with >81 characters (exact number
|
||||
depends on the stack layout/compiler used).
|
||||
Upstream-ID: f7430027b41d5ad6220e962a179c2a5213330a44
|
||||
Problem-ID: 184060
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: Replace sprintf with snprintf
|
||||
|
||||
The use of sprintf can easily result in buffer overflows as it assumes
|
||||
that the buffer it writes to is large enough to contain the formatted
|
||||
string. Thus replace sprintf by snprintf and update its users.
|
||||
|
||||
This removes the last user of vsprintf. Thus also remove vsprintf and
|
||||
its dependencies.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 132 +-------------------------------------------------
|
||||
zipl/boot/libc.h | 3 -
|
||||
zipl/boot/menu.c | 2
|
||||
zipl/boot/tape2dump.c | 2
|
||||
4 files changed, 6 insertions(+), 133 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -126,81 +126,6 @@ int strncmp(const char *s1, const char *
|
||||
}
|
||||
|
||||
/*
|
||||
- * Convert number to string
|
||||
- *
|
||||
- * Parameters:
|
||||
- *
|
||||
- * - buf: Output buffer
|
||||
- * - base: Base used for formatting (e.g. 10 or 16)
|
||||
- * - val: Number to format
|
||||
- * - zero: If > 0, fill with leading zeros, otherwise use blanks
|
||||
- * - count: Minimum number of characters used for output string
|
||||
- */
|
||||
-static int num_to_str(char *buf, int base, unsigned long val, int zero,
|
||||
- unsigned long count)
|
||||
-{
|
||||
- static const char conv_vec[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
- unsigned long num = 0, val_work = val, in_number = 1;
|
||||
- int i;
|
||||
-
|
||||
- /* Count number of characters needed for number */
|
||||
- do {
|
||||
- num++;
|
||||
- val_work /= base;
|
||||
- } while (val_work);
|
||||
- /* Real character number overwrites count */
|
||||
- if (count < num)
|
||||
- count = num;
|
||||
- /* Format number */
|
||||
- for (i = count - 1; i >= 0; i--) {
|
||||
- if (in_number) {
|
||||
- buf[i] = conv_vec[val % base];
|
||||
- val /= base;
|
||||
- in_number = val ? 1 : 0;
|
||||
- } else {
|
||||
- buf[i] = zero ? '0' : ' ';
|
||||
- }
|
||||
- }
|
||||
- buf[count] = 0;
|
||||
- return count;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * Convert string to string with indentation
|
||||
- */
|
||||
-static int str_to_str(char *buf, const char *str, unsigned long count)
|
||||
-{
|
||||
- unsigned long size;
|
||||
-
|
||||
- size = strlen(str);
|
||||
- if (count < size)
|
||||
- count = size;
|
||||
- else
|
||||
- memset(buf, ' ', count - size);
|
||||
- strcpy(buf + (count - size), str);
|
||||
- return count;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * Convert string to number with given base
|
||||
- */
|
||||
-unsigned long strtoul(const char *nptr, char **endptr, int base)
|
||||
-{
|
||||
- unsigned long val = 0;
|
||||
-
|
||||
- while (isdigit(*nptr)) {
|
||||
- if (val != 0)
|
||||
- val *= base;
|
||||
- val += *nptr - '0';
|
||||
- nptr++;
|
||||
- }
|
||||
- if (endptr)
|
||||
- *endptr = (char *) nptr;
|
||||
- return val;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
* Convert ebcdic string to number with given base
|
||||
*/
|
||||
unsigned long ebcstrtoul(char *nptr, char **endptr, int base)
|
||||
@@ -467,65 +392,14 @@ static int vsnprintf(char *buf, unsigned
|
||||
}
|
||||
|
||||
/*
|
||||
- * Convert string to number with given base
|
||||
- */
|
||||
-static int sprintf_fmt(char type, char *buf, unsigned long val, int zero,
|
||||
- int count)
|
||||
-{
|
||||
- switch (type) {
|
||||
- case 's':
|
||||
- return str_to_str(buf, (const char *) val, count);
|
||||
- case 'x':
|
||||
- return num_to_str(buf, 16, val, zero, count);
|
||||
- case 'u':
|
||||
- return num_to_str(buf, 10, val, zero, count);
|
||||
- default:
|
||||
- libc_stop(EINTERNAL);
|
||||
- }
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * Print formated string (va version)
|
||||
- */
|
||||
-static void vsprintf(char *str, const char *fmt, va_list va)
|
||||
-{
|
||||
- unsigned long val, zero, count;
|
||||
- char *fmt_next;
|
||||
-
|
||||
- do {
|
||||
- if (*fmt == '%') {
|
||||
- fmt++;
|
||||
- if (*fmt == '0') {
|
||||
- zero = 1;
|
||||
- fmt++;
|
||||
- } else {
|
||||
- zero = 0;
|
||||
- }
|
||||
- /* No number found by strtoul: count=0 fmt_next=fmt */
|
||||
- count = strtoul(fmt, &fmt_next, 10);
|
||||
- fmt = fmt_next;
|
||||
- if (*fmt == 'l')
|
||||
- fmt++;
|
||||
- val = va_arg(va, unsigned long);
|
||||
- str += sprintf_fmt(*fmt, str, val, zero, count);
|
||||
- fmt++;
|
||||
- } else {
|
||||
- *str++ = *fmt++;
|
||||
- }
|
||||
- } while (*fmt);
|
||||
- *str = 0;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * Write formated string to string
|
||||
+ * Write formatted string to buffer
|
||||
*/
|
||||
-void sprintf(char *str, const char *fmt, ...)
|
||||
+void snprintf(char *buf, unsigned long size, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
- vsprintf(str, fmt, va);
|
||||
+ vsnprintf(buf, size, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -47,13 +47,12 @@ typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
void printf(const char *, ...);
|
||||
-void sprintf(char *, const char *, ...);
|
||||
+void snprintf(char *buf, unsigned long size, const char *fmt, ...);
|
||||
void *memcpy(void *, const void *, unsigned long);
|
||||
void *memmove(void *, const void *, unsigned long);
|
||||
void *memset(void *, int c, unsigned long);
|
||||
char *strcat(char *, const char *);
|
||||
int strncmp(const char *, const char *, unsigned long);
|
||||
-unsigned long strtoul(const char *, char **, int);
|
||||
unsigned long ebcstrtoul(char *, char **, int);
|
||||
int strlen(const char *);
|
||||
char *strcpy(char *, const char *);
|
||||
--- a/zipl/boot/menu.c
|
||||
+++ b/zipl/boot/menu.c
|
||||
@@ -189,7 +189,7 @@ boot:
|
||||
(void *)&__stage2_params + TEXT_OFFSET));
|
||||
|
||||
/* append 'BOOT_IMAGE=<num>' to parmline */
|
||||
- sprintf(endstring, " BOOT_IMAGE=%u", value);
|
||||
+ snprintf(endstring, sizeof(endstring), " BOOT_IMAGE=%u", value);
|
||||
if ((strlen(cmd_line_extra) + strlen(endstring)) < COMMAND_LINE_SIZE)
|
||||
strcat(cmd_line_extra, endstring);
|
||||
|
||||
--- a/zipl/boot/tape2dump.c
|
||||
+++ b/zipl/boot/tape2dump.c
|
||||
@@ -186,7 +186,7 @@ static void progress_print_disp(unsigned
|
||||
|
||||
if (addr % (1024 * 1024 * 16) != 0)
|
||||
return;
|
||||
- sprintf(msg, "%08u", addr >> 20);
|
||||
+ snprintf(msg, sizeof(msg), "%08u", addr >> 20);
|
||||
ccw_load_display(msg);
|
||||
}
|
||||
|
@ -1,143 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: remove some useless __packed___ attributes
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 2227bb8330aea1368ba234ae6f24fe0b5779d67d
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: remove some useless __packed___ attributes
|
||||
|
||||
The __packed__ attribute is not needed for these structures as they
|
||||
don't need any padding to meet the size and alignment constraints
|
||||
defined in the Linux for zSeries ABI.
|
||||
|
||||
Reported by GCC 9.2.1 when building with '-Waddress-of-packed-member'.
|
||||
|
||||
stage3.c: In function 'is_verified_address':
|
||||
stage3.c:241:26: warning: taking address of packed member of 'struct ipl_rb_components' may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
241 | for_each_rb_entry(comp, comps) {
|
||||
| ^~~~~
|
||||
stage3.c:18:15: note: in definition of macro 'for_each_rb_entry'
|
||||
18 | for (entry = rb->entries; \
|
||||
| ^~
|
||||
CC zipl/boot/kdump3.o
|
||||
CC zipl/boot/sclp_stage3.o
|
||||
sclp_stage3.c: In function '__sclp_hsa_copy':
|
||||
sclp_stage3.c:75:34: warning: converting a packed 'struct sdias_sccb' pointer (alignment 1) to a 'struct read_sccb' pointer (alignment 4096) may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
75 | if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
|
||||
| ^~~~~~~~~
|
||||
In file included from sclp_stage3.c:13:
|
||||
sclp_stage3.h:43:8: note: defined here
|
||||
43 | struct sdias_sccb {
|
||||
| ^~~~~~~~~~
|
||||
In file included from sclp_stage3.c:12:
|
||||
sclp.h:149:8: note: defined here
|
||||
149 | struct read_sccb {
|
||||
| ^~~~~~~~~
|
||||
sclp_stage3.c: In function 'sclp_hsa_get_size':
|
||||
sclp_stage3.c:126:34: warning: converting a packed 'struct sdias_sccb' pointer (alignment 1) to a 'struct read_sccb' pointer (alignment 4096) may result in an unaligned pointer value [-Waddress-of-packed-member]
|
||||
126 | if (sclp_hsa_copy_wait((struct read_sccb *)sccb))
|
||||
| ^~~~~~~~~
|
||||
In file included from sclp_stage3.c:13:
|
||||
sclp_stage3.h:43:8: note: defined here
|
||||
43 | struct sdias_sccb {
|
||||
| ^~~~~~~~~~
|
||||
In file included from sclp_stage3.c:12:
|
||||
sclp.h:149:8: note: defined here
|
||||
149 | struct read_sccb {
|
||||
| ^~~~~~~~~
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/sclp.h | 6 ++++--
|
||||
zipl/boot/sclp_stage3.h | 3 ++-
|
||||
zipl/boot/stage3.h | 6 ++++--
|
||||
3 files changed, 10 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/zipl/boot/sclp.h
|
||||
+++ b/zipl/boot/sclp.h
|
||||
@@ -53,19 +53,21 @@ struct gds_subvector {
|
||||
uint8_t key;
|
||||
} __packed;
|
||||
|
||||
+/* Structure must not have any padding */
|
||||
struct sccb_header {
|
||||
uint16_t length;
|
||||
uint8_t function_code;
|
||||
uint8_t control_mask[3];
|
||||
uint16_t response_code;
|
||||
-} __packed;
|
||||
+};
|
||||
|
||||
+/* Structure must not have any padding */
|
||||
struct evbuf_header {
|
||||
uint16_t length;
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t _reserved;
|
||||
-} __packed;
|
||||
+};
|
||||
|
||||
struct mto {
|
||||
uint16_t length;
|
||||
--- a/zipl/boot/sclp_stage3.h
|
||||
+++ b/zipl/boot/sclp_stage3.h
|
||||
@@ -40,10 +40,11 @@ struct sdias_evbuf {
|
||||
uint16_t dbs;
|
||||
} __packed;
|
||||
|
||||
+/* Structure must not have any padding */
|
||||
struct sdias_sccb {
|
||||
struct sccb_header header;
|
||||
struct sdias_evbuf evbuf;
|
||||
-} __packed;
|
||||
+};
|
||||
|
||||
|
||||
int sclp_hsa_copy(void *, unsigned long, unsigned long);
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -124,11 +124,12 @@ struct ipl_rl_hdr {
|
||||
} __packed;
|
||||
|
||||
/* IPL Report Block header */
|
||||
+/* Structure must not have any padding */
|
||||
struct ipl_rb_hdr {
|
||||
uint32_t len;
|
||||
uint8_t rbt;
|
||||
uint8_t reserved1[11];
|
||||
-} __packed;
|
||||
+};
|
||||
|
||||
/* IPL Report Block types */
|
||||
enum ipl_rbt {
|
||||
@@ -162,12 +163,13 @@ struct ipl_rb_component_entry {
|
||||
#define IPL_RB_COMPONENT_FLAG_SIGNED 0x80
|
||||
#define IPL_RB_COMPONENT_FLAG_VERIFIED 0x40
|
||||
|
||||
+/* Structure must not have any padding */
|
||||
struct ipl_rb_components {
|
||||
uint32_t len;
|
||||
uint8_t rbt;
|
||||
uint8_t reserved1[11];
|
||||
struct ipl_rb_component_entry entries[];
|
||||
-} __packed;
|
||||
+};
|
||||
|
||||
extern unsigned long long _parm_addr; /* address of parmline */
|
||||
extern unsigned long long _initrd_addr; /* address of initrd */
|
@ -1,112 +0,0 @@
|
||||
Subject: zkey: Add utility function to get the serial number of a crypto card
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: a84d1c5d58fa4a0c9e087357eec009803ea06ef2
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add utility function to get the serial number of a crypto card
|
||||
|
||||
With recent changes in the zcrypt device driver, the serial number of
|
||||
a crypto card can be obtained by reading the sysfs attribute 'serialnr'
|
||||
of a crypto card device of type CCA-Coprocessor. The sysfs attribute
|
||||
can be found under '/sys/devices/ap/cardnn/', where nn specifies the
|
||||
card number in hex.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/utils.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 2 ++
|
||||
2 files changed, 54 insertions(+)
|
||||
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -22,6 +22,11 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
+#define pr_verbose(verbose, fmt...) do { \
|
||||
+ if (verbose) \
|
||||
+ warnx(fmt); \
|
||||
+ } while (0)
|
||||
+
|
||||
/**
|
||||
* Checks if the specified card is of type CCA and is online
|
||||
*
|
||||
@@ -107,3 +112,50 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Gets the 8 character ASCII serial number string of an card from the sysfs.
|
||||
+ *
|
||||
+ * @param[in] card card number
|
||||
+ * @param[out] serialnr Result buffer
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 if the serial number was returned. -ENODEV if the APQN is not
|
||||
+ * available, or is not a CCA card. -ENOTSUP if the serialnr sysfs
|
||||
+ * attribute is not available, because the zcrypt kernel module is
|
||||
+ * on an older level.
|
||||
+ */
|
||||
+int sysfs_get_serialnr(int card, char serialnr[9], bool verbose)
|
||||
+{
|
||||
+ char *dev_path;
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ if (serialnr == NULL)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (sysfs_is_card_online(card) != 1)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
|
||||
+ if (!util_path_is_dir(dev_path)) {
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (util_file_read_line(serialnr, 9, "%s/serialnr", dev_path) != 0) {
|
||||
+ rc = -ENOTSUP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (strlen(serialnr) == 0) {
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "Serial number of %02x: %s", card, serialnr);
|
||||
+out:
|
||||
+ if (rc != 0)
|
||||
+ pr_verbose(verbose, "Failed to get serial number for "
|
||||
+ "%02x: %s", card, strerror(-rc));
|
||||
+
|
||||
+ free(dev_path);
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -18,4 +18,6 @@ int sysfs_is_card_online(int card);
|
||||
|
||||
int sysfs_is_apqn_online(int card, int domain);
|
||||
|
||||
+int sysfs_get_serialnr(int card, char serialnr[9], bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,119 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184174] zpcitctl: Exit on error in sysfs_report_error
|
||||
From: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
Description: zpcictl: Initiate recover after reset
|
||||
Symptom: If a PCI function is reset using zpcictl --reset, the function
|
||||
is in an error state.
|
||||
Problem: zpcictl --reset only issues a SCLP reset and leaves the PCI
|
||||
function in an error state.
|
||||
Solution: Initiate an OS level recovery by calling
|
||||
/sys/bus/devices/<dev>/recover after the SCLP reset.
|
||||
Reproduction: Call zpcictl --reset <dev>
|
||||
Under z/VM check the state of the function with 'vmcp q pcif'
|
||||
Upstream-ID: 304c3d8086bc2a9230c5404f9c9fec72de08d229
|
||||
Problem-ID: 184174
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zpcitctl: Exit on error in sysfs_report_error
|
||||
|
||||
This also makes sure that we don't try to write to the
|
||||
/sys/bus/pci/device/<dev>/recover attribute if reset failed.
|
||||
|
||||
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
|
||||
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
---
|
||||
zpcictl/zpcictl.c | 55 +++++++++++++++++++++++++++++++++++++-----------------
|
||||
1 file changed, 38 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/zpcictl/zpcictl.c
|
||||
+++ b/zpcictl/zpcictl.c
|
||||
@@ -97,6 +97,35 @@ static void fopen_err(char *path)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+static void fclose_err(char *path)
|
||||
+{
|
||||
+ if (errno == EIO || errno == EOPNOTSUPP)
|
||||
+ warnx("Unsupported operation: %s: %s", path, strerror(errno));
|
||||
+ else
|
||||
+ warnx("Could not close file: %s: %s", path, strerror(errno));
|
||||
+ free(path);
|
||||
+ exit(EXIT_FAILURE);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static void fread_err(FILE *fp, char *path)
|
||||
+{
|
||||
+ warnx("Could not read file: %s: %s", path, strerror(errno));
|
||||
+ if (fclose(fp))
|
||||
+ fclose_err(path);
|
||||
+ free(path);
|
||||
+ exit(EXIT_FAILURE);
|
||||
+}
|
||||
+
|
||||
+static void fwrite_err(FILE *fp, char *path)
|
||||
+{
|
||||
+ warnx("Could not write to file: %s: %s", path, strerror(errno));
|
||||
+ if (fclose(fp))
|
||||
+ fclose_err(path);
|
||||
+ free(path);
|
||||
+ exit(EXIT_FAILURE);
|
||||
+}
|
||||
+
|
||||
#define READ_CHUNK_SIZE 512
|
||||
|
||||
static char *collect_smart_data(struct zpci_device *pdev)
|
||||
@@ -152,12 +181,10 @@ static unsigned int sysfs_read_value(str
|
||||
if (!fp)
|
||||
fopen_err(path);
|
||||
if (fscanf(fp, "%x", &val) != 1) {
|
||||
- fclose(fp);
|
||||
- warnx("Could not read file %s: %s", path, strerror(errno));
|
||||
- free(path);
|
||||
- exit(EXIT_FAILURE);
|
||||
+ fread_err(fp, path);
|
||||
}
|
||||
- fclose(fp);
|
||||
+ if (fclose(fp))
|
||||
+ fclose_err(path);
|
||||
free(path);
|
||||
|
||||
return val;
|
||||
@@ -174,12 +201,10 @@ static void sysfs_write_value(struct zpc
|
||||
if (!fp)
|
||||
fopen_err(path);
|
||||
if (fprintf(fp, "%x", val) < 0) {
|
||||
- fclose(fp);
|
||||
- warnx("Could not write to file %s: %s", path, strerror(errno));
|
||||
- free(path);
|
||||
- exit(EXIT_FAILURE);
|
||||
+ fwrite_err(fp, path);
|
||||
}
|
||||
- fclose(fp);
|
||||
+ if (fclose(fp))
|
||||
+ fclose_err(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
@@ -196,13 +221,9 @@ static void sysfs_report_error(struct zp
|
||||
if (!fp)
|
||||
fopen_err(path);
|
||||
if (fwrite(report, 1, r_size, fp) != r_size)
|
||||
- warnx("Could not write to file: %s: %s", path, strerror(errno));
|
||||
- if (fclose(fp)) {
|
||||
- if (errno == EIO || errno == EOPNOTSUPP)
|
||||
- warnx("Unsupported operation: %s: %s", path, strerror(errno));
|
||||
- else
|
||||
- warnx("Could not close file: %s: %s", path, strerror(errno));
|
||||
- }
|
||||
+ fwrite_err(fp, path);
|
||||
+ if (fclose(fp))
|
||||
+ fclose_err(path);
|
||||
free(path);
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Fix entry point for stand-alone kdump
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: abe0ba7412f4398973235497754b05a199aec818
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Fix entry point for stand-alone kdump
|
||||
|
||||
Currently zipl doesn't differentiate between the load address and the
|
||||
entry point of an image, causing stage3 to strip away the entry point at
|
||||
0x10000 for stand-alone kdump. This breaks the kdump kernel as it jumps
|
||||
to 0x10000 after the special handling needed for kdump has been
|
||||
performed.
|
||||
|
||||
Fix this by differentiating between the load address and the entry point
|
||||
of an image.
|
||||
|
||||
Fixes: d142fbd5 ("zipl: Do not strip kernel image IPL header")
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/include/boot.h | 4 ++--
|
||||
zipl/src/boot.c | 10 +++++-----
|
||||
zipl/src/bootmap.c | 2 +-
|
||||
3 files changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/zipl/include/boot.h
|
||||
+++ b/zipl/include/boot.h
|
||||
@@ -310,8 +310,8 @@ int boot_init_fba_stage1b(struct boot_fb
|
||||
int boot_get_eckd_stage2(void** data, size_t* size, struct job_data* job);
|
||||
int boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
|
||||
address_t initrd_addr, size_t initrd_len,
|
||||
- address_t load_addr, int extra_parm, uint16_t flags,
|
||||
- size_t image_len);
|
||||
+ address_t entry, int extra_parm, uint16_t flags,
|
||||
+ address_t image_addr, size_t image_len);
|
||||
int boot_get_tape_ipl(void** data, size_t* size, address_t parm_addr,
|
||||
address_t initrd_addr, address_t image_addr);
|
||||
int boot_get_tape_dump(void** data, size_t* size, uint64_t mem);
|
||||
--- a/zipl/src/boot.c
|
||||
+++ b/zipl/src/boot.c
|
||||
@@ -79,14 +79,14 @@ boot_check_data(void)
|
||||
int
|
||||
boot_get_stage3_parms(void **buffer, size_t *bytecount, address_t parm_addr,
|
||||
address_t initrd_addr, size_t initrd_len,
|
||||
- address_t image_addr, int extra_parm, uint16_t flags,
|
||||
- size_t image_len)
|
||||
+ address_t entry, int extra_parm, uint16_t flags,
|
||||
+ address_t image_addr, size_t image_len)
|
||||
{
|
||||
struct boot_stage3_params params;
|
||||
void* data;
|
||||
|
||||
- if (image_addr != (image_addr & PSW_ADDRESS_MASK)) {
|
||||
- error_reason("Kernel image load address to high (31 bit "
|
||||
+ if (entry != (entry & PSW_ADDRESS_MASK)) {
|
||||
+ error_reason("Kernel image entry point to high (31 bit "
|
||||
"addressing mode)");
|
||||
return -1;
|
||||
}
|
||||
@@ -99,7 +99,7 @@ boot_get_stage3_parms(void **buffer, siz
|
||||
params.parm_addr = (uint64_t) parm_addr;
|
||||
params.initrd_addr = (uint64_t) initrd_addr;
|
||||
params.initrd_len = (uint64_t) initrd_len;
|
||||
- params.load_psw = (uint64_t)(image_addr | PSW_LOAD);
|
||||
+ params.load_psw = (uint64_t)(entry | PSW_LOAD);
|
||||
params.extra_parm = (uint64_t) extra_parm;
|
||||
params.flags = flags;
|
||||
params.image_len = (uint64_t) image_len;
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -646,7 +646,7 @@ add_ipl_program(int fd, struct job_ipl_d
|
||||
ipl->is_kdump ? ipl->image_addr + 0x10 :
|
||||
ipl->image_addr,
|
||||
(info->type == disk_type_scsi) ? 0 : 1,
|
||||
- flags, image_size);
|
||||
+ flags, ipl->image_addr, image_size);
|
||||
if (rc) {
|
||||
free(table);
|
||||
return rc;
|
@ -1,70 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184396] zipl: fix zipl.conf man page example for secure boot
|
||||
From: Stefan Haberland <sth@linux.ibm.com>
|
||||
|
||||
Description: zipl: fix secure boot config handling
|
||||
Symptom: The config file parsing for secure boot worked not as
|
||||
it was expected to be. For example a config section
|
||||
setting was not evaluated properly.
|
||||
It is not possible to specify command line option -S
|
||||
without other options.
|
||||
Additionally the man page showed an invalid example.
|
||||
Problem: The config file parsing was not implemented properly.
|
||||
Solution: The hierarchy of the secure boot settings in the config
|
||||
file is:
|
||||
defaultboot > menu > section
|
||||
Allow that --secure or -S is specified on command line
|
||||
without the need to allow all options on the command
|
||||
line. Also ensure that the command line option
|
||||
overrules the config option and correctly ensure that
|
||||
secure boot is only set for SCSI devices.
|
||||
Fix man page example.
|
||||
Reproduction: Run zipl with a secure= setting in a configuration
|
||||
section or specify -S on command line.
|
||||
Upstream-ID: 299fd2b7729f35c6fe3be18964f7e5e6a365f94d
|
||||
Problem-ID: 184396
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: fix zipl.conf man page example for secure boot
|
||||
|
||||
The secure= option is not supported in the defaultboot section when a
|
||||
menu is used. It should be placed in the menu section in this case.
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
---
|
||||
zipl/man/zipl.conf.5 | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/zipl/man/zipl.conf.5
|
||||
+++ b/zipl/man/zipl.conf.5
|
||||
@@ -82,8 +82,6 @@ below).
|
||||
.br
|
||||
defaultmenu = menu1
|
||||
.br
|
||||
-secure = auto
|
||||
-.br
|
||||
|
||||
[linux]
|
||||
.br
|
||||
@@ -117,6 +115,8 @@ prompt = 1
|
||||
.br
|
||||
timeout = 0
|
||||
.br
|
||||
+secure = auto
|
||||
+.br
|
||||
.PP
|
||||
|
||||
.B BootLoaderSpec configuration files
|
||||
@@ -522,7 +522,7 @@ non-default memory location.
|
||||
.B secure
|
||||
=
|
||||
.IR auto / 1 / 0
|
||||
-(configuration only)
|
||||
+(configuration and menu)
|
||||
.IP
|
||||
.B Configuration section:
|
||||
.br
|
@ -1,82 +0,0 @@
|
||||
Subject: [PATCH] [BZ 184060] zipl/libc: Indicate truncated lines in printf with '...'
|
||||
From: Philipp Rudo <prudo@linux.ibm.com>
|
||||
|
||||
Description: zipl/libc: Fix potential buffer overflow in printf
|
||||
Symptom: Crash of the zipl boot loader during boot.
|
||||
Problem: The zipl boot loaders have their own minimalistic libc
|
||||
implementation. In it printf and sprintf use vsprintf for string
|
||||
formatting. Per definition vsprintf assumes that the buffer it
|
||||
writes to is large enough to contain the formatted string and
|
||||
performs no size checks. This is problematic for the boot
|
||||
loaders because the buffer they use are often allocated on the
|
||||
stack. Thus even small changes to the string format can
|
||||
potentially cause buffer overflows on the stack.
|
||||
Solution: Implement vsnprintf and make use of it.
|
||||
Reproduction: Use printf to print a string with >81 characters (exact number
|
||||
depends on the stack layout/compiler used).
|
||||
Upstream-ID: 36fed0e6c6590631c4ce1707c8fe3c3397bcce4d
|
||||
Problem-ID: 184060
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: Indicate truncated lines in printf with '...'
|
||||
|
||||
Append '...' to lines exceeding the maximum line length instead of
|
||||
silently truncating them.
|
||||
|
||||
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 10 ++++++++--
|
||||
zipl/boot/libc.h | 1 +
|
||||
zipl/boot/menu.h | 1 -
|
||||
3 files changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -408,11 +408,17 @@ void snprintf(char *buf, unsigned long s
|
||||
*/
|
||||
void printf(const char *fmt, ...)
|
||||
{
|
||||
- char buf[81];
|
||||
+ char buf[LINE_LENGTH + 1];
|
||||
+ int len;
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
- vsnprintf(buf, sizeof(buf), fmt, va);
|
||||
+ len = vsnprintf(buf, sizeof(buf), fmt, va);
|
||||
+ if (len > LINE_LENGTH) {
|
||||
+ buf[LINE_LENGTH - 1] = '.';
|
||||
+ buf[LINE_LENGTH - 2] = '.';
|
||||
+ buf[LINE_LENGTH - 3] = '.';
|
||||
+ }
|
||||
sclp_print(buf);
|
||||
va_end(va);
|
||||
}
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -40,6 +40,7 @@
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
|
||||
#define MIB (1024ULL * 1024)
|
||||
+#define LINE_LENGTH 80 /* max line length printed by printf */
|
||||
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
--- a/zipl/boot/menu.h
|
||||
+++ b/zipl/boot/menu.h
|
||||
@@ -20,7 +20,6 @@
|
||||
/* max command line length */
|
||||
#define COMMAND_LINE_SIZE 896
|
||||
#define BOOT_MENU_ENTRIES 63
|
||||
-#define LINE_LENGTH 80
|
||||
#define PARAM_SIZE 8
|
||||
#define TEXT_OFFSET 4
|
||||
|
@ -1,213 +0,0 @@
|
||||
Subject: zkey: Add utility function to get the mkvp of a crypto card
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: bf8872e94a2dc4810df388d1539560b00b1acf6e
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add utility function to get the mkvp of a crypto card
|
||||
|
||||
With recent changes in the zcrypt device driver, the master key verifi-
|
||||
cation patterns of the AES master key of am APQN can be obtained by
|
||||
reading the sysfs attribute 'mkvps' of an APQN device of type CCA-
|
||||
Coprocessor. The sysfs attribute can be found under
|
||||
'/sys/devices/ap/cardnn/nn.mmmm/', where nn specifies the card number
|
||||
in hex, and mmmm specifies the domain number on hex.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/utils.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 21 ++++++++
|
||||
2 files changed, 161 insertions(+)
|
||||
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -159,3 +159,143 @@ out:
|
||||
free(dev_path);
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+static int parse_mk_info(char *line, struct mk_info *mk_info)
|
||||
+{
|
||||
+ struct mk_info_reg *mk_reg;
|
||||
+ char *save;
|
||||
+ char *tok;
|
||||
+
|
||||
+ tok = strtok_r(line, " ", &save);
|
||||
+ if (tok == NULL)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ if (strcasecmp(tok, "AES") != 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ tok = strtok_r(NULL, " ", &save);
|
||||
+ if (tok == NULL)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ if (strcasecmp(tok, "NEW:") == 0)
|
||||
+ mk_reg = &mk_info->new_mk;
|
||||
+ else if (strcasecmp(tok, "CUR:") == 0)
|
||||
+ mk_reg = &mk_info->cur_mk;
|
||||
+ else if (strcasecmp(tok, "OLD:") == 0)
|
||||
+ mk_reg = &mk_info->old_mk;
|
||||
+ else
|
||||
+ return -EIO;
|
||||
+
|
||||
+ tok = strtok_r(NULL, " ", &save);
|
||||
+ if (tok == NULL)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ if (strcasecmp(tok, "empty") == 0)
|
||||
+ mk_reg->mk_state = MK_STATE_EMPTY;
|
||||
+ else if (strcasecmp(tok, "partial") == 0)
|
||||
+ mk_reg->mk_state = MK_STATE_PARTIAL;
|
||||
+ else if (strcasecmp(tok, "full") == 0)
|
||||
+ mk_reg->mk_state = MK_STATE_FULL;
|
||||
+ else if (strcasecmp(tok, "valid") == 0)
|
||||
+ mk_reg->mk_state = MK_STATE_VALID;
|
||||
+ else if (strcasecmp(tok, "invalid") == 0)
|
||||
+ mk_reg->mk_state = MK_STATE_INVALID;
|
||||
+ else
|
||||
+ mk_reg->mk_state = MK_STATE_UNKNOWN;
|
||||
+
|
||||
+ tok = strtok_r(NULL, " ", &save);
|
||||
+ if (tok == NULL)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ if (sscanf(tok, "%llx", &mk_reg->mkvp) != 1)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Gets the master key states and verification patterns of an APQN from the
|
||||
+ * sysfs.
|
||||
+ *
|
||||
+ * @param[in] card card number
|
||||
+ * @param[in] domain the domain
|
||||
+ * @param[out] mk_info structure is filled on return with master key infos
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 if the master key info was returned. -ENODEV if the APQN is not
|
||||
+ * available, or is not a CCA card. -ENOTSUP if the mkvps sysfs
|
||||
+ * attribute is not available, because the zcrypt kernel module is
|
||||
+ * on an older level.
|
||||
+ */
|
||||
+int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info, bool verbose)
|
||||
+{
|
||||
+ char *dev_path;
|
||||
+ char *p, *end;
|
||||
+ char buf[100];
|
||||
+ int rc = 0;
|
||||
+ FILE *fp;
|
||||
+
|
||||
+ if (mk_info == NULL)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memset(mk_info, 0, sizeof(struct mk_info));
|
||||
+ mk_info->new_mk.mk_state = MK_STATE_UNKNOWN;
|
||||
+ mk_info->cur_mk.mk_state = MK_STATE_UNKNOWN;
|
||||
+ mk_info->old_mk.mk_state = MK_STATE_UNKNOWN;
|
||||
+
|
||||
+ if (sysfs_is_apqn_online(card, domain) != 1)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ dev_path = util_path_sysfs("bus/ap/devices/card%02x/%02x.%04x/mkvps",
|
||||
+ card, card, domain);
|
||||
+ if (!util_path_is_reg_file(dev_path)) {
|
||||
+ rc = -ENOTSUP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ fp = fopen(dev_path, "r");
|
||||
+ if (fp == NULL) {
|
||||
+ rc = -ENOTSUP;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Expected contents:
|
||||
+ * AES NEW: <new_mk_state> <new_mk_mkvp>
|
||||
+ * AES CUR: <cur_mk_state> <cur_mk_mkvp>
|
||||
+ * AES OLD: <old_mk_state> <old_mk_mkvp>
|
||||
+ * with
|
||||
+ * <new_mk_state>: 'empty' or 'partial' or 'full'
|
||||
+ * <cur_mk_state>, <old_mk_state>: 'valid' or 'invalid'
|
||||
+ * <new_mk_mkvp>, <cur_mk_mkvp>, <old_mk_mkvp:
|
||||
+ * 8 byte hex string with leading 0x
|
||||
+ */
|
||||
+ while ((p = fgets(buf, sizeof(buf), fp)) != NULL) {
|
||||
+ end = memchr(buf, '\n', sizeof(buf));
|
||||
+ if (end)
|
||||
+ *end = 0;
|
||||
+ else
|
||||
+ buf[sizeof(buf) - 1] = 0;
|
||||
+
|
||||
+ pr_verbose(verbose, "mkvp for %02x.%04x: %s", card, domain,
|
||||
+ buf);
|
||||
+
|
||||
+ rc = parse_mk_info(buf, mk_info);
|
||||
+ if (rc != 0)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ fclose(fp);
|
||||
+
|
||||
+ if (mk_info->new_mk.mk_state == MK_STATE_UNKNOWN &&
|
||||
+ mk_info->cur_mk.mk_state == MK_STATE_UNKNOWN &&
|
||||
+ mk_info->old_mk.mk_state == MK_STATE_UNKNOWN)
|
||||
+ rc = -EIO;
|
||||
+out:
|
||||
+ if (rc != 0)
|
||||
+ pr_verbose(verbose, "Failed to get mkvps for %02x.%04x: %s",
|
||||
+ card, domain, strerror(-rc));
|
||||
+
|
||||
+ free(dev_path);
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -20,4 +20,25 @@ int sysfs_is_apqn_online(int card, int d
|
||||
|
||||
int sysfs_get_serialnr(int card, char serialnr[9], bool verbose);
|
||||
|
||||
+#define MK_STATE_EMPTY 0
|
||||
+#define MK_STATE_PARTIAL 1
|
||||
+#define MK_STATE_FULL 2
|
||||
+#define MK_STATE_VALID 3
|
||||
+#define MK_STATE_INVALID 4
|
||||
+#define MK_STATE_UNKNOWN -1
|
||||
+
|
||||
+struct mk_info_reg {
|
||||
+ int mk_state;
|
||||
+ u64 mkvp;
|
||||
+};
|
||||
+
|
||||
+struct mk_info {
|
||||
+ struct mk_info_reg new_mk;
|
||||
+ struct mk_info_reg cur_mk;
|
||||
+ struct mk_info_reg old_mk;
|
||||
+};
|
||||
+
|
||||
+int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info,
|
||||
+ bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,76 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Fix dependency generation in zipl/boot
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 121d5d80137f270e4828f457f717e9ab365f303b
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Fix dependency generation in zipl/boot
|
||||
|
||||
When adding new header from zipl/include to a .c file within zipl/boot
|
||||
a compiler error appears
|
||||
|
||||
stage3.c:16:10: fatal error: zipl.h: No such file or directory
|
||||
#include "zipl.h"
|
||||
^~~~~~~~
|
||||
compilation terminated.
|
||||
CC zipl/boot/stage3.o
|
||||
|
||||
This is because the rule to generate dependencies (*.o.d) does not use
|
||||
the CFLAGS_BOOT. Thus it cannot find the header and fails. Note this
|
||||
only applies to the dependency generation, the actual build succeeds.
|
||||
|
||||
To fix this rename the CFLAGS_BOOT to ALL_CFLAGS. Using ALL_CFLAGS
|
||||
instead of e.g. ALL_CPPFLAGS is important to also overwrite flags given
|
||||
on the commandline via OPT_FLAGS, e.g.
|
||||
|
||||
make V=1 OPT_FLAGS="-D__FOO__"
|
||||
|
||||
While at it also remove the unused and wrong '-D__ASSEMBLY__'.
|
||||
|
||||
Fixes: 5a6605fe ("zipl: Ensure that boot loader CFLAGS are not overwritten")
|
||||
Fixes: aa913b1e ("build process: Add automatic dependency generation")
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/Makefile | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/zipl/boot/Makefile
|
||||
+++ b/zipl/boot/Makefile
|
||||
@@ -1,7 +1,7 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
-CFLAGS_BOOT = $(NO_PIE_CFLAGS) -Os -g -I../include -D__ASSEMBLY__ \
|
||||
+ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g -I $(rootdir)/zipl/include \
|
||||
-DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||
-fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
|
||||
-fno-delete-null-pointer-checks \
|
||||
@@ -21,10 +21,10 @@ all: data.o data.h tape0.bin stage3.bin
|
||||
%: %.S
|
||||
|
||||
%.o: %.S
|
||||
- $(CC) $(CFLAGS_BOOT) -c -o $@ $<
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
- $(CC) $(CFLAGS_BOOT) -c -o $@ $<
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
eckd2dump_sv.exec: \
|
||||
head.o stage2dump.o cio.o eckd2dump.o eckd2dump_sv.o \
|
@ -1,197 +0,0 @@
|
||||
Subject: zkey: add function to iterate over all available CCA APQNs
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 625b81130ab2c9d184aaede2749f1fd776f51062
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: add function to iterate over all available CCA APQNs
|
||||
|
||||
Add a utility function to iterate over all available APQNs of
|
||||
type CCA-Coprocessor. This function is required for various
|
||||
future enhancements.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/utils.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 5 ++
|
||||
2 files changed, 132 insertions(+)
|
||||
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -7,6 +7,7 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
@@ -19,8 +20,13 @@
|
||||
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_file.h"
|
||||
+#include "lib/util_scandir.h"
|
||||
+#include "lib/util_libc.h"
|
||||
+#include "lib/util_rec.h"
|
||||
+#include "lib/util_base.h"
|
||||
|
||||
#include "utils.h"
|
||||
+#include "properties.h"
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
if (verbose) \
|
||||
@@ -299,3 +305,124 @@ out:
|
||||
free(dev_path);
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+static int scan_for_domains(int card, apqn_handler_t handler,
|
||||
+ void *handler_data, bool verbose)
|
||||
+{
|
||||
+ struct dirent **namelist;
|
||||
+ char fname[290];
|
||||
+ int i, n, domain, rc = 0;
|
||||
+
|
||||
+ sprintf(fname, "/sys/devices/ap/card%02x/", card);
|
||||
+ n = util_scandir(&namelist, alphasort, fname,
|
||||
+ "[0-9a-fA-F]+\\.[0-9a-fA-F]+");
|
||||
+
|
||||
+ if (n < 0)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ for (i = 0; i < n; i++) {
|
||||
+ if (sscanf(namelist[i]->d_name, "%x.%x", &card, &domain) != 2)
|
||||
+ continue;
|
||||
+
|
||||
+ pr_verbose(verbose, "Found %02x.%04x", card, domain);
|
||||
+
|
||||
+ if (sysfs_is_apqn_online(card, domain) != 1) {
|
||||
+ pr_verbose(verbose, "APQN %02x.%04x is offline or not "
|
||||
+ "CCA", card, domain);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ rc = handler(card, domain, handler_data);
|
||||
+ if (rc != 0)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ util_scandir_free(namelist, n);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int scan_for_apqns(apqn_handler_t handler, void *handler_data,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ struct dirent **namelist;
|
||||
+ int i, n, card, rc = 0;
|
||||
+
|
||||
+ if (handler == NULL)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ n = util_scandir(&namelist, alphasort, "/sys/devices/ap/",
|
||||
+ "card[0-9a-fA-F]+");
|
||||
+ if (n < 0)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ for (i = 0; i < n; i++) {
|
||||
+ if (sscanf(namelist[i]->d_name, "card%x", &card) != 1)
|
||||
+ continue;
|
||||
+
|
||||
+ pr_verbose(verbose, "Found card %02x", card);
|
||||
+
|
||||
+ if (sysfs_is_card_online(card) != 1) {
|
||||
+ pr_verbose(verbose, "Card %02x is offline or not CCA",
|
||||
+ card);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ rc = scan_for_domains(card, handler, handler_data, verbose);
|
||||
+ if (rc != 0)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ util_scandir_free(namelist, n);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Calls the handler for all APQNs specified in the apqns parameter, or of this
|
||||
+ * is NULL, for all online CCA APQNs found in sysfs. In case sysfs is inspected,
|
||||
+ * the cards and domains are processed in alphabetical order.
|
||||
+ *
|
||||
+ * @param[in] apqns a comma separated list of APQNs. If NULL is specified,
|
||||
+ * or an empty string, then all online CCA APQNs are
|
||||
+ * handled.
|
||||
+ * @param[in] handler a handler function that is called for each APQN
|
||||
+ * @param[in] handler_data private data that is passed to the handler
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 for success or a negative errno in case of an error
|
||||
+ */
|
||||
+int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ int card, domain;
|
||||
+ char *copy, *tok;
|
||||
+ char *save;
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ if (apqns == NULL || (apqns != NULL && strlen(apqns) == 0)) {
|
||||
+ rc = scan_for_apqns(handler, handler_data, verbose);
|
||||
+ } else {
|
||||
+ copy = util_strdup(apqns);
|
||||
+ tok = strtok_r(copy, ",", &save);
|
||||
+ while (tok != NULL) {
|
||||
+
|
||||
+ if (sscanf(tok, "%x.%x", &card, &domain) != 2) {
|
||||
+ warnx("the APQN '%s' is not valid",
|
||||
+ tok);
|
||||
+ rc = -EINVAL;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "Specified: %02x.%04x", card,
|
||||
+ domain);
|
||||
+ rc = handler(card, domain, handler_data);
|
||||
+ if (rc != 0)
|
||||
+ break;
|
||||
+
|
||||
+ tok = strtok_r(NULL, ",", &save);
|
||||
+ }
|
||||
+ free(copy);
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -41,4 +41,9 @@ struct mk_info {
|
||||
int sysfs_get_mkvps(int card, int domain, struct mk_info *mk_info,
|
||||
bool verbose);
|
||||
|
||||
+typedef int(*apqn_handler_t) (int card, int domain, void *handler_data);
|
||||
+
|
||||
+int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data,
|
||||
+ bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,349 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Make use of __packed macro
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 0f7ed7d4fc86041a8646ce7abb615849e1298cca
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Make use of __packed macro
|
||||
|
||||
Make use of the pre-defined __packed macro throughout zipl. This
|
||||
requires adding the global include dir to ALL_CFLAGS.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/Makefile | 2 -
|
||||
zipl/boot/s390.h | 2 -
|
||||
zipl/include/boot.h | 52 +++++++++++++++++++++++++------------------------
|
||||
zipl/include/bootmap.h | 4 ++-
|
||||
zipl/src/bootmap.c | 5 ++--
|
||||
zipl/src/install.c | 3 +-
|
||||
6 files changed, 37 insertions(+), 31 deletions(-)
|
||||
|
||||
--- a/zipl/boot/Makefile
|
||||
+++ b/zipl/boot/Makefile
|
||||
@@ -2,7 +2,7 @@
|
||||
include ../../common.mak
|
||||
|
||||
ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g -I $(rootdir)/zipl/include \
|
||||
- -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||
+ -I $(rootdir)/include -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||
-fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
|
||||
-fno-delete-null-pointer-checks \
|
||||
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -11,7 +11,7 @@
|
||||
#ifndef S390_H
|
||||
#define S390_H
|
||||
|
||||
-#include "../../include/lib/zt_common.h"
|
||||
+#include "lib/zt_common.h"
|
||||
#include "libc.h"
|
||||
|
||||
#define __pa32(x) ((uint32_t)(unsigned long)(x))
|
||||
--- a/zipl/include/boot.h
|
||||
+++ b/zipl/include/boot.h
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "disk.h"
|
||||
#include "job.h"
|
||||
#include "zipl.h"
|
||||
@@ -51,7 +53,7 @@ struct scsi_dump_sb {
|
||||
uint64_t csum_offset;
|
||||
uint64_t csum_size;
|
||||
uint64_t csum;
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL; /* ZFCPDUMP */
|
||||
/* To avoid a csum entry of 0 a seed is used */
|
||||
@@ -63,7 +65,7 @@ struct scsi_dump_sb {
|
||||
struct scsi_dump_param {
|
||||
uint64_t block;
|
||||
uint64_t reserved;
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
/* ECKD dump parameter */
|
||||
|
||||
struct eckd_dump_param {
|
||||
@@ -73,14 +75,14 @@ struct eckd_dump_param {
|
||||
uint8_t num_heads;
|
||||
uint8_t bpt;
|
||||
char reserved[4];
|
||||
-} __attribute((packed, may_alias));
|
||||
+} __packed __may_alias;
|
||||
|
||||
/* FBA dump parameter */
|
||||
|
||||
struct fba_dump_param {
|
||||
uint64_t start_blk;
|
||||
uint64_t blockct;
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_info_bp_dump {
|
||||
union {
|
||||
@@ -89,7 +91,7 @@ struct boot_info_bp_dump {
|
||||
struct scsi_dump_param scsi;
|
||||
} param;
|
||||
uint8_t unused[16];
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
/*
|
||||
* Layout of block pointer for linear devices
|
||||
@@ -101,7 +103,7 @@ struct linear_blockptr {
|
||||
uint16_t size;
|
||||
uint16_t blockct;
|
||||
uint8_t reserved[4];
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
/*
|
||||
* Layout of block pointer for cylinder/head/sector devices
|
||||
@@ -115,7 +117,7 @@ struct eckd_blockptr {
|
||||
uint16_t size;
|
||||
uint8_t blockct;
|
||||
uint8_t reserved[8];
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_info_bp_ipl {
|
||||
union {
|
||||
@@ -123,7 +125,7 @@ struct boot_info_bp_ipl {
|
||||
struct linear_blockptr lin;
|
||||
} bm_ptr;
|
||||
uint8_t unused[16];
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_info {
|
||||
char magic[4];
|
||||
@@ -135,7 +137,7 @@ struct boot_info {
|
||||
struct boot_info_bp_dump dump;
|
||||
struct boot_info_bp_ipl ipl;
|
||||
} bp;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_ccw0 {
|
||||
uint8_t cmd;
|
||||
@@ -144,21 +146,21 @@ struct boot_ccw0 {
|
||||
uint8_t flags;
|
||||
uint8_t pad;
|
||||
uint16_t count;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
/* Boot data structures for FBA disks */
|
||||
|
||||
struct boot_fba_locread {
|
||||
struct boot_ccw0 locate;
|
||||
struct boot_ccw0 read;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_fba_locdata {
|
||||
uint8_t command;
|
||||
uint8_t dummy;
|
||||
uint16_t blockct;
|
||||
uint32_t blocknr;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_fba_stage0 {
|
||||
uint64_t psw;
|
||||
@@ -169,13 +171,13 @@ struct boot_fba_stage0 {
|
||||
struct boot_fba_locdata locdata[2];
|
||||
uint64_t reserved[4];
|
||||
struct boot_info boot_info;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_fba_stage1b {
|
||||
struct boot_fba_locread locread[STAGE2_BLK_CNT_MAX];
|
||||
struct boot_fba_locdata locdata[STAGE2_BLK_CNT_MAX];
|
||||
uint8_t unused[448];
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
/* Boot data structures for ECKD disks */
|
||||
|
||||
@@ -184,14 +186,14 @@ struct boot_eckd_ccw1 {
|
||||
uint8_t flags;
|
||||
uint16_t count;
|
||||
uint32_t address;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_ssrt {
|
||||
struct boot_ccw0 seek;
|
||||
struct boot_ccw0 search;
|
||||
struct boot_ccw0 tic;
|
||||
struct boot_ccw0 read;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_seekarg {
|
||||
uint16_t pad;
|
||||
@@ -199,32 +201,32 @@ struct boot_eckd_seekarg {
|
||||
uint16_t head;
|
||||
uint8_t sec;
|
||||
uint8_t pad2;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_cdl_stage0 {
|
||||
uint64_t psw;
|
||||
struct boot_ccw0 read;
|
||||
struct boot_ccw0 tic;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_ldl_stage0 {
|
||||
uint64_t psw;
|
||||
struct boot_ccw0 read_r0;
|
||||
struct boot_ccw0 read_r1;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_stage1 {
|
||||
struct boot_eckd_ssrt ssrt[2];
|
||||
struct boot_ccw0 tic1b;
|
||||
struct boot_eckd_seekarg seek[2];
|
||||
struct boot_info boot_info;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct boot_eckd_stage1b {
|
||||
struct boot_eckd_ssrt ssrt[STAGE2_BLK_CNT_MAX];
|
||||
struct boot_eckd_seekarg seek[STAGE2_BLK_CNT_MAX];
|
||||
uint8_t unused[64];
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
/* Stage 2 boot menu parameter structure */
|
||||
|
||||
@@ -236,7 +238,7 @@ struct boot_stage2_params {
|
||||
uint16_t banner;
|
||||
uint16_t config[BOOT_MENU_ENTRIES + 1];
|
||||
uint64_t config_kdump;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
|
||||
/* Stage 3 bootloader parameter structure */
|
||||
@@ -251,7 +253,7 @@ struct boot_stage3_params {
|
||||
uint16_t reserved[3];
|
||||
uint64_t image_len;
|
||||
uint64_t image_addr;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
#define STAGE3_FLAG_SCSI 0x0001
|
||||
#define STAGE3_FLAG_KDUMP 0x0002
|
||||
@@ -275,7 +277,7 @@ struct mvdump_param {
|
||||
uint8_t blocksize;
|
||||
uint8_t bpt;
|
||||
uint8_t num_heads;
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
struct mvdump_parm_table {
|
||||
uint64_t timestamp;
|
||||
@@ -284,7 +286,7 @@ struct mvdump_parm_table {
|
||||
uint8_t ssid[MAX_DUMP_VOLUMES];
|
||||
unsigned char reserved[512 - sizeof(uint64_t) - sizeof(uint16_t) -
|
||||
(MAX_DUMP_VOLUMES * (sizeof(struct mvdump_param) + 1))];
|
||||
-} __attribute__ ((packed));
|
||||
+} __packed;
|
||||
|
||||
void boot_get_dump_info(struct boot_info *boot_info, uint8_t dev_type,
|
||||
void *param);
|
||||
--- a/zipl/include/bootmap.h
|
||||
+++ b/zipl/include/bootmap.h
|
||||
@@ -12,6 +12,8 @@
|
||||
#ifndef BOOTMAP_H
|
||||
#define BOOTMAP_H
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "disk.h"
|
||||
#include "job.h"
|
||||
#include "zipl.h"
|
||||
@@ -23,7 +25,7 @@ struct signature_header {
|
||||
uint8_t format;
|
||||
uint8_t reserved[3];
|
||||
uint32_t length;
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
typedef union {
|
||||
uint64_t load_address;
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "lib/util_part.h"
|
||||
#include "lib/util_path.h"
|
||||
|
||||
@@ -223,7 +224,7 @@ struct component_entry {
|
||||
uint8_t data[23];
|
||||
uint8_t type;
|
||||
component_data compdat;
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
typedef enum {
|
||||
component_execute = 0x01,
|
||||
@@ -263,7 +264,7 @@ struct component_header {
|
||||
uint8_t magic[4];
|
||||
uint8_t type;
|
||||
uint8_t reserved[27];
|
||||
-} __attribute((packed));
|
||||
+} __packed;
|
||||
|
||||
typedef enum {
|
||||
component_header_ipl = 0x00,
|
||||
--- a/zipl/src/install.c
|
||||
+++ b/zipl/src/install.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "lib/util_sys.h"
|
||||
|
||||
#include "boot.h"
|
||||
@@ -89,7 +90,7 @@ update_scsi_mbr(void* bootblock, disk_bl
|
||||
uint8_t program_table_pointer[16];
|
||||
uint8_t reserved2[0x50];
|
||||
struct boot_info boot_info;
|
||||
- } __attribute__ ((packed))* mbr;
|
||||
+ } __packed* mbr;
|
||||
struct scsi_dump_param param;
|
||||
void* buffer;
|
||||
|
@ -1,131 +0,0 @@
|
||||
Subject: zkey: Add function to print the MKVPs of APQNs
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: bfc3dd018c4f0cc17f8463d8bd6be16aab8de4a4
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add function to print the MKVPs of APQNs
|
||||
|
||||
Add a utility function to print the master key verification patterns
|
||||
of a set of APQNs. This allows the user to visually check which
|
||||
master keys are set on which APQNs.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/utils.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 2 +
|
||||
2 files changed, 82 insertions(+)
|
||||
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -426,3 +426,83 @@ int handle_apqns(const char *apqns, apqn
|
||||
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+struct print_apqn_info {
|
||||
+ struct util_rec *rec;
|
||||
+ bool verbose;
|
||||
+};
|
||||
+
|
||||
+static int print_apqn_mk_info(int card, int domain, void *handler_data)
|
||||
+{
|
||||
+ struct print_apqn_info *info = (struct print_apqn_info *)handler_data;
|
||||
+ struct mk_info mk_info;
|
||||
+ int rc;
|
||||
+
|
||||
+ rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
|
||||
+ if (rc == -ENOTSUP)
|
||||
+ return rc;
|
||||
+
|
||||
+ util_rec_set(info->rec, "APQN", "%02x.%04x", card, domain);
|
||||
+
|
||||
+ if (rc == 0) {
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_FULL)
|
||||
+ util_rec_set(info->rec, "NEW", "%016llx",
|
||||
+ mk_info.new_mk.mkvp);
|
||||
+ else if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL)
|
||||
+ util_rec_set(info->rec, "NEW", "partially loaded");
|
||||
+ else
|
||||
+ util_rec_set(info->rec, "NEW", "-");
|
||||
+
|
||||
+ if (mk_info.cur_mk.mk_state == MK_STATE_VALID)
|
||||
+ util_rec_set(info->rec, "CUR", "%016llx",
|
||||
+ mk_info.cur_mk.mkvp);
|
||||
+ else
|
||||
+ util_rec_set(info->rec, "CUR", "-");
|
||||
+
|
||||
+ if (mk_info.old_mk.mk_state == MK_STATE_VALID)
|
||||
+ util_rec_set(info->rec, "OLD", "%016llx",
|
||||
+ mk_info.old_mk.mkvp);
|
||||
+ else
|
||||
+ util_rec_set(info->rec, "OLD", "-");
|
||||
+ } else {
|
||||
+ util_rec_set(info->rec, "NEW", "?");
|
||||
+ util_rec_set(info->rec, "CUR", "?");
|
||||
+ util_rec_set(info->rec, "OLD", "?");
|
||||
+ }
|
||||
+
|
||||
+ util_rec_print(info->rec);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Prints master key information for all specified APQNs
|
||||
+ *
|
||||
+ * @param[in] apqns a comma separated list of APQNs. If NULL is specified,
|
||||
+ * or an empty string, then all online CCA APQNs are
|
||||
+ * printed.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 for success or a negative errno in case of an error. -ENOTSUP is
|
||||
+ * returned when the mkvps sysfs attribute is not available, because
|
||||
+ * the zcrypt kernel module is on an older level.
|
||||
+ */
|
||||
+int print_mk_info(const char *apqns, bool verbose)
|
||||
+{
|
||||
+ struct print_apqn_info info;
|
||||
+ int rc;
|
||||
+
|
||||
+ info.verbose = verbose;
|
||||
+ info.rec = util_rec_new_wide("-");
|
||||
+
|
||||
+ util_rec_def(info.rec, "APQN", UTIL_REC_ALIGN_LEFT, 11, "CARD.DOMAIN");
|
||||
+ util_rec_def(info.rec, "NEW", UTIL_REC_ALIGN_LEFT, 16, "NEW MK");
|
||||
+ util_rec_def(info.rec, "CUR", UTIL_REC_ALIGN_LEFT, 16, "CURRENT MK");
|
||||
+ util_rec_def(info.rec, "OLD", UTIL_REC_ALIGN_LEFT, 16, "OLD MK");
|
||||
+ util_rec_print_hdr(info.rec);
|
||||
+
|
||||
+ rc = handle_apqns(apqns, print_apqn_mk_info, &info, verbose);
|
||||
+
|
||||
+ util_rec_free(info.rec);
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -46,4 +46,6 @@ typedef int(*apqn_handler_t) (int card,
|
||||
int handle_apqns(const char *apqns, apqn_handler_t handler, void *handler_data,
|
||||
bool verbose);
|
||||
|
||||
+int print_mk_info(const char *apqns, bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,188 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: define __section macro and make use of it
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 154734efc7ffeb1e51dd2be62561a364fdc6117c
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: define __section macro and make use of it
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/zt_common.h | 1 +
|
||||
zipl/boot/eckd2dump_mv.c | 8 ++++----
|
||||
zipl/boot/eckd2dump_sv.c | 5 +++--
|
||||
zipl/boot/fba2dump.c | 4 ++--
|
||||
zipl/boot/stage2.c | 4 +++-
|
||||
zipl/boot/stage2dump.c | 5 +++--
|
||||
zipl/boot/stage2dump.h | 3 +--
|
||||
zipl/boot/tape2dump.c | 4 +++-
|
||||
8 files changed, 20 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -31,6 +31,7 @@
|
||||
#define __packed __attribute__((packed))
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
#define __may_alias __attribute__((may_alias))
|
||||
+#define __section(x) __attribute__((__section__(#x)))
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
--- a/zipl/boot/eckd2dump_mv.c
|
||||
+++ b/zipl/boot/eckd2dump_mv.c
|
||||
@@ -9,6 +9,8 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "eckd2dump.h"
|
||||
#include "error.h"
|
||||
#include "stage2dump.h"
|
||||
@@ -19,8 +21,7 @@
|
||||
/*
|
||||
* Magic number at start of dump record
|
||||
*/
|
||||
-uint64_t magic __attribute__((section(".stage2.head")))
|
||||
- = 0x584d554c54363401ULL; /* XMULT64, version 1 */
|
||||
+uint64_t __section(.stage2.head) magic = 0x584d554c54363401ULL; /* XMULT64, version 1 */
|
||||
|
||||
/*
|
||||
* Parameter format for ECKD MV dumper (13 bytes):
|
||||
@@ -59,8 +60,7 @@ struct mvdump_parm_table {
|
||||
(MAX_DUMP_VOLUMES * (sizeof(struct mvdump_param) + 1))];
|
||||
} __packed;
|
||||
|
||||
-static struct mvdump_parm_table mvdump_table
|
||||
- __attribute__((section(".eckd2dump_mv.tail")));
|
||||
+static struct mvdump_parm_table __section(.eckd2dump_mv.tail) mvdump_table;
|
||||
|
||||
static int volnr_current;
|
||||
|
||||
--- a/zipl/boot/eckd2dump_sv.c
|
||||
+++ b/zipl/boot/eckd2dump_sv.c
|
||||
@@ -9,6 +9,8 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "eckd2dump.h"
|
||||
#include "error.h"
|
||||
#include "stage2dump.h"
|
||||
@@ -16,8 +18,7 @@
|
||||
/*
|
||||
* Magic number at start of dump record
|
||||
*/
|
||||
-uint64_t magic __attribute__((section(".stage2.head"))) =
|
||||
- 0x5845434b44363401ULL; /* "XECKD64", version 1 */
|
||||
+uint64_t __section(.stage2.head) magic = 0x5845434b44363401ULL; /* "XECKD64", version 1 */
|
||||
|
||||
/*
|
||||
* ECKD parameter block passed by zipl
|
||||
--- a/zipl/boot/fba2dump.c
|
||||
+++ b/zipl/boot/fba2dump.c
|
||||
@@ -9,6 +9,7 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "error.h"
|
||||
#include "fba.h"
|
||||
#include "stage2dump.h"
|
||||
@@ -20,8 +21,7 @@
|
||||
/*
|
||||
* Magic number at start of dump record
|
||||
*/
|
||||
-uint64_t magic __attribute__((section(".stage2.head")))
|
||||
- = 0x5844464241363401ULL; /* XDFBA64, version 1 */
|
||||
+uint64_t __section(.stage2.head) magic = 0x5844464241363401ULL; /* XDFBA64, version 1 */
|
||||
|
||||
/*
|
||||
* FBA dump device partition specification
|
||||
--- a/zipl/boot/stage2.c
|
||||
+++ b/zipl/boot/stage2.c
|
||||
@@ -9,6 +9,8 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "error.h"
|
||||
#include "libc.h"
|
||||
#include "menu.h"
|
||||
@@ -141,4 +143,4 @@ void panic_notify(unsigned long UNUSED(r
|
||||
{
|
||||
}
|
||||
|
||||
-uint64_t stage2_head __attribute__((section(".stage2.head")));
|
||||
+uint64_t __section(.stage2.head) stage2_head;
|
||||
--- a/zipl/boot/stage2dump.c
|
||||
+++ b/zipl/boot/stage2dump.c
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "error.h"
|
||||
#include "sclp.h"
|
||||
#include "stage2dump.h"
|
||||
@@ -34,8 +36,7 @@ struct ipib_info {
|
||||
/*
|
||||
* Tail parameters
|
||||
*/
|
||||
-struct stage2dump_parm_tail parm_tail
|
||||
- __attribute__ ((section(".stage2dump.tail"))) = {
|
||||
+struct stage2dump_parm_tail parm_tail = {
|
||||
.mem_upper_limit = 0xffffffffffffffffULL,
|
||||
};
|
||||
|
||||
--- a/zipl/boot/stage2dump.h
|
||||
+++ b/zipl/boot/stage2dump.h
|
||||
@@ -28,8 +28,7 @@ struct stage2dump_parm_tail {
|
||||
uint64_t mem_upper_limit;
|
||||
} __packed;
|
||||
|
||||
-extern struct stage2dump_parm_tail parm_tail
|
||||
- __attribute__ ((section(".stage2dump.tail")));
|
||||
+extern struct stage2dump_parm_tail __section(.stage2dump.tail) parm_tail;
|
||||
|
||||
/*
|
||||
* S390 dump format defines
|
||||
--- a/zipl/boot/tape2dump.c
|
||||
+++ b/zipl/boot/tape2dump.c
|
||||
@@ -9,6 +9,8 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "cio.h"
|
||||
#include "error.h"
|
||||
#include "libc.h"
|
||||
@@ -33,7 +35,7 @@ struct tape_head {
|
||||
uint64_t ccw2;
|
||||
} __packed;
|
||||
|
||||
-struct tape_head tape_head __attribute__((section(".stage2.head"))) = {
|
||||
+struct tape_head __section(.stage2.head) tape_head = {
|
||||
.psw = 0x0008000080002018ULL, /* Start code at 0x2018 */
|
||||
.ccw1 = 0x0700000060000001ULL, /* Rewind ccw */
|
||||
.ccw2 = 0x0200200020003000ULL, /* CCW to load dump tool to 0x2000 */
|
@ -1,271 +0,0 @@
|
||||
Subject: zkey: Add function to cross check APQNs for valid master keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: b32c0314746ddee69e59f892f105acd720d06452
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add function to cross check APQNs for valid master keys
|
||||
|
||||
Add a utility function to cross check the master keys of a set of
|
||||
APQNs. It checks for valid master keys in the CURRENT and OLD
|
||||
master key registers, as well as newly loaded master keys in the NEW
|
||||
register. It issues information and warning messages for various
|
||||
findings and also indicates improper master key setup to the caller.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/utils.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/utils.h | 3
|
||||
2 files changed, 220 insertions(+)
|
||||
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -506,3 +506,220 @@ int print_mk_info(const char *apqns, boo
|
||||
util_rec_free(info.rec);
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+struct cross_check_info {
|
||||
+ u64 mkvp;
|
||||
+ u64 new_mkvp;
|
||||
+ bool key_mkvp;
|
||||
+ u32 num_cur_match;
|
||||
+ u32 num_old_match;
|
||||
+ u32 num_new_match;
|
||||
+ bool mismatch;
|
||||
+ bool print_mks;
|
||||
+ int num_checked;
|
||||
+ bool verbose;
|
||||
+};
|
||||
+
|
||||
+static int cross_check_mk_info(int card, int domain, void *handler_data)
|
||||
+{
|
||||
+ struct cross_check_info *info = (struct cross_check_info *)handler_data;
|
||||
+ struct mk_info mk_info;
|
||||
+ char temp[200];
|
||||
+ int rc;
|
||||
+
|
||||
+ rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
|
||||
+ if (rc == -ENODEV) {
|
||||
+ info->print_mks = 1;
|
||||
+ printf("WARNING: APQN %02x.%04x: Not available or not of "
|
||||
+ "type CCA\n", card, domain);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ info->num_checked++;
|
||||
+
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
|
||||
+ "register is only partially loaded.", card, domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+
|
||||
+ if (info->new_mkvp == 0 &&
|
||||
+ mk_info.new_mk.mk_state == MK_STATE_FULL)
|
||||
+ info->new_mkvp = mk_info.new_mk.mkvp;
|
||||
+
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
|
||||
+ mk_info.new_mk.mkvp != info->new_mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "WARNING: APQN %02x.%04x: The NEW master key "
|
||||
+ "register contains a different master key than "
|
||||
+ "the NEW register of other APQNs.", card,
|
||||
+ domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+
|
||||
+ if (mk_info.cur_mk.mk_state != MK_STATE_VALID) {
|
||||
+ info->print_mks = 1;
|
||||
+ info->mismatch = 1;
|
||||
+ printf("WARNING: APQN %02x.%04x: No master key is set.\n", card,
|
||||
+ domain);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.old_mk.mkvp == mk_info.cur_mk.mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The OLD master key "
|
||||
+ "register contains the same master key as the CURRENT "
|
||||
+ "master key register.", card, domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
|
||||
+ mk_info.new_mk.mkvp == mk_info.cur_mk.mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
|
||||
+ "register contains the same master key as the CURRENT "
|
||||
+ "master key register.", card, domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
|
||||
+ mk_info.old_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.new_mk.mkvp == mk_info.old_mk.mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
|
||||
+ "register contains the same master key as the OLD "
|
||||
+ "master key register.", card, domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+
|
||||
+ if (info->mkvp == 0)
|
||||
+ info->mkvp = mk_info.cur_mk.mkvp;
|
||||
+
|
||||
+ if (info->key_mkvp) {
|
||||
+ if (mk_info.cur_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.cur_mk.mkvp == info->mkvp)
|
||||
+ info->num_cur_match++;
|
||||
+
|
||||
+ if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.old_mk.mkvp == info->mkvp)
|
||||
+ info->num_old_match++;
|
||||
+
|
||||
+ if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
|
||||
+ mk_info.new_mk.mkvp == info->mkvp)
|
||||
+ info->num_new_match++;
|
||||
+ }
|
||||
+
|
||||
+ if (mk_info.cur_mk.mkvp != info->mkvp) {
|
||||
+
|
||||
+ if (info->key_mkvp) {
|
||||
+ if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.old_mk.mkvp == info->mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The master"
|
||||
+ " key has been changed to a new "
|
||||
+ "master key, but the secure key has "
|
||||
+ "not yet been re-enciphered.", card,
|
||||
+ domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ } else if (mk_info.new_mk.mk_state == MK_STATE_FULL &&
|
||||
+ mk_info.new_mk.mkvp == info->mkvp) {
|
||||
+ info->print_mks = 1;
|
||||
+ sprintf(temp, "INFO: APQN %02x.%04x: The master"
|
||||
+ " key has been changed but is not "
|
||||
+ "yet been set (made active).", card,
|
||||
+ domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ } else {
|
||||
+ info->print_mks = 1;
|
||||
+ info->mismatch = 1;
|
||||
+ sprintf(temp, "WARNING: APQN %02x.%04x: The "
|
||||
+ "CURRENT master key register contains "
|
||||
+ "a master key that is different from "
|
||||
+ "the one used by the secure key.", card,
|
||||
+ domain);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+ } else {
|
||||
+ info->print_mks = 1;
|
||||
+ info->mismatch = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Cross checks the master key information for all specified APQNs. It checks
|
||||
+ * if all specified APQNs have the same current master key, and if it matches
|
||||
+ * the master key specified by the mkvp parameter (optional). If not, it prints
|
||||
+ * out an information message about the APQNs that have a different master key.
|
||||
+ *
|
||||
+ * @param[in] apqns a comma separated list of APQNs. If NULL is specified,
|
||||
+ * or an empty string, then all online CCA APQNs are
|
||||
+ * checked.
|
||||
+ * @param[in] mkvp The master key verification pattern of a secure key.
|
||||
+ * If this is all zero, then the master keys are not
|
||||
+ * matched against it.
|
||||
+ * @param[in] print_mks if true, then a the full master key info of all
|
||||
+ * specified APQns is printed, in case of a mismatch.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 for success or a negative errno in case of an error. -ENODEV is
|
||||
+ * returned if at least one APQN has a mismatching master key.
|
||||
+ * -ENOTSUP is returned when the mkvps sysfs attribute is not
|
||||
+ * available, because the zcrypt kernel module is on an older level.
|
||||
+ */
|
||||
+int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, bool verbose)
|
||||
+{
|
||||
+ struct cross_check_info info;
|
||||
+ char temp[200];
|
||||
+ int rc;
|
||||
+
|
||||
+ memset(&info, 0, sizeof(info));
|
||||
+ info.key_mkvp = mkvp != 0;
|
||||
+ info.mkvp = mkvp;
|
||||
+ info.verbose = verbose;
|
||||
+
|
||||
+ pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx: %s",
|
||||
+ mkvp, apqns != NULL ? apqns : "ANY");
|
||||
+
|
||||
+ rc = handle_apqns(apqns, cross_check_mk_info, &info, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ if (info.mismatch) {
|
||||
+ if (info.key_mkvp)
|
||||
+ printf("WARNING: Not all APQNs have the correct master "
|
||||
+ "key (%016llx).\n", mkvp);
|
||||
+ else
|
||||
+ printf("WARNING: Not all APQNs have the same master "
|
||||
+ "key.\n");
|
||||
+
|
||||
+ rc = -ENODEV;
|
||||
+ }
|
||||
+ if (info.num_checked == 0) {
|
||||
+ printf("WARNING: None of the APQNs is available or of "
|
||||
+ "type CCA\n");
|
||||
+ rc = -ENODEV;
|
||||
+ }
|
||||
+ if (info.num_old_match > 0 && info.num_new_match > 0) {
|
||||
+ sprintf(temp, "WARNING: On %u APQNs the OLD master key "
|
||||
+ "register contains the master key use by the secure "
|
||||
+ "key, and on %u APQNs the NEW master key register "
|
||||
+ "contains the master key use by the secure key.",
|
||||
+ info.num_old_match, info.num_new_match);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ info.print_mks = 1;
|
||||
+ rc = -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ if (print_mks && info.print_mks) {
|
||||
+ printf("\n");
|
||||
+ print_mk_info(apqns, verbose);
|
||||
+ printf("\n");
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -48,4 +48,7 @@ int handle_apqns(const char *apqns, apqn
|
||||
|
||||
int print_mk_info(const char *apqns, bool verbose);
|
||||
|
||||
+int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks,
|
||||
+ bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Make use of __noreturn macro
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 86856f98dbe3f68e34b91b58e9fc92f7cdc8a0d4
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Make use of __noreturn macro
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 4 +++-
|
||||
zipl/boot/libc.h | 2 +-
|
||||
2 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#include "error.h"
|
||||
#include "libc.h"
|
||||
#include "sclp.h"
|
||||
@@ -511,7 +513,7 @@ void initialize(void)
|
||||
/*
|
||||
* Load disabled wait PSW with reason code in address field
|
||||
*/
|
||||
-void libc_stop(unsigned long reason)
|
||||
+void __noreturn libc_stop(unsigned long reason)
|
||||
{
|
||||
struct psw_t psw;
|
||||
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -60,7 +60,7 @@ char *strcpy(char *, const char *);
|
||||
unsigned long get_zeroed_page(void);
|
||||
void free_page(unsigned long);
|
||||
void initialize(void);
|
||||
-void libc_stop(unsigned long) __attribute__((noreturn));
|
||||
+void libc_stop(unsigned long);
|
||||
void start(void);
|
||||
void pgm_check_handler(void);
|
||||
void pgm_check_handler_fn(void);
|
@ -1,74 +0,0 @@
|
||||
Subject: zkey: Add function to obtain the mkvp of a secure key
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: ea7cc9ea606dd879e4cdfae06a6f13d8fa3afff4
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add function to obtain the mkvp of a secure key
|
||||
|
||||
A secure AES key token contains the master key verification pattern
|
||||
of the master key it is encrypted with. Add a function to obtain the
|
||||
master key verification pattern of a secure key token.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/pkey.c | 21 +++++++++++++++++++++
|
||||
zkey/pkey.h | 4 ++++
|
||||
2 files changed, 25 insertions(+)
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -769,3 +769,24 @@ out:
|
||||
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+int get_master_key_verification_pattern(const u8 *secure_key,
|
||||
+ size_t secure_key_size, u64 *mkvp,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
|
||||
+
|
||||
+ util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
+ util_assert(mkvp != NULL, "Internal error: mkvp is NULL");
|
||||
+
|
||||
+ if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
+ pr_verbose(verbose, "Size of secure key is too small: "
|
||||
+ "%lu expected %lu", secure_key_size,
|
||||
+ SECURE_KEY_SIZE);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ *mkvp = token->mkvp;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -112,4 +112,8 @@ int validate_secure_key(int pkey_fd,
|
||||
int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
+int get_master_key_verification_pattern(const u8 *secure_key,
|
||||
+ size_t secure_key_size, u64 *mkvp,
|
||||
+ bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,66 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Define __noinline macro and make use of it
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 5eace91ee7bd76b8ab44291299ac313c87c9ecb8
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Define __noinline macro and make use of it
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/zt_common.h | 1 +
|
||||
libutil/util_panic_example.c | 2 +-
|
||||
zipl/boot/libc.c | 2 +-
|
||||
3 files changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -32,6 +32,7 @@
|
||||
#define __aligned(x) __attribute__((aligned(x)))
|
||||
#define __may_alias __attribute__((may_alias))
|
||||
#define __section(x) __attribute__((__section__(#x)))
|
||||
+#define __noinline __attribute__((__noinline__))
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
--- a/libutil/util_panic_example.c
|
||||
+++ b/libutil/util_panic_example.c
|
||||
@@ -15,10 +15,10 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "lib/util_panic.h"
|
||||
|
||||
/* Make functions noinline to have a nice backtrace */
|
||||
-#define __noinline __attribute__((noinline))
|
||||
|
||||
/*
|
||||
* Test util_panic()
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -473,7 +473,7 @@ void pgm_check_handler_fn(void)
|
||||
libc_stop(psw_old->addr);
|
||||
}
|
||||
|
||||
-__attribute__ ((noinline)) void load_wait_psw(uint64_t psw_mask, struct psw_t *psw)
|
||||
+void __noinline load_wait_psw(uint64_t psw_mask, struct psw_t *psw)
|
||||
{
|
||||
struct psw_t wait_psw = { .mask = psw_mask, .addr = 0 };
|
||||
struct psw_t old_psw, *wait_psw_ptr = &wait_psw;
|
@ -1,176 +0,0 @@
|
||||
Subject: zkey: Display MKVP when validating a secure key
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: c2244a57950f4eb35e3209151dcf48de66828df1
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Display MKVP when validating a secure key
|
||||
|
||||
Display the master key verification pattern of a secure key while
|
||||
'zkey validate' and 'zkey-cryptsetup validate'
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 20 ++++++++++++++------
|
||||
zkey/zkey-cryptsetup.c | 16 +++++++++++++---
|
||||
zkey/zkey.c | 14 ++++++++++++--
|
||||
3 files changed, 39 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -2107,7 +2107,7 @@ static void _keystore_print_record(struc
|
||||
bool validation, const char *skey_filename,
|
||||
size_t secure_key_size,
|
||||
size_t clear_key_bitsize, bool valid,
|
||||
- bool is_old_mk, bool reenc_pending)
|
||||
+ bool is_old_mk, bool reenc_pending, u64 mkvp)
|
||||
{
|
||||
char temp_vp[VERIFICATION_PATTERN_LEN + 2];
|
||||
char *volumes_argz = NULL;
|
||||
@@ -2169,10 +2169,11 @@ static void _keystore_print_record(struc
|
||||
if (validation) {
|
||||
if (valid)
|
||||
util_rec_set(rec, REC_MASTERKEY,
|
||||
- is_old_mk ? "OLD CCA master key" :
|
||||
- "CURRENT CCA master key");
|
||||
+ "%s CCA master key (MKVP: %016llx)",
|
||||
+ is_old_mk ? "OLD" : "CURRENT", mkvp);
|
||||
else
|
||||
- util_rec_set(rec, REC_MASTERKEY, "(unknown)");
|
||||
+ util_rec_set(rec, REC_MASTERKEY,
|
||||
+ "(unknown, MKVP: %016llx)", mkvp);
|
||||
}
|
||||
if (volumes_argz != NULL)
|
||||
util_rec_set_argz(rec, REC_VOLUMES, volumes_argz,
|
||||
@@ -2350,6 +2351,7 @@ static int _keystore_process_validate(st
|
||||
u8 *secure_key;
|
||||
int is_old_mk;
|
||||
int rc, valid;
|
||||
+ u64 mkvp;
|
||||
|
||||
rc = _keystore_ensure_keyfiles_exist(file_names, name);
|
||||
if (rc != 0)
|
||||
@@ -2373,12 +2375,18 @@ static int _keystore_process_validate(st
|
||||
info->num_valid++;
|
||||
valid = 1;
|
||||
}
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, keystore->verbose);
|
||||
free(secure_key);
|
||||
+ if (rc)
|
||||
+ goto out;
|
||||
|
||||
_keystore_print_record(info->rec, name, properties, 1,
|
||||
file_names->skey_filename, secure_key_size,
|
||||
clear_key_bitsize, valid, is_old_mk,
|
||||
- _keystore_reencipher_key_exists(file_names));
|
||||
+ _keystore_reencipher_key_exists(file_names),
|
||||
+ mkvp);
|
||||
|
||||
if (valid && is_old_mk) {
|
||||
util_print_indented("WARNING: The secure key is currently "
|
||||
@@ -3131,7 +3139,7 @@ static int _keystore_display_key(struct
|
||||
IS_XTS(secure_key_size) ? secure_key->bitsize * 2
|
||||
: secure_key->bitsize,
|
||||
0, 0,
|
||||
- _keystore_reencipher_key_exists(file_names));
|
||||
+ _keystore_reencipher_key_exists(file_names), 0);
|
||||
|
||||
out:
|
||||
free(secure_key);
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -1834,6 +1834,7 @@ static int command_validate(void)
|
||||
char *prompt;
|
||||
char *msg;
|
||||
int token;
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg);
|
||||
@@ -1864,6 +1865,14 @@ static int command_validate(void)
|
||||
vp_tok_avail = 1;
|
||||
}
|
||||
|
||||
+ rc = get_master_key_verification_pattern((u8 *)key, keysize,
|
||||
+ &mkvp, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
printf("Validation of secure volume key of device '%s':\n", g.pos_arg);
|
||||
printf(" Status: %s\n", is_valid ? "Valid" : "Invalid");
|
||||
printf(" Secure key size: %lu bytes\n", keysize);
|
||||
@@ -1871,11 +1880,12 @@ static int command_validate(void)
|
||||
keysize > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
if (is_valid) {
|
||||
printf(" Clear key size: %lu bits\n", clear_keysize);
|
||||
- printf(" Enciphered with: %s CCA master key\n",
|
||||
- is_old_mk ? "OLD" : "CURRENT");
|
||||
+ printf(" Enciphered with: %s CCA master key (MKVP: "
|
||||
+ "%016llx)\n", is_old_mk ? "OLD" : "CURRENT", mkvp);
|
||||
} else {
|
||||
printf(" Clear key size: (unknown)\n");
|
||||
- printf(" Enciphered with: (unknown)\n");
|
||||
+ printf(" Enciphered with: (unknown, MKVP: %016llx)\n",
|
||||
+ mkvp);
|
||||
}
|
||||
if (vp_tok_avail)
|
||||
print_verification_pattern(vp_tok.verification_pattern);
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1300,6 +1300,7 @@ static int command_validate_file(void)
|
||||
size_t clear_key_size;
|
||||
u8 *secure_key;
|
||||
int is_old_mk;
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
if (g.name != NULL) {
|
||||
@@ -1346,14 +1347,23 @@ static int command_validate_file(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
printf("Validation of secure key in file '%s':\n", g.pos_arg);
|
||||
printf(" Status: Valid\n");
|
||||
printf(" Secure key size: %lu bytes\n", secure_key_size);
|
||||
printf(" Clear key size: %lu bits\n", clear_key_size);
|
||||
printf(" XTS type key: %s\n",
|
||||
secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
- printf(" Enciphered with: %s CCA master key\n",
|
||||
- is_old_mk ? "OLD" : "CURRENT");
|
||||
+ printf(" Enciphered with: %s CCA master key (MKVP: %016llx)\n",
|
||||
+ is_old_mk ? "OLD" : "CURRENT", mkvp);
|
||||
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
||||
vp);
|
||||
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
@ -1,49 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/stage3: Mark start_kernel __noreturn
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: edfb6a03d862e332223eda02be46109be12c0a4e
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/stage3: Mark start_kernel __noreturn
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/stage3.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -175,8 +175,7 @@ static void ebcdic_to_ascii(unsigned cha
|
||||
target[i] = ebc[source[i]];
|
||||
}
|
||||
|
||||
-static void
|
||||
-start_kernel(void)
|
||||
+static inline void __noreturn start_kernel(void)
|
||||
{
|
||||
struct psw_t *psw = &S390_lowcore.program_new_psw;
|
||||
unsigned long addr, code;
|
||||
@@ -199,6 +198,7 @@ start_kernel(void)
|
||||
: [addr] "=&d" (addr),
|
||||
[code] "+&d" (code)
|
||||
: [psw] "a" (psw) );
|
||||
+ while (1);
|
||||
}
|
||||
|
||||
unsigned int
|
@ -1,91 +0,0 @@
|
||||
Subject: zkey: Cross check APQNs when generating secure keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: a5b58038a0dbf1c3eb202a6933265f0d2e57e130
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Cross check APQNs when generating secure keys
|
||||
|
||||
Perform a cross check of the APQNs when a new secure AES key is
|
||||
generated. When a set of APQNs are associated to a new secure key,
|
||||
these APQNs are cross checked. If a new secure key is generated
|
||||
outside of the key repository, or no APQNs are associated to a secure
|
||||
key generated inside the key repository, then all currently available
|
||||
APQNs are cross checked. If a master key mismatch is detected, then
|
||||
the key generation is rejected.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 8 ++++++++
|
||||
zkey/zkey.c | 11 +++++++++++
|
||||
2 files changed, 19 insertions(+)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1685,6 +1685,14 @@ int keystore_generate_key(struct keystor
|
||||
if (rc != 0)
|
||||
goto out_free_key_filenames;
|
||||
|
||||
+ rc = cross_check_apqns(apqns, 0, true, keystore->verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ goto out_free_key_filenames;
|
||||
+ if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ goto out_free_key_filenames;
|
||||
+ }
|
||||
+
|
||||
rc = _keystore_get_card_domain(apqns, &card, &domain);
|
||||
if (rc != 0)
|
||||
goto out_free_key_filenames;
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "keystore.h"
|
||||
#include "misc.h"
|
||||
#include "pkey.h"
|
||||
+#include "utils.h"
|
||||
|
||||
/*
|
||||
* Program configuration
|
||||
@@ -1060,6 +1061,8 @@ static int command_generate_repository(v
|
||||
*/
|
||||
static int command_generate(void)
|
||||
{
|
||||
+ int rc;
|
||||
+
|
||||
if (g.pos_arg != NULL && g.name != NULL) {
|
||||
warnx(" Option '--name|-N' is not valid for generating a key "
|
||||
"outside of the repository");
|
||||
@@ -1100,6 +1103,14 @@ static int command_generate(void)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
+ rc = cross_check_apqns(NULL, 0, true, g.verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ return EXIT_FAILURE;
|
||||
+ if (rc != 0 && rc != -ENOTSUP) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
return g.clearkeyfile ? command_generate_clear()
|
||||
: command_generate_random();
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/sclp: Remove duplicate macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: b2ae5a91ac16c5facb892dedc2dcb268eff07edf
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/sclp: Remove duplicate macros
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/sclp_stage3.h | 3 ---
|
||||
1 file changed, 3 deletions(-)
|
||||
|
||||
--- a/zipl/boot/sclp_stage3.h
|
||||
+++ b/zipl/boot/sclp_stage3.h
|
||||
@@ -17,9 +17,6 @@
|
||||
#define SDIAS_EVSTATE_ALL_STORED 0x00
|
||||
#define SDIAS_EVSTATE_PART_STORED 0x10
|
||||
|
||||
-#define SDIAS_EVSTATE_ALL_STORED 0x00
|
||||
-#define SDIAS_EVSTATE_PART_STORED 0x10
|
||||
-
|
||||
struct sdias_evbuf {
|
||||
struct evbuf_header header;
|
||||
uint8_t event_qual;
|
@ -1,123 +0,0 @@
|
||||
Subject: zkey: Cross check APQNs when validating secure keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 7f8e31e8619b32297b432a4882d78af79de37a58
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Cross check APQNs when validating secure keys
|
||||
|
||||
Perform a cross check of the APQNs when a secure AES key is validated.
|
||||
When a set of APQNs are associated to a secure key, these APQNs are
|
||||
cross checked. If a secure key is validated outside of the key repository,
|
||||
or no APQNs are associated to a secure key inside the key repository,
|
||||
then all currently available APQNs are cross checked. If a master key
|
||||
mismatch is detected, then an error message is issued.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 34 ++++++++++++----------------------
|
||||
zkey/zkey.c | 9 +++++++++
|
||||
2 files changed, 21 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -2252,43 +2252,32 @@ struct validate_info {
|
||||
/**
|
||||
* Displays the status of the associated APQNs.
|
||||
*
|
||||
+ * @param[in] keystore the key store
|
||||
* @param[in] properties the properties of the key
|
||||
- * @param[in] name the name of the key
|
||||
+ * @param[in] mkvp the master key verification pattern of the key
|
||||
*
|
||||
* @returns 0 in case of success, 1 if at least one of the APQNs is not
|
||||
- * available
|
||||
+ * available or has a master key mismatch
|
||||
*/
|
||||
-static int _keystore_display_apqn_status(struct properties *properties,
|
||||
- const char *name)
|
||||
+static int _keystore_display_apqn_status(struct keystore *keystore,
|
||||
+ struct properties *properties,
|
||||
+ u64 mkvp)
|
||||
{
|
||||
- int i, rc, card, domain, warning = 0;
|
||||
- char **apqn_list;
|
||||
+ int rc, warning = 0;
|
||||
char *apqns;
|
||||
|
||||
apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
if (apqns == NULL)
|
||||
return 0;
|
||||
- apqn_list = str_list_split(apqns);
|
||||
-
|
||||
- for (i = 0; apqn_list[i] != NULL; i++) {
|
||||
-
|
||||
- if (sscanf(apqn_list[i], "%x.%x", &card, &domain) != 2)
|
||||
- continue;
|
||||
|
||||
- rc = sysfs_is_apqn_online(card, domain);
|
||||
- if (rc != 1) {
|
||||
- printf("WARNING: The APQN %02x.%04x associated with "
|
||||
- "key '%s' is %s\n", card, domain, name,
|
||||
- rc == -1 ? "not a CCA card" : "not online");
|
||||
- warning = 1;
|
||||
- }
|
||||
- }
|
||||
+ rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose);
|
||||
+ if (rc != 0 && rc != -ENOTSUP)
|
||||
+ warning = 1;
|
||||
|
||||
if (warning)
|
||||
printf("\n");
|
||||
|
||||
free(apqns);
|
||||
- str_list_free_string_array(apqn_list);
|
||||
return warning;
|
||||
}
|
||||
/**
|
||||
@@ -2405,7 +2394,8 @@ static int _keystore_process_validate(st
|
||||
info->num_warnings++;
|
||||
}
|
||||
if (info->noapqncheck == 0)
|
||||
- if (_keystore_display_apqn_status(properties, name) != 0)
|
||||
+ if (_keystore_display_apqn_status(keystore, properties,
|
||||
+ mkvp) != 0)
|
||||
info->num_warnings++;
|
||||
if (_keystore_display_volume_status(properties, name) != 0)
|
||||
info->num_warnings++;
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1380,6 +1380,15 @@ static int command_validate_file(void)
|
||||
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
||||
&vp[VERIFICATION_PATTERN_LEN / 2]);
|
||||
|
||||
+ rc = cross_check_apqns(NULL, mkvp, true, g.verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ return EXIT_FAILURE;
|
||||
+ if (rc != 0 && rc != -ENOTSUP) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
out:
|
||||
free(secure_key);
|
||||
return rc;
|
@ -1,116 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Make address/size/mask macros UL
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: ea14f5471c6fbc9a8a407aa33324db39082b4689
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Make address/size/mask macros UL
|
||||
|
||||
While at it also fix some white space damages.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/stage3.h | 18 +++++++++---------
|
||||
zipl/include/zipl.h | 36 ++++++++++++++++++------------------
|
||||
2 files changed, 27 insertions(+), 27 deletions(-)
|
||||
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -15,12 +15,12 @@
|
||||
#include "libc.h"
|
||||
#include "s390.h"
|
||||
|
||||
-#define IPL_DEVICE 0x10404
|
||||
-#define INITRD_START 0x10408
|
||||
-#define INITRD_SIZE 0x10410
|
||||
-#define OLDMEM_BASE 0x10418
|
||||
-#define OLDMEM_SIZE 0x10420
|
||||
-#define COMMAND_LINE 0x10480
|
||||
+#define IPL_DEVICE 0x10404UL
|
||||
+#define INITRD_START 0x10408UL
|
||||
+#define INITRD_SIZE 0x10410UL
|
||||
+#define OLDMEM_BASE 0x10418UL
|
||||
+#define OLDMEM_SIZE 0x10420UL
|
||||
+#define COMMAND_LINE 0x10480UL
|
||||
#define COMMAND_LINE_SIZE 896
|
||||
#define COMMAND_LINE_EXTRA 0xE000
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
#define IPL_FLAG_SECURE 0x40
|
||||
|
||||
#define DEFAULT_IMAGE_ADDR 0x10000
|
||||
-#define DEFAULT_PSW_LOAD 0x0008000080010000L
|
||||
-#define PSW_ADDR_MASK 0x000000007FFFFFFFL
|
||||
+#define DEFAULT_PSW_LOAD 0x0008000080010000UL
|
||||
+#define PSW_ADDR_MASK 0x000000007FFFFFFFUL
|
||||
#define KERNEL_HEADER_SIZE 65536
|
||||
|
||||
-#define UNSPECIFIED_ADDRESS -1ULL
|
||||
+#define UNSPECIFIED_ADDRESS -1UL
|
||||
|
||||
|
||||
/* IPL Parameter List header */
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -19,27 +19,27 @@
|
||||
#define ZIPL_MAGIC_SIZE 4
|
||||
#define DISK_LAYOUT_ID 0x00000001
|
||||
|
||||
-#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000
|
||||
-#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000LL
|
||||
-#define DEFAULT_IMAGE_ADDRESS 0x10000LL
|
||||
-#define KDUMP_IMAGE_ADDRESS 0x10010LL
|
||||
-#define DEFAULT_STAGE3_ADDRESS 0xa000LL
|
||||
-#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000LL
|
||||
-#define MINIMUM_ADDRESS 0x10000LL
|
||||
-#define ADDRESS_LIMIT 0x80000000LL
|
||||
+#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
+#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000UL
|
||||
+#define DEFAULT_IMAGE_ADDRESS 0x10000UL
|
||||
+#define KDUMP_IMAGE_ADDRESS 0x10010UL
|
||||
+#define DEFAULT_STAGE3_ADDRESS 0xa000UL
|
||||
+#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000UL
|
||||
+#define MINIMUM_ADDRESS 0x10000UL
|
||||
+#define ADDRESS_LIMIT 0x80000000UL
|
||||
#define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */
|
||||
-#define UNSPECIFIED_ADDRESS -1ULL
|
||||
-#define MAXIMUM_PARMLINE_SIZE 0x380
|
||||
-#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000
|
||||
+#define UNSPECIFIED_ADDRESS -1UL
|
||||
+#define MAXIMUM_PARMLINE_SIZE 0x380UL
|
||||
+#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000UL
|
||||
|
||||
-#define STAGE3_HEAP_SIZE 0x4000
|
||||
-#define STAGE3_HEAP_ADDRESS 0x2000
|
||||
-#define STAGE3_STACK_SIZE 0x1000
|
||||
-#define STAGE3_STACK_ADDRESS 0xF000
|
||||
+#define STAGE3_HEAP_SIZE 0x4000UL
|
||||
+#define STAGE3_HEAP_ADDRESS 0x2000UL
|
||||
+#define STAGE3_STACK_SIZE 0x1000UL
|
||||
+#define STAGE3_STACK_ADDRESS 0xF000UL
|
||||
|
||||
-#define PSW_ADDRESS_MASK 0x000000007fffffffLL
|
||||
-#define PSW_LOAD 0x0008000080000000LL
|
||||
-#define PSW_DISABLED_WAIT 0x000a000000000000LL
|
||||
+#define PSW_ADDRESS_MASK 0x000000007fffffffUL
|
||||
+#define PSW_LOAD 0x0008000080000000UL
|
||||
+#define PSW_DISABLED_WAIT 0x000a000000000000UL
|
||||
|
||||
#define BOOTMAP_FILENAME "bootmap"
|
||||
#define BOOTMAP_TEMPLATE_FILENAME "bootmap_temp.XXXXXX"
|
@ -1,85 +0,0 @@
|
||||
Subject: zkey: Cross check APQNs when importing secure keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: d854aed4b8154e7420def8749db2106a049dd80a
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Cross check APQNs when importing secure keys
|
||||
|
||||
Perform a cross check of the APQNs when an existing secure AES key is
|
||||
imported into the key repository. When a set of APQNs are associated to
|
||||
the imported secure key, these APQNs are cross checked. If no APQNs are
|
||||
associated to imported secure key, then all currently available
|
||||
APQNs are cross checked. If a master key mismatch is detected, then
|
||||
the key import is rejected.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1770,6 +1770,7 @@ int keystore_import_key(struct keystore
|
||||
struct properties *key_props = NULL;
|
||||
size_t secure_key_size;
|
||||
u8 *secure_key;
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
@@ -1791,9 +1792,26 @@ int keystore_import_key(struct keystore
|
||||
goto out_free_key_filenames;
|
||||
}
|
||||
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, keystore->verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+
|
||||
+ rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ goto out_free_key;
|
||||
+ if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+
|
||||
rc = write_secure_key(file_names.skey_filename, secure_key,
|
||||
secure_key_size, keystore->verbose);
|
||||
free(secure_key);
|
||||
+ secure_key = NULL;
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
@@ -1811,6 +1829,9 @@ int keystore_import_key(struct keystore
|
||||
"Successfully imported a secure key in '%s' and key info in '%s'",
|
||||
file_names.skey_filename, file_names.info_filename);
|
||||
|
||||
+out_free_key:
|
||||
+ if (secure_key != NULL)
|
||||
+ free(secure_key);
|
||||
out_free_props:
|
||||
if (key_props != NULL)
|
||||
properties_free(key_props);
|
@ -1,52 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/libc: Use stdint.h instead of self defined macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 8face3e63ed88443392bcbcd93cc0b5e29b40069
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: Use stdint.h instead of self defined macros
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.h | 7 ++-----
|
||||
1 file changed, 2 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef LIBC_H
|
||||
#define LIBC_H
|
||||
|
||||
+#include <stdint.h>
|
||||
+
|
||||
#define NULL ((void *) 0)
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
@@ -42,11 +44,6 @@
|
||||
#define MIB (1024ULL * 1024)
|
||||
#define LINE_LENGTH 80 /* max line length printed by printf */
|
||||
|
||||
-typedef unsigned long long uint64_t;
|
||||
-typedef unsigned int uint32_t;
|
||||
-typedef unsigned short uint16_t;
|
||||
-typedef unsigned char uint8_t;
|
||||
-
|
||||
void printf(const char *, ...);
|
||||
void snprintf(char *buf, unsigned long size, const char *fmt, ...);
|
||||
void *memcpy(void *, const void *, unsigned long);
|
@ -1,86 +0,0 @@
|
||||
Subject: zkey: Cross check APQNs when changing APQN associations
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 0b4cbf00412f27456d28ff7f86ec5335a39e3416
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Cross check APQNs when changing APQN associations
|
||||
|
||||
Perform a cross check of the APQNs when the APQN association of a
|
||||
secure AES key in the key repository is changed. When adding new APQNs,
|
||||
or associating a new set of APQNs to a secure key, then the APQNs are
|
||||
cross checked. If all associated APQNs are removed, then all currently
|
||||
available APQNs are cross checked. If a master key mismatch is detected,
|
||||
then the change is rejected.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 31 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 31 insertions(+)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1886,7 +1886,11 @@ int keystore_change_key(struct keystore
|
||||
.nomsg = 0 };
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
+ size_t secure_key_size;
|
||||
+ char *apqns_prop;
|
||||
+ u8 *secure_key;
|
||||
char temp[30];
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
@@ -1932,6 +1936,33 @@ int keystore_change_key(struct keystore
|
||||
&apqn_check);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
+
|
||||
+ secure_key = read_secure_key(file_names.skey_filename,
|
||||
+ &secure_key_size,
|
||||
+ keystore->verbose);
|
||||
+ if (secure_key == NULL) {
|
||||
+ rc = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(secure_key,
|
||||
+ secure_key_size,
|
||||
+ &mkvp,
|
||||
+ keystore->verbose);
|
||||
+ free(secure_key);
|
||||
+ if (rc)
|
||||
+ goto out;
|
||||
+
|
||||
+ apqns_prop = properties_get(key_props, PROP_NAME_APQNS);
|
||||
+ rc = cross_check_apqns(apqns_prop, mkvp, true,
|
||||
+ keystore->verbose);
|
||||
+ free(apqns_prop);
|
||||
+ if (rc == -ENOTSUP)
|
||||
+ rc = 0;
|
||||
+ if (rc != 0 && noapqncheck == 0) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (sector_size >= 0) {
|
@ -1,199 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Consolidate IMAGE macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: cb614ed1ee61f05fb521a7e3ac0d27eb2eb45672
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Consolidate IMAGE macros
|
||||
|
||||
Combine the different macros for 0x10000 and use a consistent naming
|
||||
schema.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/stage3.c | 7 ++++---
|
||||
zipl/boot/stage3.h | 2 --
|
||||
zipl/include/zipl.h | 8 +++++---
|
||||
zipl/src/bootmap.c | 8 ++++----
|
||||
zipl/src/job.c | 17 +++++++++--------
|
||||
5 files changed, 22 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "s390.h"
|
||||
#include "stage3.h"
|
||||
#include "error.h"
|
||||
+#include "zipl.h"
|
||||
|
||||
#define for_each_rb_entry(entry, rb) \
|
||||
for (entry = rb->entries; \
|
||||
@@ -272,7 +273,7 @@ void start(void)
|
||||
* verified component. If it is not IPL is aborted.
|
||||
*/
|
||||
if (secure_boot_enabled()) {
|
||||
- if (_image_addr != DEFAULT_IMAGE_ADDR ||
|
||||
+ if (_image_addr != IMAGE_LOAD_ADDRESS ||
|
||||
_load_psw != DEFAULT_PSW_LOAD)
|
||||
panic(ESECUREBOOT, "%s", msg_sipl_inval);
|
||||
|
||||
@@ -283,8 +284,8 @@ void start(void)
|
||||
* cut the kernel header
|
||||
*/
|
||||
memmove((void *)_image_addr,
|
||||
- (void *)_image_addr + KERNEL_HEADER_SIZE,
|
||||
- _image_len - KERNEL_HEADER_SIZE);
|
||||
+ (void *)_image_addr + IMAGE_LOAD_ADDRESS,
|
||||
+ _image_len - IMAGE_LOAD_ADDRESS);
|
||||
|
||||
/* store subchannel ID into low core and into new kernel space */
|
||||
subchannel_id = S390_lowcore.subchannel_id;
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -29,10 +29,8 @@
|
||||
|
||||
#define IPL_FLAG_SECURE 0x40
|
||||
|
||||
-#define DEFAULT_IMAGE_ADDR 0x10000
|
||||
#define DEFAULT_PSW_LOAD 0x0008000080010000UL
|
||||
#define PSW_ADDR_MASK 0x000000007FFFFFFFUL
|
||||
-#define KERNEL_HEADER_SIZE 65536
|
||||
|
||||
#define UNSPECIFIED_ADDRESS -1UL
|
||||
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -19,13 +19,15 @@
|
||||
#define ZIPL_MAGIC_SIZE 4
|
||||
#define DISK_LAYOUT_ID 0x00000001
|
||||
|
||||
+#define IMAGE_ENTRY 0x10000UL
|
||||
+#define IMAGE_ENTRY_KDUMP 0x10010UL
|
||||
+
|
||||
#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000UL
|
||||
-#define DEFAULT_IMAGE_ADDRESS 0x10000UL
|
||||
-#define KDUMP_IMAGE_ADDRESS 0x10010UL
|
||||
#define DEFAULT_STAGE3_ADDRESS 0xa000UL
|
||||
#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000UL
|
||||
-#define MINIMUM_ADDRESS 0x10000UL
|
||||
+#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
|
||||
+
|
||||
#define ADDRESS_LIMIT 0x80000000UL
|
||||
#define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */
|
||||
#define UNSPECIFIED_ADDRESS -1UL
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -644,8 +644,8 @@ add_ipl_program(int fd, struct job_ipl_d
|
||||
rc = boot_get_stage3_parms(&stage3_params, &stage3_params_size,
|
||||
ipl->parm_addr, ipl->ramdisk_addr,
|
||||
ramdisk_size,
|
||||
- ipl->is_kdump ? ipl->image_addr + 0x10 :
|
||||
- ipl->image_addr,
|
||||
+ ipl->is_kdump ? IMAGE_ENTRY_KDUMP :
|
||||
+ IMAGE_ENTRY,
|
||||
(info->type == disk_type_scsi) ? 0 : 1,
|
||||
flags, ipl->image_addr, image_size);
|
||||
if (rc) {
|
||||
@@ -1187,7 +1187,7 @@ bootmap_create(struct job_data *job, dis
|
||||
ulong unused_size;
|
||||
|
||||
/* Use approximated stage 3 size as starting point */
|
||||
- size = MINIMUM_ADDRESS;
|
||||
+ size = IMAGE_LOAD_ADDRESS;
|
||||
|
||||
/* Ramdisk */
|
||||
if (job->data.dump.ramdisk != NULL) {
|
||||
@@ -1199,7 +1199,7 @@ bootmap_create(struct job_data *job, dis
|
||||
/* Kernel */
|
||||
if (stat(job->data.dump.image, &st))
|
||||
goto out_misc_free_temp_dev;
|
||||
- size += DIV_ROUND_UP(st.st_size - 0x10000,
|
||||
+ size += DIV_ROUND_UP(st.st_size - IMAGE_LOAD_ADDRESS,
|
||||
info->phy_block_size);
|
||||
/* Parmfile */
|
||||
size += DIV_ROUND_UP(DUMP_PARAM_MAX_LEN, info->phy_block_size);
|
||||
--- a/zipl/src/job.c
|
||||
+++ b/zipl/src/job.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "job.h"
|
||||
#include "misc.h"
|
||||
#include "scan.h"
|
||||
+#include "zipl.h"
|
||||
|
||||
/* Command line options */
|
||||
static struct option options[] = {
|
||||
@@ -663,12 +664,12 @@ check_component_address_data(struct comp
|
||||
address_limit);
|
||||
return -1;
|
||||
}
|
||||
- if (*cl[i].addrp < MINIMUM_ADDRESS) {
|
||||
+ if (*cl[i].addrp < IMAGE_LOAD_ADDRESS) {
|
||||
if (name != NULL)
|
||||
error_text("Section '%s'", name);
|
||||
error_reason("Component '%s' falls below available "
|
||||
"address space (limit is 0x%08x)",
|
||||
- cl[i].name, MINIMUM_ADDRESS);
|
||||
+ cl[i].name, IMAGE_LOAD_ADDRESS);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -706,12 +707,12 @@ finalize_component_address_data(struct c
|
||||
for (j = -1; j < i; j++) {
|
||||
if (j < 0) {
|
||||
/* Try address before first component */
|
||||
- addr = MINIMUM_ADDRESS;
|
||||
+ addr = IMAGE_LOAD_ADDRESS;
|
||||
} else {
|
||||
/* Try address after component j */
|
||||
addr = *cl[j].addrp + cl[j].size;
|
||||
- if (addr < MINIMUM_ADDRESS)
|
||||
- addr = MINIMUM_ADDRESS;
|
||||
+ if (addr < IMAGE_LOAD_ADDRESS)
|
||||
+ addr = IMAGE_LOAD_ADDRESS;
|
||||
}
|
||||
addr = ALIGN(addr, cl[i].align);
|
||||
if (addr + cl[i].size > address_limit) {
|
||||
@@ -905,7 +906,7 @@ check_job_dump_images(struct job_dump_da
|
||||
dump->image = misc_strdup(ZFCPDUMP_IMAGE);
|
||||
if (dump->image == NULL)
|
||||
return -1;
|
||||
- dump->image_addr = DEFAULT_IMAGE_ADDRESS;
|
||||
+ dump->image_addr = IMAGE_LOAD_ADDRESS;
|
||||
|
||||
/* Ramdisk is no longer required with new initramfs dump system */
|
||||
if (misc_check_readable_file(ZFCPDUMP_INITRD))
|
||||
@@ -1351,7 +1352,7 @@ get_job_from_section_data(char* data[],
|
||||
return -1;
|
||||
if (extract_address(job->data.ipl.image,
|
||||
&job->data.ipl.image_addr)) {
|
||||
- job->data.ipl.image_addr = DEFAULT_IMAGE_ADDRESS;
|
||||
+ job->data.ipl.image_addr = IMAGE_LOAD_ADDRESS;
|
||||
}
|
||||
/* Fill in parmline */
|
||||
rc = get_parmline(data[(int) scan_keyword_parmfile],
|
||||
@@ -1406,7 +1407,7 @@ get_job_from_section_data(char* data[],
|
||||
return -1;
|
||||
if (extract_address(job->data.ipl_tape.image,
|
||||
&job->data.ipl_tape.image_addr)) {
|
||||
- job->data.ipl_tape.image_addr = DEFAULT_IMAGE_ADDRESS;
|
||||
+ job->data.ipl_tape.image_addr = IMAGE_LOAD_ADDRESS;
|
||||
}
|
||||
/* Fill in parmline */
|
||||
rc = get_parmline(data[(int) scan_keyword_parmfile],
|
@ -1,455 +0,0 @@
|
||||
Subject: zkey: Add function to select a specific CCA adapter
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 016a0a56fcb3dd0bf8bed693e5d64873f6288995
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add function to select a specific CCA adapter
|
||||
|
||||
Some operations require the CCA host library to be used, such as
|
||||
re-enciphering a secure key. The CCA host library uses a different
|
||||
approach to select the APQN it operates with. To ensure that the
|
||||
desired APQN is used for an operation, a utility function is added
|
||||
to select a specific APQN for usage with the CCA host library.
|
||||
|
||||
The CCA host library allows to set environment variables to override
|
||||
the default CCA APQN selection. The environment variables are inspected
|
||||
during CCA host library initialization only. To select a specific
|
||||
domain for CCA, the CSU_DEFAULT_DOMAIN environment variable is set,
|
||||
and then the CCA host library is un-loaded and re-loaded again.
|
||||
Furthermore, the 'Cryptographic Resource Allocate' verb of the CCA
|
||||
host library is used together with the 'Cryptographic Facility Query
|
||||
function' verb to iterate over the crypto cards known by the CCA host
|
||||
library, and to identify the desired crypto card based on its serial
|
||||
number. That way, a specific APQN can be selected for use with
|
||||
subsequent CCA verbs.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/Makefile | 4
|
||||
zkey/cca.c | 296 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
zkey/cca.h | 32 ++++++
|
||||
3 files changed, 329 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/zkey/Makefile
|
||||
+++ b/zkey/Makefile
|
||||
@@ -66,7 +66,7 @@ all: $(BUILD_TARGETS)
|
||||
|
||||
zkey.o: zkey.c pkey.h cca.h misc.h
|
||||
pkey.o: pkey.c pkey.h
|
||||
-cca.o: cca.c cca.h pkey.h
|
||||
+cca.o: cca.c cca.h pkey.h utils.h
|
||||
utils.o: utils.h
|
||||
properties.o: check-dep-zkey properties.c properties.h
|
||||
keystore.o: keystore.c keystore.h properties.h pkey.h cca.h utils.h
|
||||
@@ -77,7 +77,7 @@ zkey: zkey.o pkey.o cca.o properties.o k
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c
|
||||
-zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o $(libs)
|
||||
+zkey-cryptsetup: zkey-cryptsetup.o pkey.o cca.o utils.o $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
install-common:
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
|
||||
#include "cca.h"
|
||||
#include "pkey.h"
|
||||
+#include "utils.h"
|
||||
|
||||
#define pr_verbose(verbose, fmt...) do { \
|
||||
if (verbose) \
|
||||
@@ -32,6 +34,8 @@
|
||||
*/
|
||||
#define CCA_LIBRARY_NAME "libcsulcca.so"
|
||||
#define CCA_WEB_PAGE "http://www.ibm.com/security/cryptocards"
|
||||
+#define CCA_DOMAIN_ENVAR "CSU_DEFAULT_DOMAIN"
|
||||
+#define CCA_ADAPTER_ENVAR "CSU_DEFAULT_ADAPTER"
|
||||
|
||||
/**
|
||||
* Prints CCA return and reason code information for certain known CCA
|
||||
@@ -136,8 +140,20 @@ int load_cca_library(struct cca_lib *cca
|
||||
/* Get the Key Token Change function */
|
||||
cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC");
|
||||
|
||||
+ /* Get the Cryptographic Facility Query function */
|
||||
+ cca->dll_CSUACFQ = (t_CSUACFQ)dlsym(cca->lib_csulcca, "CSUACFQ");
|
||||
+
|
||||
+ /* Get the Cryptographic Resource Allocate function */
|
||||
+ cca->dll_CSUACRA = (t_CSUACRA)dlsym(cca->lib_csulcca, "CSUACRA");
|
||||
+
|
||||
+ /* Cryptographic Resource Deallocate function */
|
||||
+ cca->dll_CSUACRD = (t_CSUACRD)dlsym(cca->lib_csulcca, "CSUACRD");
|
||||
+
|
||||
if (cca->dll_CSUACFV == NULL ||
|
||||
- cca->dll_CSNBKTC == NULL) {
|
||||
+ cca->dll_CSNBKTC == NULL ||
|
||||
+ cca->dll_CSUACFQ == NULL ||
|
||||
+ cca->dll_CSUACRA == NULL ||
|
||||
+ cca->dll_CSUACRD == NULL) {
|
||||
pr_verbose(verbose, "%s", dlerror());
|
||||
warnx("The command requires the IBM CCA Host Libraries and "
|
||||
"Tools.\nFor the supported environments and downloads, "
|
||||
@@ -213,3 +229,281 @@ int key_token_change(struct cca_lib *cca
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Queries the number of adapters known by the CCA host library
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[out] adapters the number of adapters
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error.
|
||||
+ */
|
||||
+static int get_number_of_cca_adapters(struct cca_lib *cca,
|
||||
+ unsigned int *adapters, bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count, verb_data_length = 0;
|
||||
+ unsigned char rule_array[16 * 8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+ util_assert(adapters != NULL, "Internal error: adapters is NULL");
|
||||
+
|
||||
+ memset(rule_array, 0, sizeof(rule_array));
|
||||
+ memcpy(rule_array, "STATCRD2", 8);
|
||||
+ rule_array_count = 1;
|
||||
+
|
||||
+ cca->dll_CSUACFQ(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &verb_data_length, NULL);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
|
||||
+ "return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ rule_array[8] = '\0';
|
||||
+ if (sscanf((char *)rule_array, "%u", adapters) != 1) {
|
||||
+ pr_verbose(verbose, "Unparsable output: %s", rule_array);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "Number of CCA adapters: %u", *adapters);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Allocate a specific CCA adapter.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] adapter the adapter number, starting at 1. If 0 is
|
||||
+ * specified, then the AUTOSELECT option is
|
||||
+ * enabled.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error. -ENODEV is
|
||||
+ * returned if the adapter is not available.
|
||||
+ */
|
||||
+static int allocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count;
|
||||
+ unsigned char rule_array[8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+ char res_name[9];
|
||||
+ long res_name_len;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ if (adapter > 0)
|
||||
+ memcpy(rule_array, "DEVICE ", 8);
|
||||
+ else
|
||||
+ memcpy(rule_array, "DEV-ANY ", 8);
|
||||
+ rule_array_count = 1;
|
||||
+
|
||||
+ sprintf(res_name, "CRP%02d", adapter);
|
||||
+ res_name_len = strlen(res_name);
|
||||
+
|
||||
+ cca->dll_CSUACRA(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &res_name_len, (unsigned char *)res_name);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSUACRA (Cryptographic Resource Allocate) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "Adapter %u (%s) allocated", adapter, res_name);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Deallocate a specific CCA adapter.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] adapter the adapter number, starting at 1. If 0 is
|
||||
+ * specified, then the AUTOSELECT option is
|
||||
+ * disabled.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error. -ENODEV is
|
||||
+ * returned if the adapter is not available.
|
||||
+ */
|
||||
+static int deallocate_cca_adapter(struct cca_lib *cca, unsigned int adapter,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count;
|
||||
+ unsigned char rule_array[8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+ char res_name[9];
|
||||
+ long res_name_len;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ if (adapter > 0)
|
||||
+ memcpy(rule_array, "DEVICE ", 8);
|
||||
+ else
|
||||
+ memcpy(rule_array, "DEV-ANY ", 8);
|
||||
+ rule_array_count = 1;
|
||||
+
|
||||
+ sprintf(res_name, "CRP%02d", adapter);
|
||||
+ res_name_len = strlen(res_name);
|
||||
+
|
||||
+ cca->dll_CSUACRD(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &res_name_len, (unsigned char *)res_name);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSUACRD (Cryptographic Resource Deallocate) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "Adapter %u (%s) deallocated", adapter, res_name);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Queries the serial number of the current CCA adapter
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[out] serialnr the buffer where the serial number is returned
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error.
|
||||
+ */
|
||||
+static int get_cca_adapter_serialnr(struct cca_lib *cca, char serialnr[9],
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count, verb_data_length = 0;
|
||||
+ unsigned char rule_array[16 * 8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ memset(rule_array, 0, sizeof(rule_array));
|
||||
+ memcpy(rule_array, "STATCRD2", 8);
|
||||
+ rule_array_count = 1;
|
||||
+
|
||||
+ cca->dll_CSUACFQ(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &verb_data_length, NULL);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
|
||||
+ "return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(serialnr, rule_array+14*8, 8);
|
||||
+ serialnr[8] = '\0';
|
||||
+
|
||||
+ pr_verbose(verbose, "Serial number of CCA adapter: %s", serialnr);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Selects the specified APQN to be used for the CCA host library.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] card the card number
|
||||
+ * @param[in] domain the domain number
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error. -ENOTSUP is
|
||||
+ * returned when the serialnr sysfs attribute is not available,
|
||||
+ * because the zcrypt kernel module is on an older level. -ENODEV is
|
||||
+ * returned if the APQN is not available.
|
||||
+ */
|
||||
+int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose)
|
||||
+{
|
||||
+ unsigned int adapters, adapter;
|
||||
+ char adapter_serialnr[9];
|
||||
+ char apqn_serialnr[9];
|
||||
+ char temp[10];
|
||||
+ int rc, found = 0;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ pr_verbose(verbose, "Select %02x.%04x for the CCA host library", card,
|
||||
+ domain);
|
||||
+
|
||||
+ rc = sysfs_get_serialnr(card, apqn_serialnr, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ pr_verbose(verbose, "Failed to get the serial number: %s",
|
||||
+ strerror(-rc));
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ sprintf(temp, "%u", domain);
|
||||
+ if (setenv(CCA_DOMAIN_ENVAR, temp, 1) != 0) {
|
||||
+ rc = -errno;
|
||||
+ pr_verbose(verbose, "Failed to set the %s environment variable:"
|
||||
+ " %s", CCA_DOMAIN_ENVAR, strerror(-rc));
|
||||
+ return rc;
|
||||
+ }
|
||||
+ unsetenv(CCA_ADAPTER_ENVAR);
|
||||
+
|
||||
+ /*
|
||||
+ * Unload and reload the CCA host library so that it recognizes the
|
||||
+ * changed CSU_DEFAULT_DOMAIN environment variable value.
|
||||
+ */
|
||||
+ if (cca->lib_csulcca != NULL)
|
||||
+ dlclose(cca->lib_csulcca);
|
||||
+ memset(cca, 0, sizeof(struct cca_lib));
|
||||
+
|
||||
+ rc = load_cca_library(cca, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ rc = get_number_of_cca_adapters(cca, &adapters, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ /* Disable the AUTOSELECT option */
|
||||
+ rc = deallocate_cca_adapter(cca, 0, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ for (adapter = 1; adapter <= adapters; adapter++) {
|
||||
+ rc = allocate_cca_adapter(cca, adapter, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ rc = get_cca_adapter_serialnr(cca, adapter_serialnr, verbose);
|
||||
+ if (rc == 0) {
|
||||
+ if (memcmp(apqn_serialnr, adapter_serialnr, 8) == 0) {
|
||||
+ found = 1;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rc = deallocate_cca_adapter(cca, adapter, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
+ if (!found)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ pr_verbose(verbose, "Selected adapter %u (CRP%02d)", adapter, adapter);
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -32,6 +32,33 @@ typedef void (*t_CSUACFV)(long *return_c
|
||||
long *version_data_length,
|
||||
unsigned char *version_data);
|
||||
|
||||
+typedef void (*t_CSUACFQ)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *verb_data_length,
|
||||
+ unsigned char *verb_data);
|
||||
+
|
||||
+typedef void (*t_CSUACRA)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *ressource_name_length,
|
||||
+ unsigned char *ressource_name);
|
||||
+
|
||||
+typedef void (*t_CSUACRD)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *ressource_name_length,
|
||||
+ unsigned char *ressource_name);
|
||||
+
|
||||
struct cca_version {
|
||||
unsigned int ver;
|
||||
unsigned int rel;
|
||||
@@ -42,6 +69,9 @@ struct cca_lib {
|
||||
void *lib_csulcca;
|
||||
t_CSNBKTC dll_CSNBKTC;
|
||||
t_CSUACFV dll_CSUACFV;
|
||||
+ t_CSUACFQ dll_CSUACFQ;
|
||||
+ t_CSUACRA dll_CSUACRA;
|
||||
+ t_CSUACRD dll_CSUACRD;
|
||||
struct cca_version version;
|
||||
};
|
||||
|
||||
@@ -51,4 +81,6 @@ int key_token_change(struct cca_lib *cca
|
||||
u8 *secure_key, unsigned int secure_key_size,
|
||||
char *method, bool verbose);
|
||||
|
||||
+int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,110 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: Consolidate STAGE{2,3} macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 4762e65acbc4efe7142ccb5fd2ef86073737ebd8
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: Consolidate STAGE{2,3} macros
|
||||
|
||||
Increase consistency with the other macros by moving and renaming
|
||||
the STAGE{2,3} macros in zipl.h.
|
||||
|
||||
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/include/zipl.h | 8 ++++----
|
||||
zipl/src/boot.c | 4 ++--
|
||||
zipl/src/bootmap.c | 6 +++---
|
||||
3 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -19,13 +19,12 @@
|
||||
#define ZIPL_MAGIC_SIZE 4
|
||||
#define DISK_LAYOUT_ID 0x00000001
|
||||
|
||||
+#define STAGE3_ENTRY 0xa000UL
|
||||
#define IMAGE_ENTRY 0x10000UL
|
||||
#define IMAGE_ENTRY_KDUMP 0x10010UL
|
||||
|
||||
-#define ZIPL_STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
-#define ZIPL_STAGE3_ENTRY_ADDRESS 0xa000UL
|
||||
-#define DEFAULT_STAGE3_ADDRESS 0xa000UL
|
||||
-#define DEFAULT_STAGE3_PARAMS_ADDRESS 0x9000UL
|
||||
+#define STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
+#define STAGE3_LOAD_ADDRESS 0xa000UL
|
||||
#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
|
||||
|
||||
#define ADDRESS_LIMIT 0x80000000UL
|
||||
@@ -38,6 +37,7 @@
|
||||
#define STAGE3_HEAP_ADDRESS 0x2000UL
|
||||
#define STAGE3_STACK_SIZE 0x1000UL
|
||||
#define STAGE3_STACK_ADDRESS 0xF000UL
|
||||
+#define STAGE3_PARAMS_ADDRESS 0x9000UL
|
||||
|
||||
#define PSW_ADDRESS_MASK 0x000000007fffffffUL
|
||||
#define PSW_LOAD 0x0008000080000000UL
|
||||
--- a/zipl/src/boot.c
|
||||
+++ b/zipl/src/boot.c
|
||||
@@ -195,7 +195,7 @@ boot_init_fba_stage1b(struct boot_fba_st
|
||||
stage1b->locdata[i].blocknr =
|
||||
(uint32_t) stage2_list[i].linear.block;
|
||||
stage1b->locread[i].read.address_lo =
|
||||
- ZIPL_STAGE2_LOAD_ADDRESS + i * FBA_BLK_SIZE;
|
||||
+ STAGE2_LOAD_ADDRESS + i * FBA_BLK_SIZE;
|
||||
}
|
||||
/* Terminate CCW chain */
|
||||
stage1b->locread[i - 1].read.flags &= ~CCW_FLAG_CC;
|
||||
@@ -220,7 +220,7 @@ boot_init_eckd_stage1b(struct boot_eckd_
|
||||
stage1b->seek[i].head = stage2_list[i].chs.head |
|
||||
((stage2_list[i].chs.cyl >> 12) & 0xfff0);
|
||||
stage1b->seek[i].sec = stage2_list[i].chs.sec;
|
||||
- stage1b->ssrt[i].read.address_lo = ZIPL_STAGE2_LOAD_ADDRESS +
|
||||
+ stage1b->ssrt[i].read.address_lo = STAGE2_LOAD_ADDRESS +
|
||||
i * stage2_list[i].chs.size;
|
||||
stage1b->ssrt[i].read.flags = CCW_FLAG_CC | CCW_FLAG_SLI;
|
||||
}
|
||||
--- a/zipl/src/bootmap.c
|
||||
+++ b/zipl/src/bootmap.c
|
||||
@@ -627,7 +627,7 @@ add_ipl_program(int fd, struct job_ipl_d
|
||||
}
|
||||
|
||||
/* Add stage 3 loader to bootmap */
|
||||
- rc = add_component_file(fd, ZIPL_STAGE3_PATH, DEFAULT_STAGE3_ADDRESS,
|
||||
+ rc = add_component_file(fd, ZIPL_STAGE3_PATH, STAGE3_LOAD_ADDRESS,
|
||||
signature_size, VOID_ADD(table, offset), 1,
|
||||
info, target, &comp_loc[comp_nr]);
|
||||
if (rc) {
|
||||
@@ -654,7 +654,7 @@ add_ipl_program(int fd, struct job_ipl_d
|
||||
}
|
||||
rc = add_component_buffer(fd, stage3_params, stage3_params_size,
|
||||
(component_data) (uint64_t)
|
||||
- DEFAULT_STAGE3_PARAMS_ADDRESS,
|
||||
+ STAGE3_PARAMS_ADDRESS,
|
||||
VOID_ADD(table, offset), info,
|
||||
&comp_loc[comp_nr], component_load);
|
||||
free(stage3_params);
|
||||
@@ -792,7 +792,7 @@ add_ipl_program(int fd, struct job_ipl_d
|
||||
create_component_entry(VOID_ADD(table, offset), NULL,
|
||||
component_execute,
|
||||
(component_data) (uint64_t)
|
||||
- (ZIPL_STAGE3_ENTRY_ADDRESS | PSW_LOAD),
|
||||
+ (STAGE3_ENTRY | PSW_LOAD),
|
||||
info);
|
||||
/* Write component table */
|
||||
rc = disk_write_block_aligned(fd, table, info->phy_block_size,
|
@ -1,162 +0,0 @@
|
||||
Subject: zkey: Add function to select a CCA adapter by mkvp
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 1091b0bf65328aff94055a2e333aff2c737b6744
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add function to select a CCA adapter by mkvp
|
||||
|
||||
Add a utility function to select an APQN that is set up with
|
||||
a specific master key for use with the CCA host library. The
|
||||
selection is based on the master key verification pattern, which
|
||||
is typically obtained from an existing secure AES key.
|
||||
|
||||
The function iterates over a set of APQNs to find one that is setup
|
||||
with the desired master key in the CURRENT or OLD master key register,
|
||||
and optionally has a new master key loaded. It then selects the found
|
||||
APQN for use with the CCA host library.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/cca.h | 7 ++++
|
||||
2 files changed, 107 insertions(+)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -507,3 +507,103 @@ int select_cca_adapter(struct cca_lib *c
|
||||
pr_verbose(verbose, "Selected adapter %u (CRP%02d)", adapter, adapter);
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+struct find_mkvp_info {
|
||||
+ u64 mkvp;
|
||||
+ unsigned int flags;
|
||||
+ bool found;
|
||||
+ int card;
|
||||
+ int domain;
|
||||
+ bool verbose;
|
||||
+};
|
||||
+
|
||||
+static int find_mkvp(int card, int domain, void *handler_data)
|
||||
+{
|
||||
+ struct find_mkvp_info *info = (struct find_mkvp_info *)handler_data;
|
||||
+ struct mk_info mk_info;
|
||||
+ bool found = false;
|
||||
+ int rc;
|
||||
+
|
||||
+ rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
|
||||
+ if (rc == -ENODEV)
|
||||
+ return 0;
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ if (info->flags & FLAG_SEL_CCA_MATCH_CUR_MKVP)
|
||||
+ if (mk_info.cur_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.cur_mk.mkvp == info->mkvp)
|
||||
+ found = true;
|
||||
+
|
||||
+ if (info->flags & FLAG_SEL_CCA_MATCH_OLD_MKVP)
|
||||
+ if (mk_info.old_mk.mk_state == MK_STATE_VALID &&
|
||||
+ mk_info.old_mk.mkvp == info->mkvp)
|
||||
+ found = true;
|
||||
+
|
||||
+ if (info->flags & FLAG_SEL_CCA_NEW_MUST_BE_SET)
|
||||
+ if (mk_info.new_mk.mk_state != MK_STATE_FULL)
|
||||
+ found = false;
|
||||
+
|
||||
+
|
||||
+ if (found) {
|
||||
+ info->card = card;
|
||||
+ info->domain = domain;
|
||||
+ info->found = true;
|
||||
+
|
||||
+ pr_verbose(info->verbose, "%02x.%04x has the desired mkvp%s",
|
||||
+ card, domain,
|
||||
+ info->flags & FLAG_SEL_CCA_NEW_MUST_BE_SET ?
|
||||
+ " and NEW MK set" : "");
|
||||
+
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Selects an APQN to be used for the CCA host library that has the specified
|
||||
+ * master key verification pattern
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] mkvp the master key verification pattern to search for
|
||||
+ * @param[in] apqns a comma separated list of APQNs. If NULL is specified,
|
||||
+ * or an empty string, then all online CCA APQNs are
|
||||
+ * checked.
|
||||
+ * @param[in] flags Flags that control the MKVM matching and NEW register
|
||||
+ * checking. Multiple flags can be combined.
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error. -ENOTSUP is
|
||||
+ * returned when the serialnr sysfs attribute is not available,
|
||||
+ * because the zcrypt kernel module is on an older level. -ENODEV is
|
||||
+ * returned if no APQN is available with the desired mkvp.
|
||||
+ */
|
||||
+int select_cca_adapter_by_mkvp(struct cca_lib *cca, u64 mkvp, const char *apqns,
|
||||
+ unsigned int flags, bool verbose)
|
||||
+{
|
||||
+ struct find_mkvp_info info;
|
||||
+ int rc;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ pr_verbose(verbose, "Select mkvp %016llx in APQNs %s for the CCA host "
|
||||
+ "library", mkvp, apqns == 0 ? "ANY" : apqns);
|
||||
+
|
||||
+ info.mkvp = mkvp;
|
||||
+ info.flags = flags;
|
||||
+ info.found = false;
|
||||
+ info.card = 0;
|
||||
+ info.domain = 0;
|
||||
+ info.verbose = verbose;
|
||||
+
|
||||
+ rc = handle_apqns(apqns, find_mkvp, &info, verbose);
|
||||
+ if (rc < 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ if (!info.found)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ rc = select_cca_adapter(cca, info.card, info.domain, verbose);
|
||||
+ return rc;
|
||||
+}
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -83,4 +83,11 @@ int key_token_change(struct cca_lib *cca
|
||||
|
||||
int select_cca_adapter(struct cca_lib *cca, int card, int domain, bool verbose);
|
||||
|
||||
+#define FLAG_SEL_CCA_MATCH_CUR_MKVP 0x01
|
||||
+#define FLAG_SEL_CCA_MATCH_OLD_MKVP 0x02
|
||||
+#define FLAG_SEL_CCA_NEW_MUST_BE_SET 0x80
|
||||
+
|
||||
+int select_cca_adapter_by_mkvp(struct cca_lib *cca, u64 mkvp, const char *apqns,
|
||||
+ unsigned int flags, bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,53 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: stfle: use uint64_t instead of u64
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 9d1baaa594d796ca9fe6bdf1282c78e4b2ff5234
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: stfle: use uint64_t instead of u64
|
||||
|
||||
As the definition of `stfle_fac_list` in the lowcore uses uint64_t, we
|
||||
should also use uint64_t for the `stfle_fac_list` parameter of the
|
||||
`stfle/__stfle_asm` function.
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/s390.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -452,7 +452,7 @@ static inline int test_facility(unsigned
|
||||
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
|
||||
}
|
||||
|
||||
-static inline unsigned long __stfle_asm(u64 *stfle_fac_list, int size)
|
||||
+static inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, int size)
|
||||
{
|
||||
register unsigned long reg0 asm("0") = size - 1;
|
||||
|
||||
@@ -469,7 +469,7 @@ static inline unsigned long __stfle_asm(
|
||||
* @stfle_fac_list: array where facility list can be stored
|
||||
* @size: size of passed in array in double words
|
||||
*/
|
||||
-static inline void stfle(u64 *stfle_fac_list, int size)
|
||||
+static inline void stfle(uint64_t *stfle_fac_list, int size)
|
||||
{
|
||||
unsigned long nr;
|
||||
|
@ -1,397 +0,0 @@
|
||||
Subject: zkey: Select CCA adapter when re-enciphering
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: 552a915465301b768268cddc7ccb65a6d167e432
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Select CCA adapter when re-enciphering
|
||||
|
||||
When re-enciphering secure AES keys, select the correct APQN for used
|
||||
with the CCA host library. Re-enciphering a secure key requires the use
|
||||
of the CCA host library. The APQN is selected based on the master key
|
||||
verification pattern obtained from the secure key to re-encipher.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 19 ++++++++++++++
|
||||
zkey/cca.h | 2 +
|
||||
zkey/keystore.c | 57 ++++++++++++++++++++++++++++++++++++-------
|
||||
zkey/zkey-cryptsetup.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
zkey/zkey.c | 50 ++++++++++++++++++++++++++++++++++++--
|
||||
5 files changed, 179 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include "lib/util_base.h"
|
||||
+#include "lib/util_libc.h"
|
||||
#include "lib/util_panic.h"
|
||||
|
||||
#include "cca.h"
|
||||
@@ -607,3 +609,20 @@ int select_cca_adapter_by_mkvp(struct cc
|
||||
rc = select_cca_adapter(cca, info.card, info.domain, verbose);
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+void print_msg_for_cca_envvars(const char *key_name)
|
||||
+{
|
||||
+ char *msg;
|
||||
+
|
||||
+ util_asprintf(&msg, "WARNING: You must set environment variables "
|
||||
+ "%s and %s to the desired card and domain that is "
|
||||
+ "set up with the AES master key used by this %s. "
|
||||
+ "%s specifies the domain as decimal number. %s "
|
||||
+ "specifies the adapter number as 'CRPnn', where "
|
||||
+ "'nn' is the adapter number. See the CCA "
|
||||
+ "documentation for more details.\n",
|
||||
+ CCA_DOMAIN_ENVAR, CCA_ADAPTER_ENVAR, key_name,
|
||||
+ CCA_DOMAIN_ENVAR, CCA_ADAPTER_ENVAR);
|
||||
+ util_print_indented(msg, 0);
|
||||
+ free(msg);
|
||||
+}
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -90,4 +90,6 @@ int select_cca_adapter(struct cca_lib *c
|
||||
int select_cca_adapter_by_mkvp(struct cca_lib *cca, u64 mkvp, const char *apqns,
|
||||
unsigned int flags, bool verbose);
|
||||
|
||||
+void print_msg_for_cca_envvars(const char *key_name);
|
||||
+
|
||||
#endif
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -2535,6 +2535,7 @@ struct reencipher_info {
|
||||
* @param[in] secure_key_size the size of the secure key
|
||||
* @param[in] is_old_mk if true the key is currently re-enciphered with the
|
||||
* OLD master key
|
||||
+ * @param[in] apqns the associated APQNs (or NULL if none)
|
||||
* @returns 0 if the re-enciphering is successful, a negative errno value
|
||||
* otherwise, 1 if it was skipped
|
||||
*/
|
||||
@@ -2543,9 +2544,18 @@ static int _keystore_perform_reencipher(
|
||||
struct cca_lib *cca,
|
||||
struct reencipher_params *params,
|
||||
u8 *secure_key, size_t secure_key_size,
|
||||
- bool is_old_mk)
|
||||
+ bool is_old_mk, const char *apqns)
|
||||
{
|
||||
- int rc;
|
||||
+ int rc, selected = 1;
|
||||
+ u64 mkvp;
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, keystore->verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ return rc;
|
||||
+ }
|
||||
|
||||
if (!params->from_old && !params->to_new) {
|
||||
/* Autodetect reencipher mode */
|
||||
@@ -2567,12 +2577,6 @@ static int _keystore_perform_reencipher(
|
||||
}
|
||||
|
||||
if (params->from_old) {
|
||||
- if (!is_old_mk) {
|
||||
- printf("The secure key '%s' is already enciphered "
|
||||
- "with the CURRENT CCA master key\n", name);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
if (params->inplace == -1)
|
||||
params->inplace = 1;
|
||||
|
||||
@@ -2580,12 +2584,27 @@ static int _keystore_perform_reencipher(
|
||||
"Secure key '%s' will be re-enciphered from OLD "
|
||||
"to the CURRENT CCA master key", name);
|
||||
|
||||
+ rc = select_cca_adapter_by_mkvp(cca, mkvp, apqns,
|
||||
+ FLAG_SEL_CCA_MATCH_OLD_MKVP,
|
||||
+ keystore->verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ warnx("No APQN found that is suitable for "
|
||||
+ "re-enciphering this secure AES key");
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(cca, secure_key, secure_key_size,
|
||||
METHOD_OLD_TO_CURRENT,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to re-encipher '%s' from OLD to "
|
||||
"CURRENT CCA master key", name);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -2597,12 +2616,30 @@ static int _keystore_perform_reencipher(
|
||||
if (params->inplace == -1)
|
||||
params->inplace = 0;
|
||||
|
||||
+ rc = select_cca_adapter_by_mkvp(cca, mkvp, apqns,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
+ FLAG_SEL_CCA_NEW_MUST_BE_SET,
|
||||
+ keystore->verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_print_indented("No APQN found that is suitable "
|
||||
+ "for re-enciphering this secure "
|
||||
+ "AES key and has the NEW master "
|
||||
+ "key loaded", 0);
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(cca, secure_key, secure_key_size,
|
||||
METHOD_CURRENT_TO_NEW,
|
||||
keystore->verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to re-encipher '%s' from CURRENT to "
|
||||
"NEW CCA master key", name);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -2692,7 +2729,9 @@ static int _keystore_process_reencipher(
|
||||
|
||||
rc = _keystore_perform_reencipher(keystore, name, info->cca,
|
||||
¶ms, secure_key,
|
||||
- secure_key_size, is_old_mk);
|
||||
+ secure_key_size, is_old_mk,
|
||||
+ properties_get(properties,
|
||||
+ PROP_NAME_APQNS));
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
if (rc > 0) {
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -1514,10 +1514,12 @@ static int reencipher_prepare(int token)
|
||||
char *password = NULL;
|
||||
size_t password_len;
|
||||
char *key = NULL;
|
||||
+ int selected = 1;
|
||||
size_t keysize;
|
||||
int is_old_mk;
|
||||
char *prompt;
|
||||
char *msg;
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
if (token >= 0) {
|
||||
@@ -1578,13 +1580,42 @@ static int reencipher_prepare(int token)
|
||||
util_print_indented(msg, 0);
|
||||
free(msg);
|
||||
|
||||
+ rc = get_master_key_verification_pattern((u8 *)key, keysize, &mkvp,
|
||||
+ g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ is_old_mk ? FLAG_SEL_CCA_MATCH_OLD_MKVP
|
||||
+ : FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
+ FLAG_SEL_CCA_NEW_MUST_BE_SET,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_asprintf(&msg, "No APQN found that is suitable for "
|
||||
+ "re-enciphering the secure AES volume key%s",
|
||||
+ !is_old_mk ? " and has the NEW master key loaded"
|
||||
+ : "");
|
||||
+ util_print_indented(msg, 0);
|
||||
+ free(msg);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
is_old_mk ? METHOD_OLD_TO_CURRENT :
|
||||
METHOD_CURRENT_TO_NEW,
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to re-encipher the secure volume key of device "
|
||||
- "'%s'", g.pos_arg);
|
||||
+ "'%s'\n", g.pos_arg);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES volume key");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -1651,10 +1682,12 @@ static int reencipher_complete(int token
|
||||
char *password = NULL;
|
||||
size_t password_len;
|
||||
char *key = NULL;
|
||||
+ int selected = 1;
|
||||
size_t keysize;
|
||||
int is_old_mk;
|
||||
char *prompt;
|
||||
char *msg;
|
||||
+ u64 mkvp;
|
||||
int rc;
|
||||
|
||||
rc = get_reencipher_token(g.cd, token, &tok, true);
|
||||
@@ -1700,11 +1733,38 @@ static int reencipher_complete(int token
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ rc = get_master_key_verification_pattern((u8 *)key, keysize,
|
||||
+ &mkvp, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification "
|
||||
+ "pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_OLD_MKVP,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_print_indented("No APQN found that is suitable "
|
||||
+ "for re-enciphering the secure AES "
|
||||
+ "volume key from the OLD to the "
|
||||
+ "CURRENT CCA master key.", 0);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
METHOD_OLD_TO_CURRENT, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to re-encipher the secure volume key for "
|
||||
- "device '%s'", g.pos_arg);
|
||||
+ "device '%s'\n", g.pos_arg);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars(
|
||||
+ "secure AES volume key");
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1128,7 +1128,9 @@ static int command_reencipher_file(void)
|
||||
{
|
||||
size_t secure_key_size;
|
||||
int rc, is_old_mk;
|
||||
+ int selected = 1;
|
||||
u8 *secure_key;
|
||||
+ u64 mkvp;
|
||||
|
||||
if (g.name != NULL) {
|
||||
warnx("Option '--name|-N' is not valid for "
|
||||
@@ -1174,6 +1176,15 @@ static int command_reencipher_file(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (!g.fromold && !g.tonew) {
|
||||
/* Autodetect reencipher option */
|
||||
if (is_old_mk) {
|
||||
@@ -1205,12 +1216,28 @@ static int command_reencipher_file(void)
|
||||
pr_verbose("Secure key will be re-enciphered from OLD to the "
|
||||
"CURRENT CCA master key");
|
||||
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_OLD_MKVP,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ warnx("No APQN found that is suitable for "
|
||||
+ "re-enciphering the secure AES volume key");
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(&g.cca, secure_key, secure_key_size,
|
||||
METHOD_OLD_TO_CURRENT,
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Re-encipher from OLD to CURRENT CCA "
|
||||
- "master key has failed");
|
||||
+ "master key has failed\n");
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
rc = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
||||
@@ -1219,11 +1246,30 @@ static int command_reencipher_file(void)
|
||||
pr_verbose("Secure key will be re-enciphered from CURRENT "
|
||||
"to the NEW CCA master key");
|
||||
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
+ FLAG_SEL_CCA_NEW_MUST_BE_SET,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_print_indented("No APQN found that is suitable "
|
||||
+ "for re-enciphering this secure "
|
||||
+ "AES key and has the NEW master "
|
||||
+ "key loaded", 0);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
rc = key_token_change(&g.cca, secure_key, secure_key_size,
|
||||
METHOD_CURRENT_TO_NEW, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Re-encipher from CURRENT to NEW CCA "
|
||||
- "master key has failed");
|
||||
+ "master key has failed\n");
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
rc = EXIT_FAILURE;
|
||||
goto out;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/boot: fix comment in stage3.lds
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 971970989bbb1de8887d11b0ab8e4f19adbd484f
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/boot: fix comment in stage3.lds
|
||||
|
||||
See STAGE3_STACK_ADDRESS macro.
|
||||
|
||||
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/stage3.lds | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/stage3.lds
|
||||
+++ b/zipl/boot/stage3.lds
|
||||
@@ -10,7 +10,7 @@
|
||||
* 0x6000-0x8fff free
|
||||
* 0x9000-0x9fff Stage3 parameter
|
||||
* 0xa000-0xdfff Stage3 code + data
|
||||
- * 0xe000-0xffff Stack
|
||||
+ * 0xf000-0xffff Stack
|
||||
*/
|
||||
|
||||
SECTIONS
|
@ -1,289 +0,0 @@
|
||||
Subject: zkey-cryptsetup: Add --to-new and --from-old options
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: check master key consistency
|
||||
Description: Enhances the zkey tool to perform a cross check whether the
|
||||
APQNs associated with a secure key have the same master key.
|
||||
Display the master key verification pattern of a secure key
|
||||
during the zkey validate command. This helps to better identify
|
||||
which master key is the correct one, in case of master key
|
||||
inconsistencies.
|
||||
Select an appropriate APQN when re-enciphering a secure key.
|
||||
Re-enciphering is done using the CCA host library. Special
|
||||
handling is required to select an appropriate APQN for use with
|
||||
the CCA host library.
|
||||
Upstream-ID: a0ed6709cf3c62b1fc9dfa28358e70215c1da55a
|
||||
Problem-ID: SEC1916
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey-cryptsetup: Add --to-new and --from-old options
|
||||
|
||||
To allow better control about the secure AES volume key re-enciphering
|
||||
with 'zkey-cryptsetup reencipher', add options '--to-new' and '--from-old'
|
||||
to specify if a re-enciphering from CURRENT to NEW, or OLD to CURRENT master
|
||||
key registers is to be performed. If these options are not specified, then
|
||||
it is auto-detected, based on the master key that the secure key is currently
|
||||
re-enciphered with.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/zkey-cryptsetup.1 | 49 ++++++++++++++---
|
||||
zkey/zkey-cryptsetup.c | 137 ++++++++++++++++++++++++++++++++++++-------------
|
||||
2 files changed, 142 insertions(+), 44 deletions(-)
|
||||
|
||||
--- a/zkey/zkey-cryptsetup.1
|
||||
+++ b/zkey/zkey-cryptsetup.1
|
||||
@@ -91,6 +91,8 @@ behave in the same way as with \fBcrypts
|
||||
.B zkey\-cryptsetup
|
||||
.BR reencipher | re
|
||||
.I device
|
||||
+.RB [ \-\-to\-new | \-N ]
|
||||
+.RB [ \-\-from\-old | \-O ]
|
||||
.RB [ \-\-staged | \-s ]
|
||||
.RB [ \-\-in\-place | \-i ]
|
||||
.RB [ \-\-complete | \-c ]
|
||||
@@ -128,17 +130,36 @@ register can still be used until the mas
|
||||
The \fBNEW\fP register contains the new master key to be set.
|
||||
The master key in the \fBNEW\fP register cannot be used until it is made
|
||||
the current master key. You can pro-actively re-encipher a secure key with the
|
||||
-\fBNEW\fP master key before this key is made the \fBCURRENT\fP key.
|
||||
+\fBNEW\fP master key before this key is made the \fBCURRENT\fP key. Use the
|
||||
+.B \-\-to-new
|
||||
+option to do this.
|
||||
.RE
|
||||
.PP
|
||||
-\fBzkey\-cryptsetup\fP automatically detects whether the secure volume key
|
||||
-is currently enciphered with the master key in the \fBOLD\fP register or with
|
||||
-the master key in the \fBCURRENT\fP register. If currently enciphered with the
|
||||
-master key in the \fBOLD\fP register, it is re-enciphered with the master key
|
||||
-in the \fBCURRENT\fP register. If it is currently enciphered with the master
|
||||
-key in the \fBCURRENT\fP register, it is re-enciphered with the master key in
|
||||
-the \fBNEW\fP register. If for this case the \fBNEW\fP register does not
|
||||
-contain a valid master key, then the re-encipher operation fails.
|
||||
+Use the
|
||||
+.B \-\-from\-old
|
||||
+option to re-encipher a secure volume key that is currently enciphered with
|
||||
+the master key in the \fBOLD\fP register with the master key in the
|
||||
+\fBCURRENT\fP register.
|
||||
+.PP
|
||||
+.PP
|
||||
+If both the
|
||||
+.B \-\-from-old
|
||||
+and
|
||||
+.B \-\-to-new
|
||||
+options are specified, a secure volume key that is currently enciphered
|
||||
+with the master key in the \fBOLD\fP register is re-enciphered with the
|
||||
+master key in the \fBNEW\fP register.
|
||||
+.RE
|
||||
+.PP
|
||||
+If both options are omitted, \fBzkey-cryptsetup\fP automatically detects whether
|
||||
+the secure volume key is currently enciphered with the master key in the
|
||||
+\fBOLD\fP register or with the master key in the \fBCURRENT\fP register.
|
||||
+If currently enciphered with the master key in the \fBOLD\fP register,
|
||||
+it is re-enciphered with the master key in the \fBCURRENT\fP register.
|
||||
+If it is currently enciphered with the master key in the \fBCURRENT\fP
|
||||
+register, it is re-enciphered with the master key in the \fBNEW\fP register.
|
||||
+If for this case the \fBNEW\fP register does not contain a valid master key,
|
||||
+then the re-encipher operation fails.
|
||||
.PP
|
||||
Re-enciphering a secure volume key of a volume encrypted with
|
||||
\fBLUKS2\fP and the \fBpaes\fP cipher can be performed \fBin-place\fP, or in
|
||||
@@ -326,6 +347,16 @@ relevance.
|
||||
.
|
||||
.SS "Options for the reencipher command"
|
||||
.TP
|
||||
+.BR \-N ", " \-\-to\-new
|
||||
+Re-enciphers a secure volume key in the LUKS2 header that is currently
|
||||
+enciphered with the master key in the CURRENT register with the master key in
|
||||
+the NEW register.
|
||||
+.TP
|
||||
+.BR \-O ", " \-\-from\-old
|
||||
+Re-enciphers a secure volume key in the LUKS2 header that is currently
|
||||
+enciphered with the master key in the OLD register with the master key in the
|
||||
+CURRENT register.
|
||||
+.TP
|
||||
.BR \-i ", " \-\-in-place
|
||||
Forces an in-place re-enciphering of a secure volume key in the LUKS2
|
||||
header. This option immediately replaces the secure volume key in the LUKS2
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -95,6 +95,8 @@ static struct zkey_cryptsetup_globals {
|
||||
long long keyfile_offset;
|
||||
long long keyfile_size;
|
||||
long long tries;
|
||||
+ bool tonew;
|
||||
+ bool fromold;
|
||||
bool complete;
|
||||
bool inplace;
|
||||
bool staged;
|
||||
@@ -163,6 +165,22 @@ static struct util_opt opt_vec[] = {
|
||||
.command = COMMAND_REENCIPHER,
|
||||
},
|
||||
{
|
||||
+ .option = {"to-new", 0, NULL, 'N'},
|
||||
+ .desc = "Re-enciphers a secure volume key in the LUKS2 header "
|
||||
+ "that is currently enciphered with the master key in "
|
||||
+ "the CURRENT register with the master key in the NEW "
|
||||
+ "register",
|
||||
+ .command = COMMAND_REENCIPHER,
|
||||
+ },
|
||||
+ {
|
||||
+ .option = {"from-old", 0, NULL, 'O'},
|
||||
+ .desc = "Re-enciphers a secure volume key in the LUKS2 header "
|
||||
+ "that is currently enciphered with the master key in "
|
||||
+ "the OLD register with the master key in the CURRENT "
|
||||
+ "register",
|
||||
+ .command = COMMAND_REENCIPHER,
|
||||
+ },
|
||||
+ {
|
||||
.option = {"staged", 0, NULL, 's'},
|
||||
.desc = "Forces that the re-enciphering of a secure volume "
|
||||
"key in the LUKS2 header is performed in staged mode",
|
||||
@@ -1572,13 +1590,28 @@ static int reencipher_prepare(int token)
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
- util_asprintf(&msg, "The secure volume key of device '%s' is "
|
||||
- "enciphered with the %s CCA master key and is being "
|
||||
- "re-enciphered with the %s CCA master key.",
|
||||
- g.pos_arg, is_old_mk ? "OLD" : "CURRENT",
|
||||
- is_old_mk ? "CURRENT" : "NEW");
|
||||
- util_print_indented(msg, 0);
|
||||
- free(msg);
|
||||
+ if (!g.fromold && !g.tonew) {
|
||||
+ /* Autodetect reencipher mode */
|
||||
+ if (is_old_mk) {
|
||||
+ g.fromold = 1;
|
||||
+ util_asprintf(&msg, "The secure volume key of device "
|
||||
+ "'%s' is enciphered with the OLD CCA "
|
||||
+ "master key and is being re-enciphered "
|
||||
+ "with the CURRENT CCA master key.",
|
||||
+ g.pos_arg);
|
||||
+ util_print_indented(msg, 0);
|
||||
+ free(msg);
|
||||
+ } else {
|
||||
+ g.tonew = 1;
|
||||
+ util_asprintf(&msg, "The secure volume key of device "
|
||||
+ "'%s' is enciphered with the CURRENT CCA "
|
||||
+ "master key and is being re-enciphered "
|
||||
+ "with the NEW CCA master key.",
|
||||
+ g.pos_arg);
|
||||
+ util_print_indented(msg, 0);
|
||||
+ free(msg);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
rc = get_master_key_verification_pattern((u8 *)key, keysize, &mkvp,
|
||||
g.verbose);
|
||||
@@ -1588,36 +1621,64 @@ static int reencipher_prepare(int token)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
- is_old_mk ? FLAG_SEL_CCA_MATCH_OLD_MKVP
|
||||
- : FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
- FLAG_SEL_CCA_NEW_MUST_BE_SET,
|
||||
- g.verbose);
|
||||
- if (rc == -ENOTSUP) {
|
||||
- rc = 0;
|
||||
- selected = 0;
|
||||
- }
|
||||
- if (rc != 0) {
|
||||
- util_asprintf(&msg, "No APQN found that is suitable for "
|
||||
- "re-enciphering the secure AES volume key%s",
|
||||
- !is_old_mk ? " and has the NEW master key loaded"
|
||||
- : "");
|
||||
- util_print_indented(msg, 0);
|
||||
- free(msg);
|
||||
- goto out;
|
||||
+ if (g.fromold) {
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_OLD_MKVP,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_print_indented("No APQN found that is suitable "
|
||||
+ "for re-enciphering the secure AES "
|
||||
+ "volume key from the OLD to the "
|
||||
+ "CURRENT CCA master key.", 0);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
+ METHOD_OLD_TO_CURRENT, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to re-encipher the secure volume key of "
|
||||
+ "device '%s'\n", g.pos_arg);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars(
|
||||
+ "secure AES volume key");
|
||||
+ rc = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
- rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
- is_old_mk ? METHOD_OLD_TO_CURRENT :
|
||||
- METHOD_CURRENT_TO_NEW,
|
||||
- g.verbose);
|
||||
- if (rc != 0) {
|
||||
- warnx("Failed to re-encipher the secure volume key of device "
|
||||
- "'%s'\n", g.pos_arg);
|
||||
- if (!selected)
|
||||
- print_msg_for_cca_envvars("secure AES volume key");
|
||||
- rc = -EINVAL;
|
||||
- goto out;
|
||||
+ if (g.tonew) {
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
+ FLAG_SEL_CCA_NEW_MUST_BE_SET,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ util_print_indented("No APQN found that is suitable "
|
||||
+ "for re-enciphering the secure AES "
|
||||
+ "volume key from the CURRENT to "
|
||||
+ "the NEW CCA master key.", 0);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = key_token_change(&g.cca, (u8 *)key, keysize,
|
||||
+ METHOD_CURRENT_TO_NEW,
|
||||
+ g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to re-encipher the secure volume key of "
|
||||
+ "device '%s'\n", g.pos_arg);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars(
|
||||
+ "secure AES volume key");
|
||||
+ rc = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
rc = crypt_keyslot_add_by_key(g.cd, CRYPT_ANY_SLOT, key, keysize,
|
||||
@@ -2276,6 +2337,12 @@ int main(int argc, char *argv[])
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c) {
|
||||
+ case 'N':
|
||||
+ g.tonew = 1;
|
||||
+ break;
|
||||
+ case 'O':
|
||||
+ g.fromold = 1;
|
||||
+ break;
|
||||
case 'c':
|
||||
g.complete = 1;
|
||||
break;
|
@ -1,50 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] lib/zt_common: add STATIC_ASSERT macro
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: bac3f93772bdf8618c2c9677c59569d70e4a39c0
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
lib/zt_common: add STATIC_ASSERT macro
|
||||
|
||||
Add `STATIC_ASSERT` macro that uses `_Static_assert` if available (was
|
||||
introduced with gcc 4.6, see https://gcc.gnu.org/wiki/C11Status). For
|
||||
example, this could be used for the verification of structure sizes at
|
||||
compile time.
|
||||
|
||||
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/zt_common.h | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -22,6 +22,13 @@
|
||||
# define UNUSED(x) x
|
||||
#endif
|
||||
|
||||
+#ifdef STATIC_ASSERT
|
||||
+#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ >= 5)
|
||||
+# define STATIC_ASSERT(test) _Static_assert((test), "(" #test ") failed");
|
||||
+#else
|
||||
+# define STATIC_ASSERT(test)
|
||||
+#endif
|
||||
+
|
||||
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
@ -1,202 +0,0 @@
|
||||
Subject: zkey: Display key type with list and validate commands
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 9de85f42951e0b1a3d083363d7000b1950aebcd7
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Display key type with list and validate commands
|
||||
|
||||
For the 'zkey list', 'zkey validate' and 'zkey-cryptsetup validate'
|
||||
commands, display the key type.
|
||||
|
||||
As of today there is only one possible key type (CCA-AESDATA),
|
||||
but in the future there might be additional key types.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 7 +++++++
|
||||
zkey/pkey.c | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
zkey/pkey.h | 17 +++++++++++++++++
|
||||
zkey/zkey-cryptsetup.c | 2 ++
|
||||
zkey/zkey.c | 2 ++
|
||||
5 files changed, 67 insertions(+)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -77,6 +77,7 @@ struct key_filenames {
|
||||
#define REC_SEC_KEY_SIZE "Secure key size"
|
||||
#define REC_CLR_KEY_SIZE "Clear key size"
|
||||
#define REC_XTS "XTS type key"
|
||||
+#define REC_KEY_TYPE "Key type"
|
||||
#define REC_VOLUMES "Volumes"
|
||||
#define REC_APQNS "APQNs"
|
||||
#define REC_KEY_FILE "Key file name"
|
||||
@@ -2140,6 +2141,7 @@ static struct util_rec *_keystore_setup_
|
||||
util_rec_def(rec, REC_CLR_KEY_SIZE, UTIL_REC_ALIGN_LEFT, 20,
|
||||
REC_CLR_KEY_SIZE);
|
||||
util_rec_def(rec, REC_XTS, UTIL_REC_ALIGN_LEFT, 3, REC_XTS);
|
||||
+ util_rec_def(rec, REC_KEY_TYPE, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_TYPE);
|
||||
if (validation)
|
||||
util_rec_def(rec, REC_MASTERKEY, UTIL_REC_ALIGN_LEFT, 54,
|
||||
REC_MASTERKEY);
|
||||
@@ -2178,6 +2180,7 @@ static void _keystore_print_record(struc
|
||||
char *description;
|
||||
char *volume_type;
|
||||
char *reencipher;
|
||||
+ char *key_type;
|
||||
char *creation;
|
||||
char *volumes;
|
||||
char *change;
|
||||
@@ -2212,6 +2215,7 @@ static void _keystore_print_record(struc
|
||||
reencipher = properties_get(properties, PROP_NAME_REENC_TIME);
|
||||
vp = properties_get(properties, PROP_NAME_KEY_VP);
|
||||
volume_type = _keystore_get_volume_type(properties);
|
||||
+ key_type = properties_get(properties, PROP_NAME_KEY_TYPE);
|
||||
|
||||
util_rec_set(rec, REC_KEY, name);
|
||||
if (validation)
|
||||
@@ -2226,6 +2230,7 @@ static void _keystore_print_record(struc
|
||||
util_rec_set(rec, REC_CLR_KEY_SIZE, "(unknown)");
|
||||
util_rec_set(rec, REC_XTS,
|
||||
IS_XTS(secure_key_size) ? "Yes" : "No");
|
||||
+ util_rec_set(rec, REC_KEY_TYPE, key_type);
|
||||
if (validation) {
|
||||
if (valid)
|
||||
util_rec_set(rec, REC_MASTERKEY,
|
||||
@@ -2290,6 +2295,8 @@ static void _keystore_print_record(struc
|
||||
free(vp);
|
||||
if (volume_type != NULL)
|
||||
free(volume_type);
|
||||
+ if (key_type != NULL)
|
||||
+ free(key_type);
|
||||
}
|
||||
|
||||
struct validate_info {
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -790,3 +790,42 @@ int get_master_key_verification_pattern(
|
||||
|
||||
return 0;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Check if the specified key is a CCA AESDATA key token.
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ *
|
||||
+ * @returns true if the key is an CCA AESDATA token type
|
||||
+ */
|
||||
+bool is_cca_aes_data_key(const u8 *key, size_t key_size)
|
||||
+{
|
||||
+ struct tokenheader *hdr = (struct tokenheader *)key;
|
||||
+
|
||||
+ if (key == NULL || key_size < SECURE_KEY_SIZE)
|
||||
+ return false;
|
||||
+
|
||||
+ if (hdr->type != TOKEN_TYPE_CCA_INTERNAL)
|
||||
+ return false;
|
||||
+ if (hdr->version != TOKEN_VERSION_AESDATA)
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Returns the type of the key
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ *
|
||||
+ * @returns a static string on success, NULL in case of an error
|
||||
+ */
|
||||
+const char *get_key_type(const u8 *key, size_t key_size)
|
||||
+{
|
||||
+ if (is_cca_aes_data_key(key, key_size))
|
||||
+ return KEY_TYPE_CCA_AESDATA;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -18,6 +18,18 @@
|
||||
/*
|
||||
* Definitions for the /dev/pkey kernel module interface
|
||||
*/
|
||||
+struct tokenheader {
|
||||
+ u8 type;
|
||||
+ u8 res0[3];
|
||||
+ u8 version;
|
||||
+ u8 res1[3];
|
||||
+} __packed;
|
||||
+
|
||||
+#define TOKEN_TYPE_NON_CCA 0x00
|
||||
+#define TOKEN_TYPE_CCA_INTERNAL 0x01
|
||||
+
|
||||
+#define TOKEN_VERSION_AESDATA 0x04
|
||||
+
|
||||
struct secaeskeytoken {
|
||||
u8 type; /* 0x01 for internal key token */
|
||||
u8 res0[3];
|
||||
@@ -82,6 +94,8 @@ struct pkey_verifykey {
|
||||
|
||||
#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
|
||||
|
||||
+#define KEY_TYPE_CCA_AESDATA "CCA-AESDATA"
|
||||
+
|
||||
#define PAES_BLOCK_SIZE 16
|
||||
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
|
||||
#define VERIFICATION_PATTERN_LEN (2 * ENC_ZERO_LEN + 1)
|
||||
@@ -116,4 +130,7 @@ int get_master_key_verification_pattern(
|
||||
size_t secure_key_size, u64 *mkvp,
|
||||
bool verbose);
|
||||
|
||||
+bool is_cca_aes_data_key(const u8 *key, size_t key_size);
|
||||
+const char *get_key_type(const u8 *key, size_t key_size);
|
||||
+
|
||||
#endif
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -1999,6 +1999,8 @@ static int command_validate(void)
|
||||
printf(" Secure key size: %lu bytes\n", keysize);
|
||||
printf(" XTS type key: %s\n",
|
||||
keysize > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
+ printf(" Key type: %s\n",
|
||||
+ get_key_type((u8 *)key, keysize));
|
||||
if (is_valid) {
|
||||
printf(" Clear key size: %lu bits\n", clear_keysize);
|
||||
printf(" Enciphered with: %s CCA master key (MKVP: "
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1416,6 +1416,8 @@ static int command_validate_file(void)
|
||||
printf("Validation of secure key in file '%s':\n", g.pos_arg);
|
||||
printf(" Status: Valid\n");
|
||||
printf(" Secure key size: %lu bytes\n", secure_key_size);
|
||||
+ printf(" Key type: %s\n",
|
||||
+ get_key_type(secure_key, secure_key_size));
|
||||
printf(" Clear key size: %lu bits\n", clear_key_size);
|
||||
printf(" XTS type key: %s\n",
|
||||
secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
|
@ -1,91 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: use STATIC_ASSERT macro for no padding verification
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: cc16e41595d6dcb942f84443f27a1b52d06d17da
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: use STATIC_ASSERT macro for no padding verification
|
||||
|
||||
A simple comment above the struct declaration to indicate that the
|
||||
structure must not have any padding is prone to error. Therefore let's
|
||||
add a check for the structure size at compile time.
|
||||
|
||||
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/sclp.h | 2 ++
|
||||
zipl/boot/sclp_stage3.h | 2 ++
|
||||
zipl/boot/stage3.h | 4 ++++
|
||||
3 files changed, 8 insertions(+)
|
||||
|
||||
--- a/zipl/boot/sclp.h
|
||||
+++ b/zipl/boot/sclp.h
|
||||
@@ -60,6 +60,7 @@ struct sccb_header {
|
||||
uint8_t control_mask[3];
|
||||
uint16_t response_code;
|
||||
};
|
||||
+STATIC_ASSERT(sizeof(struct sccb_header) == 2 + 1 + 3 + 2)
|
||||
|
||||
/* Structure must not have any padding */
|
||||
struct evbuf_header {
|
||||
@@ -68,6 +69,7 @@ struct evbuf_header {
|
||||
uint8_t flags;
|
||||
uint16_t _reserved;
|
||||
};
|
||||
+STATIC_ASSERT(sizeof(struct evbuf_header) == 2 + 1 + 1 + 2)
|
||||
|
||||
struct mto {
|
||||
uint16_t length;
|
||||
--- a/zipl/boot/sclp_stage3.h
|
||||
+++ b/zipl/boot/sclp_stage3.h
|
||||
@@ -42,6 +42,8 @@ struct sdias_sccb {
|
||||
struct sccb_header header;
|
||||
struct sdias_evbuf evbuf;
|
||||
};
|
||||
+STATIC_ASSERT(sizeof(struct sdias_sccb) ==
|
||||
+ sizeof(struct sccb_header) + sizeof(struct sdias_evbuf))
|
||||
|
||||
|
||||
int sclp_hsa_copy(void *, unsigned long, unsigned long);
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "libc.h"
|
||||
#include "s390.h"
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
#define IPL_DEVICE 0x10404UL
|
||||
#define INITRD_START 0x10408UL
|
||||
#define INITRD_SIZE 0x10410UL
|
||||
@@ -128,6 +130,7 @@ struct ipl_rb_hdr {
|
||||
uint8_t rbt;
|
||||
uint8_t reserved1[11];
|
||||
};
|
||||
+STATIC_ASSERT(sizeof(struct ipl_rb_hdr) == 4 + 1 + 11)
|
||||
|
||||
/* IPL Report Block types */
|
||||
enum ipl_rbt {
|
||||
@@ -168,6 +171,7 @@ struct ipl_rb_components {
|
||||
uint8_t reserved1[11];
|
||||
struct ipl_rb_component_entry entries[];
|
||||
};
|
||||
+STATIC_ASSERT(sizeof(struct ipl_rb_components) == 4 + 1 + 11)
|
||||
|
||||
extern unsigned long long _parm_addr; /* address of parmline */
|
||||
extern unsigned long long _initrd_addr; /* address of initrd */
|
@ -1,331 +0,0 @@
|
||||
Subject: zkey: Allow to filter list output by key type
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 91c35543ca7fd25691487c61ec2e308f2903a6b8
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Allow to filter list output by key type
|
||||
|
||||
The zkey list command now accepts option --key-type|-K type
|
||||
to filter the displayed keys by key type. If not specified,
|
||||
then all key types are displayed.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++------
|
||||
zkey/keystore.h | 2 -
|
||||
zkey/zkey.1 | 9 ++++-
|
||||
zkey/zkey.c | 15 +++++++-
|
||||
4 files changed, 112 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -315,6 +315,39 @@ static char *_keystore_get_volume_type(s
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Returns the key type contained in the properties. If no key type
|
||||
+ * property is contained, then 'CCA-AESDATA' is assumed (for backward
|
||||
+ * compatibility).
|
||||
+ *
|
||||
+ * @returns a string containing the key type. Must be freed by the caller.
|
||||
+ */
|
||||
+static char *_keystore_get_key_type(struct properties *properties)
|
||||
+{
|
||||
+ char *type;
|
||||
+
|
||||
+ type = properties_get(properties, PROP_NAME_KEY_TYPE);
|
||||
+ if (type == NULL)
|
||||
+ type = util_strdup(KEY_TYPE_CCA_AESDATA);
|
||||
+
|
||||
+ return type;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Checks if the key type is supported.
|
||||
+ *
|
||||
+ * @param[in] key_type the key type
|
||||
+ *
|
||||
+ * @returns 1 if the key type is valid, 0 otherwise
|
||||
+ */
|
||||
+static int _keystore_valid_key_type(const char *key_type)
|
||||
+{
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0)
|
||||
+ return 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Prints a message followed by a list of associated volumes, if volumes are
|
||||
* associated and the volume-type matches (if specified)
|
||||
*
|
||||
@@ -817,6 +850,33 @@ static int _keystore_match_volume_type_p
|
||||
return rc;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * Checks if the key type property matches the specified key type.
|
||||
+ * If the properties do not contain a key type property, then the default
|
||||
+ * key type is assumed.
|
||||
+ *
|
||||
+ * @param[in] properties a properties object
|
||||
+ * @param[in] key_type the key type to match. Can be NULL. In this case
|
||||
+ * it always matches.
|
||||
+ *
|
||||
+ * @returns 1 for a match, 0 for not matched
|
||||
+ */
|
||||
+static int _keystore_match_key_type_property(struct properties *properties,
|
||||
+ const char *key_type)
|
||||
+{
|
||||
+ char *type;
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ if (key_type == NULL)
|
||||
+ return 1;
|
||||
+
|
||||
+ type = _keystore_get_key_type(properties);
|
||||
+ if (strcasecmp(type, key_type) == 0)
|
||||
+ rc = 1;
|
||||
+
|
||||
+ free(type);
|
||||
+ return rc;
|
||||
+}
|
||||
|
||||
/**
|
||||
* Checks if a key name matches a name filter
|
||||
@@ -882,6 +942,7 @@ typedef int (*process_key_t)(struct keys
|
||||
* mutliple APQN filters separated by commas.
|
||||
* NULL means no APQN filter.
|
||||
* @param[in] volume_type If not NULL, specifies the volume type.
|
||||
+ * @param[in] key_type The key type. NULL means no key type filter.
|
||||
* @param[in] process_func the callback function called for a matching key
|
||||
* @param[in/out] process_private private data passed to the process_func
|
||||
*
|
||||
@@ -894,6 +955,7 @@ static int _keystore_process_filtered(st
|
||||
const char *volume_filter,
|
||||
const char *apqn_filter,
|
||||
const char *volume_type,
|
||||
+ const char *key_type,
|
||||
process_key_t process_func,
|
||||
void *process_private)
|
||||
{
|
||||
@@ -985,6 +1047,15 @@ static int _keystore_process_filtered(st
|
||||
goto free_prop;
|
||||
}
|
||||
|
||||
+ rc = _keystore_match_key_type_property(key_props,
|
||||
+ key_type);
|
||||
+ if (rc == 0) {
|
||||
+ pr_verbose(keystore,
|
||||
+ "Key '%s' filtered out due to key type",
|
||||
+ name);
|
||||
+ goto free_prop;
|
||||
+ }
|
||||
+
|
||||
rc = process_func(keystore, name, key_props, &file_names,
|
||||
process_private);
|
||||
if (rc != 0) {
|
||||
@@ -1193,7 +1264,7 @@ static int _keystore_volume_check(const
|
||||
|
||||
info->set = set;
|
||||
rc = _keystore_process_filtered(info->keystore, NULL, info->volume,
|
||||
- NULL, NULL,
|
||||
+ NULL, NULL, NULL,
|
||||
_keystore_volume_check_process, info);
|
||||
out:
|
||||
free((void *)info->volume);
|
||||
@@ -1454,7 +1525,8 @@ static int _keystore_set_default_propert
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = properties_set(key_props, PROP_NAME_KEY_TYPE, "CCA-AESDATA");
|
||||
+ rc = properties_set(key_props, PROP_NAME_KEY_TYPE,
|
||||
+ KEY_TYPE_CCA_AESDATA);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
@@ -2498,7 +2570,7 @@ int keystore_validate_key(struct keystor
|
||||
info.num_warnings = 0;
|
||||
|
||||
rc = _keystore_process_filtered(keystore, name_filter, NULL,
|
||||
- apqn_filter, NULL,
|
||||
+ apqn_filter, NULL, NULL,
|
||||
_keystore_process_validate, &info);
|
||||
|
||||
util_rec_free(rec);
|
||||
@@ -2877,7 +2949,7 @@ int keystore_reencipher_key(struct keyst
|
||||
info.num_skipped = 0;
|
||||
|
||||
rc = _keystore_process_filtered(keystore, name_filter, NULL,
|
||||
- apqn_filter, NULL,
|
||||
+ apqn_filter, NULL, NULL,
|
||||
_keystore_process_reencipher, &info);
|
||||
|
||||
if (rc != 0) {
|
||||
@@ -3258,12 +3330,13 @@ out:
|
||||
* mutliple APQN filters separated by commas.
|
||||
* NULL means no APQN filter.
|
||||
* @param[in] volume_type The volume type. NULL means no volume type filter.
|
||||
+ * @param[in] key_type The key type. NULL means no key type filter.
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
*/
|
||||
int keystore_list_keys(struct keystore *keystore, const char *name_filter,
|
||||
const char *volume_filter, const char *apqn_filter,
|
||||
- const char *volume_type)
|
||||
+ const char *volume_type, const char *key_type)
|
||||
{
|
||||
struct util_rec *rec;
|
||||
int rc;
|
||||
@@ -3276,10 +3349,16 @@ int keystore_list_keys(struct keystore *
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ if (key_type != NULL &&
|
||||
+ !_keystore_valid_key_type(key_type)) {
|
||||
+ warnx("Invalid key-type specified");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
rec = _keystore_setup_record(0);
|
||||
|
||||
rc = _keystore_process_filtered(keystore, name_filter, volume_filter,
|
||||
- apqn_filter, volume_type,
|
||||
+ apqn_filter, volume_type, key_type,
|
||||
_keystore_display_key, rec);
|
||||
util_rec_free(rec);
|
||||
|
||||
@@ -3773,8 +3852,8 @@ int keystore_cryptsetup(struct keystore
|
||||
info.process_func = _keystore_process_cryptsetup;
|
||||
|
||||
rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL,
|
||||
- volume_type, _keystore_process_crypt,
|
||||
- &info);
|
||||
+ volume_type, NULL,
|
||||
+ _keystore_process_crypt, &info);
|
||||
|
||||
str_list_free_string_array(info.volume_filter);
|
||||
|
||||
@@ -3834,8 +3913,8 @@ int keystore_crypttab(struct keystore *k
|
||||
info.process_func = _keystore_process_crypttab;
|
||||
|
||||
rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL,
|
||||
- volume_type, _keystore_process_crypt,
|
||||
- &info);
|
||||
+ volume_type, NULL,
|
||||
+ _keystore_process_crypt, &info);
|
||||
|
||||
str_list_free_string_array(info.volume_filter);
|
||||
|
||||
--- a/zkey/keystore.h
|
||||
+++ b/zkey/keystore.h
|
||||
@@ -68,7 +68,7 @@ int keystore_remove_key(struct keystore
|
||||
|
||||
int keystore_list_keys(struct keystore *keystore, const char *name_filter,
|
||||
const char *volume_filter, const char *apqn_filter,
|
||||
- const char *volume_type);
|
||||
+ const char *volume_type, const char *key_type);
|
||||
|
||||
int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter,
|
||||
bool execute, const char *volume_type,
|
||||
--- a/zkey/zkey.1
|
||||
+++ b/zkey/zkey.1
|
||||
@@ -368,6 +368,8 @@ The exported secure key also remains in
|
||||
.IR card1.domain1[,card2.domain2[,...]] ]
|
||||
.RB [ \-\-volume-type | \-t
|
||||
.IR type ]
|
||||
+.RB [ \-\-key-type | \-K
|
||||
+.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -382,7 +384,7 @@ listed that are associated with the spec
|
||||
.PP
|
||||
The
|
||||
.B list
|
||||
-command displays the attributes of the secure keys, such as key sizes,
|
||||
+command displays the attributes of the secure keys, such as key sizes, key type,
|
||||
whether it is a secure key that can be used for the XTS cipher mode, the textual
|
||||
description, associated cryptographic adapters (APQNs) and volumes, the
|
||||
sector size, the key verification pattern, and timestamps for key creation, last
|
||||
@@ -907,6 +909,11 @@ This option is only available if
|
||||
.B zkey
|
||||
has been compiled with LUKS2 support enabled.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
+.TP
|
||||
+.BR \-K ", " \-\-key-type\~\fItype\fP
|
||||
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
|
||||
+Only keys with the specified key type are listed.
|
||||
+This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
.
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -73,6 +73,7 @@ static struct zkey_globals {
|
||||
long int sector_size;
|
||||
char *volume_type;
|
||||
char *newname;
|
||||
+ char *key_type;
|
||||
bool run;
|
||||
bool batch_mode;
|
||||
char *keyfile;
|
||||
@@ -432,6 +433,15 @@ static struct util_opt opt_vec[] = {
|
||||
.command = COMMAND_LIST,
|
||||
},
|
||||
#endif
|
||||
+ {
|
||||
+ .option = { "key-type", required_argument, NULL, 'K'},
|
||||
+ .argument = "type",
|
||||
+ .desc = "The type of the key. Possible values are '"
|
||||
+ KEY_TYPE_CCA_AESDATA"'. "
|
||||
+ "Use this option to list all keys with the specified "
|
||||
+ "key type.",
|
||||
+ .command = COMMAND_LIST,
|
||||
+ },
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -1532,7 +1542,7 @@ static int command_list(void)
|
||||
int rc;
|
||||
|
||||
rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns,
|
||||
- g.volume_type);
|
||||
+ g.volume_type, g.key_type);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1853,6 +1863,9 @@ int main(int argc, char *argv[])
|
||||
case 'r':
|
||||
g.run = 1;
|
||||
break;
|
||||
+ case 'K':
|
||||
+ g.key_type = optarg;
|
||||
+ break;
|
||||
case 'F':
|
||||
g.force = 1;
|
||||
break;
|
@ -1,65 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] Support `lib/zt_common.h` to be used in assembler and add `_AC` macro
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 400167f5128a14ba48b0d05b7b777b42c450c73f
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
Support `lib/zt_common.h` to be used in assembler and add `_AC` macro
|
||||
|
||||
Support `lib/zt_common.h` to be used in assembler files. In addition,
|
||||
add the macro `_AC` that can be used to make constant macros usable in
|
||||
both assembler and C code.
|
||||
|
||||
Suggested-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/zt_common.h | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -15,6 +15,21 @@
|
||||
#define STRINGIFY_1(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_1(x)
|
||||
|
||||
+/* Use this macro to make constant macros usable in both assembler and
|
||||
+ * C code.
|
||||
+ *
|
||||
+ * Usage example:
|
||||
+ * #define IMAGE_ENTRY _AC(0x10000, UL)
|
||||
+ */
|
||||
+#ifdef __ASSEMBLER__
|
||||
+#define _AC(X, TYPE) X
|
||||
+#else
|
||||
+#define _AC(X, TYPE) X##TYPE
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
#ifdef UNUSED
|
||||
#elif defined(__GNUC__)
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||
@@ -50,4 +65,5 @@ typedef signed short int s16;
|
||||
typedef unsigned char u8;
|
||||
typedef signed char s8;
|
||||
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
#endif /* LIB_ZT_COMMON_H */
|
@ -1,348 +0,0 @@
|
||||
Subject: zkey: Allow to specify the key type with the generate command
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: b47007b8ac8b446eb94b06e7ed3050b3df3e80e8
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Allow to specify the key type with the generate command
|
||||
|
||||
The zkey generate command allows to specify the --key-type|-K
|
||||
option to specify the key type. If not specified, then the
|
||||
default is CCA-AESDATA.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 35 ++++++++++++++++++++++++-----------
|
||||
zkey/keystore.h | 2 +-
|
||||
zkey/pkey.c | 20 +++++++++++++++++---
|
||||
zkey/pkey.h | 6 +++---
|
||||
zkey/zkey.1 | 14 ++++++++++++++
|
||||
zkey/zkey.c | 17 ++++++++++++++---
|
||||
6 files changed, 73 insertions(+), 21 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1525,11 +1525,6 @@ static int _keystore_set_default_propert
|
||||
{
|
||||
int rc;
|
||||
|
||||
- rc = properties_set(key_props, PROP_NAME_KEY_TYPE,
|
||||
- KEY_TYPE_CCA_AESDATA);
|
||||
- if (rc != 0)
|
||||
- return rc;
|
||||
-
|
||||
rc = properties_set(key_props, PROP_NAME_CIPHER, "paes");
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
@@ -1564,6 +1559,7 @@ static int _keystore_set_default_propert
|
||||
* the sector size is not specified and the system
|
||||
* default is used.
|
||||
* @param[in] volume_type the type of volume
|
||||
+ * @param[in] key_type the type of the key
|
||||
*/
|
||||
static int _keystore_create_info_file(struct keystore *keystore,
|
||||
const char *name,
|
||||
@@ -1572,7 +1568,8 @@ static int _keystore_create_info_file(st
|
||||
const char *volumes, const char *apqns,
|
||||
bool noapqncheck,
|
||||
size_t sector_size,
|
||||
- const char *volume_type)
|
||||
+ const char *volume_type,
|
||||
+ const char *key_type)
|
||||
{
|
||||
struct volume_check vol_check = { .keystore = keystore, .name = name,
|
||||
.set = 0 };
|
||||
@@ -1594,6 +1591,12 @@ static int _keystore_create_info_file(st
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ rc = properties_set2(key_props, PROP_NAME_KEY_TYPE, key_type, true);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Invalid characters in key-type");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
rc = _keystore_change_association(key_props, PROP_NAME_VOLUMES,
|
||||
volumes != NULL ? volumes : "",
|
||||
"volume", _keystore_volume_check,
|
||||
@@ -1731,6 +1734,7 @@ out:
|
||||
* clear key contained in the file denoted here.
|
||||
* if NULL, the secure key is generated by random.
|
||||
* @param[in] volume_type the type of volume
|
||||
+ * @param[in] key_type the type of the key
|
||||
* @param[in] pkey_fd the file descriptor of /dev/pkey
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
@@ -1740,7 +1744,7 @@ int keystore_generate_key(struct keystor
|
||||
const char *apqns, bool noapqncheck,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *clear_key_file, const char *volume_type,
|
||||
- int pkey_fd)
|
||||
+ const char *key_type, int pkey_fd)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
@@ -1749,6 +1753,12 @@ int keystore_generate_key(struct keystor
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
util_assert(name != NULL, "Internal error: name is NULL");
|
||||
+ util_assert(key_type != NULL, "Internal error: key_type is NULL");
|
||||
+
|
||||
+ if (!_keystore_valid_key_type(key_type)) {
|
||||
+ warnx("Invalid key-type specified");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
rc = _keystore_get_key_filenames(keystore, name, &file_names);
|
||||
if (rc != 0)
|
||||
@@ -1773,13 +1783,14 @@ int keystore_generate_key(struct keystor
|
||||
if (clear_key_file == NULL)
|
||||
rc = generate_secure_key_random(pkey_fd,
|
||||
file_names.skey_filename,
|
||||
- keybits, xts, card, domain,
|
||||
+ keybits, xts, key_type,
|
||||
+ card, domain,
|
||||
keystore->verbose);
|
||||
else
|
||||
rc = generate_secure_key_clear(pkey_fd,
|
||||
file_names.skey_filename,
|
||||
keybits, xts, clear_key_file,
|
||||
- card, domain,
|
||||
+ key_type, card, domain,
|
||||
keystore->verbose);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
@@ -1790,7 +1801,8 @@ int keystore_generate_key(struct keystor
|
||||
|
||||
rc = _keystore_create_info_file(keystore, name, &file_names,
|
||||
description, volumes, apqns,
|
||||
- noapqncheck, sector_size, volume_type);
|
||||
+ noapqncheck, sector_size, volume_type,
|
||||
+ key_type);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
@@ -1894,7 +1906,8 @@ int keystore_import_key(struct keystore
|
||||
|
||||
rc = _keystore_create_info_file(keystore, name, &file_names,
|
||||
description, volumes, apqns,
|
||||
- noapqncheck, sector_size, volume_type);
|
||||
+ noapqncheck, sector_size, volume_type,
|
||||
+ KEY_TYPE_CCA_AESDATA);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
--- a/zkey/keystore.h
|
||||
+++ b/zkey/keystore.h
|
||||
@@ -32,7 +32,7 @@ int keystore_generate_key(struct keystor
|
||||
const char *apqns, bool noapqncheck,
|
||||
size_t sector_size, size_t keybits, bool xts,
|
||||
const char *clear_key_file, const char *volume_type,
|
||||
- int pkey_fd);
|
||||
+ const char *key_type, int pkey_fd);
|
||||
|
||||
int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -278,6 +278,7 @@ out:
|
||||
* @param[in] keyfile the file name of the secure key to generate
|
||||
* @param[in] keybits the cryptographic size of the key in bits
|
||||
* @param[in] xts if true an XTS key is generated
|
||||
+ * @param[in] key_type the type of the key
|
||||
* @param[in] card the card number to use (or AUTOSELECT)
|
||||
* @param[in] domain the domain number to use (or AUTOSELECT)
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
@@ -285,8 +286,8 @@ out:
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
- size_t keybits, bool xts, u16 card, u16 domain,
|
||||
- bool verbose)
|
||||
+ size_t keybits, bool xts, const char *key_type,
|
||||
+ u16 card, u16 domain, bool verbose)
|
||||
{
|
||||
struct pkey_genseck gensec;
|
||||
size_t secure_key_size;
|
||||
@@ -295,6 +296,12 @@ int generate_secure_key_random(int pkey_
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
|
||||
+ util_assert(key_type != NULL, "Internal error: key_type is NULL");
|
||||
+
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) != 0) {
|
||||
+ warnx("Invalid key-type: %s", key_type);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
if (keybits == 0)
|
||||
keybits = DEFAULT_KEYBITS;
|
||||
@@ -374,6 +381,7 @@ out:
|
||||
* determines the keybits.
|
||||
* @param[in] xts if true an XTS key is generated
|
||||
* @param[in] clearkeyfile the file name of the clear key to read
|
||||
+ * @param[in] key_type the type of the key
|
||||
* @param[in] card the card number to use (or AUTOSELECT)
|
||||
* @param[in] domain the domain number to use (or AUTOSELECT)
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
@@ -382,7 +390,7 @@ out:
|
||||
*/
|
||||
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts,
|
||||
- const char *clearkeyfile,
|
||||
+ const char *clearkeyfile, const char *key_type,
|
||||
u16 card, u16 domain,
|
||||
bool verbose)
|
||||
{
|
||||
@@ -397,6 +405,12 @@ int generate_secure_key_clear(int pkey_f
|
||||
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
|
||||
util_assert(clearkeyfile != NULL,
|
||||
"Internal error: clearkeyfile is NULL");
|
||||
+ util_assert(key_type != NULL, "Internal error: key_type is NULL");
|
||||
+
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) != 0) {
|
||||
+ warnx("Invalid key-type: %s", key_type);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
|
||||
secure_key = util_malloc(secure_key_size);
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -103,12 +103,12 @@ struct pkey_verifykey {
|
||||
int open_pkey_device(bool verbose);
|
||||
|
||||
int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
- size_t keybits, bool xts, u16 card, u16 domain,
|
||||
- bool verbose);
|
||||
+ size_t keybits, bool xts, const char *key_type,
|
||||
+ u16 card, u16 domain, bool verbose);
|
||||
|
||||
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts,
|
||||
- const char *clearkeyfile,
|
||||
+ const char *clearkeyfile, const char *key_type,
|
||||
u16 card, u16 domain,
|
||||
bool verbose);
|
||||
|
||||
--- a/zkey/zkey.1
|
||||
+++ b/zkey/zkey.1
|
||||
@@ -79,6 +79,8 @@ key repository.
|
||||
.RB [ \-\-xts | \-x ]
|
||||
.RB [ \-\-clearkey | \-c
|
||||
.IR clear\-key\-file ]
|
||||
+.RB [ \-\-key-type | \-K
|
||||
+.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.
|
||||
.PP
|
||||
@@ -102,6 +104,8 @@ key repository.
|
||||
.RB [ \-\-xts | \-x ]
|
||||
.RB [ \-\-clearkey | \-c
|
||||
.IR clear\-key\-file ]
|
||||
+.RB [ \-\-key-type | \-K
|
||||
+.IR type ]
|
||||
.RB [ \-\-verbose | \-V ]
|
||||
.PP
|
||||
Use the
|
||||
@@ -129,6 +133,11 @@ additional information can be associated
|
||||
, or the
|
||||
.B \-\-sector-size
|
||||
options.
|
||||
+.PP
|
||||
+You can generate different types of secure keys: \fBCCA-AESDATA\fP keys.
|
||||
+Specify the type of the secure key using the
|
||||
+.B \-\-key\-type
|
||||
+option. The default key type is CCA-AESDATA.
|
||||
.
|
||||
.SS "Validating secure AES keys"
|
||||
.
|
||||
@@ -730,6 +739,11 @@ This option is only available if
|
||||
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
|
||||
the default volume type is \fBplain\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
+.TP
|
||||
+.BR \-K ", " \-\-key-type\~\fItype\fP
|
||||
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
|
||||
+If this option is omitted, then a secure key of type
|
||||
+CCA-AESDATA is generated.
|
||||
.
|
||||
.
|
||||
.
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -217,6 +217,15 @@ static struct util_opt opt_vec[] = {
|
||||
.command = COMMAND_GENERATE,
|
||||
},
|
||||
#endif
|
||||
+ {
|
||||
+ .option = { "key-type", required_argument, NULL, 'K'},
|
||||
+ .argument = "type",
|
||||
+ .desc = "The type of the key. Possible values are '"
|
||||
+ KEY_TYPE_CCA_AESDATA"'. "
|
||||
+ "When this option is omitted, the default is '"
|
||||
+ KEY_TYPE_CCA_AESDATA"'",
|
||||
+ .command = COMMAND_GENERATE,
|
||||
+ },
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
@@ -1019,7 +1028,7 @@ static int command_generate_clear(void)
|
||||
|
||||
rc = generate_secure_key_clear(g.pkey_fd, g.pos_arg,
|
||||
g.keybits, g.xts,
|
||||
- g.clearkeyfile,
|
||||
+ g.clearkeyfile, g.key_type,
|
||||
AUTOSELECT, AUTOSELECT,
|
||||
g.verbose);
|
||||
|
||||
@@ -1036,7 +1045,7 @@ static int command_generate_random(void)
|
||||
int rc;
|
||||
|
||||
rc = generate_secure_key_random(g.pkey_fd, g.pos_arg,
|
||||
- g.keybits, g.xts,
|
||||
+ g.keybits, g.xts, g.key_type,
|
||||
AUTOSELECT, AUTOSELECT,
|
||||
g.verbose);
|
||||
|
||||
@@ -1058,7 +1067,7 @@ static int command_generate_repository(v
|
||||
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.noapqncheck, g.sector_size,
|
||||
g.keybits, g.xts, g.clearkeyfile,
|
||||
- g.volume_type, g.pkey_fd);
|
||||
+ g.volume_type, g.key_type, g.pkey_fd);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1085,6 +1094,8 @@ static int command_generate(void)
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
+ if (g.key_type == NULL)
|
||||
+ g.key_type = KEY_TYPE_CCA_AESDATA;
|
||||
if (g.name != NULL)
|
||||
return command_generate_repository();
|
||||
if (g.pos_arg != NULL) {
|
@ -1,359 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: move IPL related definitions into separate header
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 9d39a4bd47008b15bbf4ebe672b91d6d63888536
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: move IPL related definitions into separate header
|
||||
|
||||
Move the IPL related definitions into `include/boot/ipl.h`. This
|
||||
allows the reuse of the definitions, e.g. in the boot loader for
|
||||
protected guests.
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/ipl.h | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zipl/boot/stage3.h | 140 ----------------------------------------------
|
||||
2 files changed, 160 insertions(+), 139 deletions(-)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/boot/ipl.h
|
||||
@@ -0,0 +1,159 @@
|
||||
+/*
|
||||
+ * IPL related 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 IPL_H
|
||||
+#define IPL_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+#define IPL_FLAG_SECURE 0x40
|
||||
+
|
||||
+#define IPL_RB_COMPONENT_FLAG_SIGNED 0x80
|
||||
+#define IPL_RB_COMPONENT_FLAG_VERIFIED 0x40
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+/* IPL Parameter List header */
|
||||
+struct ipl_pl_hdr {
|
||||
+ uint32_t len;
|
||||
+ uint8_t flags;
|
||||
+ uint8_t reserved1[2];
|
||||
+ uint8_t version;
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Parameter Block header */
|
||||
+struct ipl_pb_hdr {
|
||||
+ uint32_t len;
|
||||
+ uint8_t pbt;
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Parameter Block 0 with common fields */
|
||||
+struct ipl_pb0_common {
|
||||
+ uint32_t len;
|
||||
+ uint8_t pbt;
|
||||
+ uint8_t flags;
|
||||
+ uint8_t reserved1[2];
|
||||
+ uint8_t loadparm[8];
|
||||
+ uint8_t reserved2[84];
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Parameter Block 0 for FCP */
|
||||
+struct ipl_pb0_fcp {
|
||||
+ uint32_t len;
|
||||
+ uint8_t pbt;
|
||||
+ uint8_t reserved1[3];
|
||||
+ uint8_t loadparm[8];
|
||||
+ uint8_t reserved2[304];
|
||||
+ uint8_t opt;
|
||||
+ uint8_t reserved3[3];
|
||||
+ uint8_t cssid;
|
||||
+ uint8_t reserved4[1];
|
||||
+ uint8_t devno;
|
||||
+ uint8_t reserved5[4];
|
||||
+ uint64_t wwpn;
|
||||
+ uint64_t lun;
|
||||
+ uint32_t bootprog;
|
||||
+ uint8_t reserved6[12];
|
||||
+ uint64_t br_lba;
|
||||
+ uint32_t scp_data_len;
|
||||
+ uint8_t reserved7[260];
|
||||
+ uint8_t scp_data[];
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Parameter Block 0 for CCW */
|
||||
+struct ipl_pb0_ccw {
|
||||
+ uint32_t len;
|
||||
+ uint8_t pbt;
|
||||
+ uint8_t flags;
|
||||
+ uint8_t reserved1[2];
|
||||
+ uint8_t loadparm[8];
|
||||
+ uint8_t reserved2[84];
|
||||
+ uint16_t reserved3 : 13;
|
||||
+ uint8_t ssid : 3;
|
||||
+ uint16_t devno;
|
||||
+ uint8_t vm_flags;
|
||||
+ uint8_t reserved4[3];
|
||||
+ uint32_t vm_parm_len;
|
||||
+ uint8_t nss_name[8];
|
||||
+ uint8_t vm_parm[64];
|
||||
+ uint8_t reserved5[8];
|
||||
+} __packed;
|
||||
+
|
||||
+struct ipl_parameter_block {
|
||||
+ struct ipl_pl_hdr hdr;
|
||||
+ union {
|
||||
+ struct ipl_pb_hdr pb0_hdr;
|
||||
+ struct ipl_pb0_common common;
|
||||
+ struct ipl_pb0_fcp fcp;
|
||||
+ struct ipl_pb0_ccw ccw;
|
||||
+ char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
|
||||
+ };
|
||||
+} __packed __aligned(PAGE_SIZE);
|
||||
+
|
||||
+/* IPL Report List header */
|
||||
+struct ipl_rl_hdr {
|
||||
+ uint32_t len;
|
||||
+ uint8_t flags;
|
||||
+ uint8_t reserved1[2];
|
||||
+ uint8_t version;
|
||||
+ uint8_t reserved2[8];
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Report Block header */
|
||||
+/* Structure must not have any padding */
|
||||
+struct ipl_rb_hdr {
|
||||
+ uint32_t len;
|
||||
+ uint8_t rbt;
|
||||
+ uint8_t reserved1[11];
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct ipl_rb_hdr) == 4 + 1 + 11)
|
||||
+
|
||||
+/* IPL Report Block types */
|
||||
+enum ipl_rbt {
|
||||
+ IPL_RBT_CERTIFICATES = 1,
|
||||
+ IPL_RBT_COMPONENTS = 2,
|
||||
+};
|
||||
+
|
||||
+/* IPL Report Block for the certificate list */
|
||||
+struct ipl_rb_certificate_entry {
|
||||
+ uint64_t addr;
|
||||
+ uint64_t len;
|
||||
+} __packed;
|
||||
+
|
||||
+struct ipl_rb_certificates {
|
||||
+ uint32_t len;
|
||||
+ uint8_t rbt;
|
||||
+ uint8_t reserved1[11];
|
||||
+ struct ipl_rb_certificate_entry entries[];
|
||||
+} __packed;
|
||||
+
|
||||
+/* IPL Report Block for the component list */
|
||||
+struct ipl_rb_component_entry {
|
||||
+ uint64_t addr;
|
||||
+ uint64_t len;
|
||||
+ uint8_t flags;
|
||||
+ uint8_t reserved1[5];
|
||||
+ uint16_t certificate_index;
|
||||
+ uint8_t reserved2[8];
|
||||
+};
|
||||
+
|
||||
+/* Structure must not have any padding */
|
||||
+struct ipl_rb_components {
|
||||
+ uint32_t len;
|
||||
+ uint8_t rbt;
|
||||
+ uint8_t reserved1[11];
|
||||
+ struct ipl_rb_component_entry entries[];
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct ipl_rb_components) == 4 + 1 + 11)
|
||||
+
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* IPL_H */
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "libc.h"
|
||||
#include "s390.h"
|
||||
|
||||
-#include "lib/zt_common.h"
|
||||
+#include "boot/ipl.h"
|
||||
|
||||
#define IPL_DEVICE 0x10404UL
|
||||
#define INITRD_START 0x10408UL
|
||||
@@ -29,150 +29,12 @@
|
||||
#define STAGE3_FLAG_SCSI 0x0001000000000000ULL
|
||||
#define STAGE3_FLAG_KDUMP 0x0002000000000000ULL
|
||||
|
||||
-#define IPL_FLAG_SECURE 0x40
|
||||
-
|
||||
#define DEFAULT_PSW_LOAD 0x0008000080010000UL
|
||||
#define PSW_ADDR_MASK 0x000000007FFFFFFFUL
|
||||
|
||||
#define UNSPECIFIED_ADDRESS -1UL
|
||||
|
||||
|
||||
-/* IPL Parameter List header */
|
||||
-struct ipl_pl_hdr {
|
||||
- uint32_t len;
|
||||
- uint8_t flags;
|
||||
- uint8_t reserved1[2];
|
||||
- uint8_t version;
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Parameter Block header */
|
||||
-struct ipl_pb_hdr {
|
||||
- uint32_t len;
|
||||
- uint8_t pbt;
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Parameter Block 0 with common fields */
|
||||
-struct ipl_pb0_common {
|
||||
- uint32_t len;
|
||||
- uint8_t pbt;
|
||||
- uint8_t flags;
|
||||
- uint8_t reserved1[2];
|
||||
- uint8_t loadparm[8];
|
||||
- uint8_t reserved2[84];
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Parameter Block 0 for FCP */
|
||||
-struct ipl_pb0_fcp {
|
||||
- uint32_t len;
|
||||
- uint8_t pbt;
|
||||
- uint8_t reserved1[3];
|
||||
- uint8_t loadparm[8];
|
||||
- uint8_t reserved2[304];
|
||||
- uint8_t opt;
|
||||
- uint8_t reserved3[3];
|
||||
- uint8_t cssid;
|
||||
- uint8_t reserved4[1];
|
||||
- uint8_t devno;
|
||||
- uint8_t reserved5[4];
|
||||
- uint64_t wwpn;
|
||||
- uint64_t lun;
|
||||
- uint32_t bootprog;
|
||||
- uint8_t reserved6[12];
|
||||
- uint64_t br_lba;
|
||||
- uint32_t scp_data_len;
|
||||
- uint8_t reserved7[260];
|
||||
- uint8_t scp_data[];
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Parameter Block 0 for CCW */
|
||||
-struct ipl_pb0_ccw {
|
||||
- uint32_t len;
|
||||
- uint8_t pbt;
|
||||
- uint8_t flags;
|
||||
- uint8_t reserved1[2];
|
||||
- uint8_t loadparm[8];
|
||||
- uint8_t reserved2[84];
|
||||
- uint16_t reserved3 : 13;
|
||||
- uint8_t ssid : 3;
|
||||
- uint16_t devno;
|
||||
- uint8_t vm_flags;
|
||||
- uint8_t reserved4[3];
|
||||
- uint32_t vm_parm_len;
|
||||
- uint8_t nss_name[8];
|
||||
- uint8_t vm_parm[64];
|
||||
- uint8_t reserved5[8];
|
||||
-} __packed;
|
||||
-
|
||||
-struct ipl_parameter_block {
|
||||
- struct ipl_pl_hdr hdr;
|
||||
- union {
|
||||
- struct ipl_pb_hdr pb0_hdr;
|
||||
- struct ipl_pb0_common common;
|
||||
- struct ipl_pb0_fcp fcp;
|
||||
- struct ipl_pb0_ccw ccw;
|
||||
- char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
|
||||
- };
|
||||
-} __packed __aligned(PAGE_SIZE);
|
||||
-
|
||||
-/* IPL Report List header */
|
||||
-struct ipl_rl_hdr {
|
||||
- uint32_t len;
|
||||
- uint8_t flags;
|
||||
- uint8_t reserved1[2];
|
||||
- uint8_t version;
|
||||
- uint8_t reserved2[8];
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Report Block header */
|
||||
-/* Structure must not have any padding */
|
||||
-struct ipl_rb_hdr {
|
||||
- uint32_t len;
|
||||
- uint8_t rbt;
|
||||
- uint8_t reserved1[11];
|
||||
-};
|
||||
-STATIC_ASSERT(sizeof(struct ipl_rb_hdr) == 4 + 1 + 11)
|
||||
-
|
||||
-/* IPL Report Block types */
|
||||
-enum ipl_rbt {
|
||||
- IPL_RBT_CERTIFICATES = 1,
|
||||
- IPL_RBT_COMPONENTS = 2,
|
||||
-};
|
||||
-
|
||||
-/* IPL Report Block for the certificate list */
|
||||
-struct ipl_rb_certificate_entry {
|
||||
- uint64_t addr;
|
||||
- uint64_t len;
|
||||
-} __packed;
|
||||
-
|
||||
-struct ipl_rb_certificates {
|
||||
- uint32_t len;
|
||||
- uint8_t rbt;
|
||||
- uint8_t reserved1[11];
|
||||
- struct ipl_rb_certificate_entry entries[];
|
||||
-} __packed;
|
||||
-
|
||||
-/* IPL Report Block for the component list */
|
||||
-struct ipl_rb_component_entry {
|
||||
- uint64_t addr;
|
||||
- uint64_t len;
|
||||
- uint8_t flags;
|
||||
- uint8_t reserved1[5];
|
||||
- uint16_t certificate_index;
|
||||
- uint8_t reserved2[8];
|
||||
-};
|
||||
-
|
||||
-#define IPL_RB_COMPONENT_FLAG_SIGNED 0x80
|
||||
-#define IPL_RB_COMPONENT_FLAG_VERIFIED 0x40
|
||||
-
|
||||
-/* Structure must not have any padding */
|
||||
-struct ipl_rb_components {
|
||||
- uint32_t len;
|
||||
- uint8_t rbt;
|
||||
- uint8_t reserved1[11];
|
||||
- struct ipl_rb_component_entry entries[];
|
||||
-};
|
||||
-STATIC_ASSERT(sizeof(struct ipl_rb_components) == 4 + 1 + 11)
|
||||
-
|
||||
extern unsigned long long _parm_addr; /* address of parmline */
|
||||
extern unsigned long long _initrd_addr; /* address of initrd */
|
||||
extern unsigned long long _initrd_len; /* length of initrd */
|
@ -1,665 +0,0 @@
|
||||
Subject: zkey: Preparations for introducing a new key type
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 298fab68fee86cb9b1862d60ca274971d4c39638
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Preparations for introducing a new key type
|
||||
|
||||
Introduce helper functions and definitions to allow key type
|
||||
independent code in the keystore implementation
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 4 -
|
||||
zkey/keystore.c | 91 +++++++++++++++----------------------------
|
||||
zkey/pkey.c | 103 ++++++++++++++++++++++++++++++++++++-------------
|
||||
zkey/pkey.h | 17 +++++---
|
||||
zkey/zkey-cryptsetup.c | 27 +++++++-----
|
||||
zkey/zkey.c | 4 -
|
||||
6 files changed, 139 insertions(+), 107 deletions(-)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -215,11 +215,11 @@ int key_token_change(struct cca_lib *cca
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
- if (secure_key_size == 2 * SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size == 2 * AESDATA_KEY_SIZE) {
|
||||
cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
&exit_data_len, exit_data,
|
||||
&rule_array_count, rule_array,
|
||||
- secure_key + SECURE_KEY_SIZE);
|
||||
+ secure_key + AESDATA_KEY_SIZE);
|
||||
|
||||
pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
|
||||
"returned: return_code: %ld, reason_code: %ld",
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -70,8 +70,6 @@ struct key_filenames {
|
||||
#define DEFAULT_VOLUME_TYPE VOLUME_TYPE_PLAIN
|
||||
#endif
|
||||
|
||||
-#define IS_XTS(secure_key_size) (secure_key_size > SECURE_KEY_SIZE ? 1 : 0)
|
||||
-
|
||||
#define REC_KEY "Key"
|
||||
#define REC_DESCRIPTION "Description"
|
||||
#define REC_SEC_KEY_SIZE "Secure key size"
|
||||
@@ -1440,7 +1438,7 @@ static int _keystore_generate_verificati
|
||||
if (key == NULL)
|
||||
return -EIO;
|
||||
|
||||
- rc = generate_key_verification_pattern((const char *)key, key_size,
|
||||
+ rc = generate_key_verification_pattern(key, key_size,
|
||||
vp, vp_len, keystore->verbose);
|
||||
|
||||
free(key);
|
||||
@@ -1854,6 +1852,7 @@ int keystore_import_key(struct keystore
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
size_t secure_key_size;
|
||||
+ const char *key_type;
|
||||
u8 *secure_key;
|
||||
u64 mkvp;
|
||||
int rc;
|
||||
@@ -1877,6 +1876,14 @@ int keystore_import_key(struct keystore
|
||||
goto out_free_key_filenames;
|
||||
}
|
||||
|
||||
+ key_type = get_key_type(secure_key, secure_key_size);
|
||||
+ if (key_type == NULL) {
|
||||
+ warnx("Key '%s' is not a valid secure key", name);
|
||||
+ free(secure_key);
|
||||
+ rc = -EINVAL;
|
||||
+ goto out_free_key_filenames;
|
||||
+ }
|
||||
+
|
||||
rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
&mkvp, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
@@ -1907,7 +1914,7 @@ int keystore_import_key(struct keystore
|
||||
rc = _keystore_create_info_file(keystore, name, &file_names,
|
||||
description, volumes, apqns,
|
||||
noapqncheck, sector_size, volume_type,
|
||||
- KEY_TYPE_CCA_AESDATA);
|
||||
+ key_type);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
|
||||
@@ -2252,7 +2259,7 @@ static void _keystore_print_record(struc
|
||||
const char *name,
|
||||
struct properties *properties,
|
||||
bool validation, const char *skey_filename,
|
||||
- size_t secure_key_size,
|
||||
+ size_t secure_key_size, bool is_xts,
|
||||
size_t clear_key_bitsize, bool valid,
|
||||
bool is_old_mk, bool reenc_pending, u64 mkvp)
|
||||
{
|
||||
@@ -2308,13 +2315,12 @@ static void _keystore_print_record(struc
|
||||
util_rec_set(rec, REC_DESCRIPTION,
|
||||
description != NULL ? description : "");
|
||||
util_rec_set(rec, REC_SEC_KEY_SIZE, "%lu bytes", secure_key_size);
|
||||
- if (!validation || valid)
|
||||
+ if ((!validation || valid) && clear_key_bitsize != 0)
|
||||
util_rec_set(rec, REC_CLR_KEY_SIZE, "%lu bits",
|
||||
clear_key_bitsize);
|
||||
else
|
||||
util_rec_set(rec, REC_CLR_KEY_SIZE, "(unknown)");
|
||||
- util_rec_set(rec, REC_XTS,
|
||||
- IS_XTS(secure_key_size) ? "Yes" : "No");
|
||||
+ util_rec_set(rec, REC_XTS, is_xts ? "Yes" : "No");
|
||||
util_rec_set(rec, REC_KEY_TYPE, key_type);
|
||||
if (validation) {
|
||||
if (valid)
|
||||
@@ -2525,6 +2531,7 @@ static int _keystore_process_validate(st
|
||||
|
||||
_keystore_print_record(info->rec, name, properties, 1,
|
||||
file_names->skey_filename, secure_key_size,
|
||||
+ is_xts_key(secure_key, secure_key_size),
|
||||
clear_key_bitsize, valid, is_old_mk,
|
||||
_keystore_reencipher_key_exists(file_names),
|
||||
mkvp);
|
||||
@@ -3297,29 +3304,29 @@ static int _keystore_display_key(struct
|
||||
void *private)
|
||||
{
|
||||
struct util_rec *rec = (struct util_rec *)private;
|
||||
- struct secaeskeytoken *secure_key;
|
||||
- size_t secure_key_size;
|
||||
+ u8 *secure_key;
|
||||
+ size_t secure_key_size, clear_key_bitsize = 0;
|
||||
int rc = 0;
|
||||
|
||||
- secure_key = (struct secaeskeytoken *)
|
||||
- read_secure_key(file_names->skey_filename,
|
||||
+ secure_key = read_secure_key(file_names->skey_filename,
|
||||
&secure_key_size, keystore->verbose);
|
||||
if (secure_key == NULL)
|
||||
return -EIO;
|
||||
|
||||
- if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size < MIN_SECURE_KEY_SIZE) {
|
||||
pr_verbose(keystore,
|
||||
"Size of secure key is too small: %lu expected %lu",
|
||||
- secure_key_size, SECURE_KEY_SIZE);
|
||||
+ secure_key_size, MIN_SECURE_KEY_SIZE);
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ get_key_bit_size(secure_key, secure_key_size, &clear_key_bitsize);
|
||||
+
|
||||
_keystore_print_record(rec, name, properties, 0,
|
||||
file_names->skey_filename, secure_key_size,
|
||||
- IS_XTS(secure_key_size) ? secure_key->bitsize * 2
|
||||
- : secure_key->bitsize,
|
||||
- 0, 0,
|
||||
+ is_xts_key(secure_key, secure_key_size),
|
||||
+ clear_key_bitsize, 0, 0,
|
||||
_keystore_reencipher_key_exists(file_names), 0);
|
||||
|
||||
out:
|
||||
@@ -3682,37 +3689,6 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
- * Returns the size of the secure key file
|
||||
- *
|
||||
- * @param[in] keystore the keystore
|
||||
- * @param[in] skey_filename the file name of the secure key
|
||||
- *
|
||||
- * @returns the size of the secure key, or -1 in case of an error
|
||||
- */
|
||||
-static size_t _keystore_get_key_file_size(struct keystore *keystore,
|
||||
- const char *skey_filename)
|
||||
-{
|
||||
- size_t secure_key_size;
|
||||
- struct stat sb;
|
||||
-
|
||||
- if (stat(skey_filename, &sb)) {
|
||||
- pr_verbose(keystore, "Key file '%s': %s",
|
||||
- skey_filename, strerror(errno));
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- secure_key_size = sb.st_size;
|
||||
- if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
- pr_verbose(keystore,
|
||||
- "Size of secure key is too small: %lu expected %lu",
|
||||
- secure_key_size, SECURE_KEY_SIZE);
|
||||
- return -1;
|
||||
- }
|
||||
-
|
||||
- return secure_key_size;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
* Processing function for the cryptsetup and crypttab functions.
|
||||
* Extracts the required information and calls the secondary processing function
|
||||
* contained in struct crypt_info.
|
||||
@@ -3738,6 +3714,7 @@ static int _keystore_process_crypt(struc
|
||||
size_t secure_key_size;
|
||||
size_t sector_size = 0;
|
||||
char *volumes = NULL;
|
||||
+ u8 *secure_key = NULL;
|
||||
char *dmname;
|
||||
char *temp;
|
||||
int rc = 0;
|
||||
@@ -3745,18 +3722,14 @@ static int _keystore_process_crypt(struc
|
||||
char *ch;
|
||||
int i;
|
||||
|
||||
- secure_key_size = _keystore_get_key_file_size(keystore,
|
||||
- file_names->skey_filename);
|
||||
- if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
- pr_verbose(keystore,
|
||||
- "Size of secure key is too small: %lu expected %lu",
|
||||
- secure_key_size, SECURE_KEY_SIZE);
|
||||
- rc = -EIO;
|
||||
- goto out;
|
||||
- }
|
||||
+ secure_key = read_secure_key(file_names->skey_filename,
|
||||
+ &secure_key_size, keystore->verbose);
|
||||
+ if (secure_key == NULL)
|
||||
+ return -EIO;
|
||||
|
||||
cipher_spec = _keystore_build_cipher_spec(properties,
|
||||
- IS_XTS(secure_key_size));
|
||||
+ is_xts_key(secure_key,
|
||||
+ secure_key_size));
|
||||
if (cipher_spec == NULL) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
@@ -3808,6 +3781,8 @@ out:
|
||||
free(cipher_spec);
|
||||
if (volume_type != NULL)
|
||||
free(volume_type);
|
||||
+ if (secure_key != NULL)
|
||||
+ free(secure_key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -98,10 +98,8 @@ u8 *read_secure_key(const char *keyfile,
|
||||
}
|
||||
size = sb.st_size;
|
||||
|
||||
- if (size != SECURE_KEY_SIZE && size != 2*SECURE_KEY_SIZE) {
|
||||
- warnx("File '%s' has an invalid size, %lu or %lu bytes "
|
||||
- "expected", keyfile, SECURE_KEY_SIZE,
|
||||
- 2 * SECURE_KEY_SIZE);
|
||||
+ if (size < MIN_SECURE_KEY_SIZE || size > 2 * MAX_SECURE_KEY_SIZE) {
|
||||
+ warnx("File '%s' has an invalid size: %lu", keyfile, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -306,7 +304,7 @@ int generate_secure_key_random(int pkey_
|
||||
if (keybits == 0)
|
||||
keybits = DEFAULT_KEYBITS;
|
||||
|
||||
- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
|
||||
+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts);
|
||||
secure_key = util_malloc(secure_key_size);
|
||||
|
||||
pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
|
||||
@@ -344,7 +342,7 @@ int generate_secure_key_random(int pkey_
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE);
|
||||
+ memcpy(secure_key, &gensec.seckey, AESDATA_KEY_SIZE);
|
||||
|
||||
if (xts) {
|
||||
rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
|
||||
@@ -357,8 +355,8 @@ int generate_secure_key_random(int pkey_
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey,
|
||||
- SECURE_KEY_SIZE);
|
||||
+ memcpy(secure_key + AESDATA_KEY_SIZE, &gensec.seckey,
|
||||
+ AESDATA_KEY_SIZE);
|
||||
}
|
||||
|
||||
pr_verbose(verbose, "Successfully generated a secure key");
|
||||
@@ -412,7 +410,7 @@ int generate_secure_key_clear(int pkey_f
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
|
||||
+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts);
|
||||
secure_key = util_malloc(secure_key_size);
|
||||
|
||||
clear_key = read_clear_key(clearkeyfile, keybits, xts, &clear_key_size,
|
||||
@@ -453,7 +451,7 @@ int generate_secure_key_clear(int pkey_f
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE);
|
||||
+ memcpy(secure_key, &clr2sec.seckey, AESDATA_KEY_SIZE);
|
||||
|
||||
if (xts) {
|
||||
memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2,
|
||||
@@ -469,8 +467,8 @@ int generate_secure_key_clear(int pkey_f
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey,
|
||||
- SECURE_KEY_SIZE);
|
||||
+ memcpy(secure_key + AESDATA_KEY_SIZE, &clr2sec.seckey,
|
||||
+ AESDATA_KEY_SIZE);
|
||||
}
|
||||
|
||||
pr_verbose(verbose,
|
||||
@@ -505,21 +503,21 @@ static int validate_secure_xts_key(int p
|
||||
u16 part1_keysize, u32 part1_attributes,
|
||||
size_t *clear_key_bitsize, bool verbose)
|
||||
{
|
||||
- struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
|
||||
+ struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
struct pkey_verifykey verifykey;
|
||||
- struct secaeskeytoken *token2;
|
||||
+ struct aesdatakeytoken *token2;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
|
||||
/* XTS uses 2 secure key tokens concatenated to each other */
|
||||
- token2 = (struct secaeskeytoken *)(secure_key + SECURE_KEY_SIZE);
|
||||
+ token2 = (struct aesdatakeytoken *)(secure_key + AESDATA_KEY_SIZE);
|
||||
|
||||
- if (secure_key_size != 2 * SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size != 2 * AESDATA_KEY_SIZE) {
|
||||
pr_verbose(verbose, "Size of secure key is too small: "
|
||||
"%lu expected %lu", secure_key_size,
|
||||
- 2 * SECURE_KEY_SIZE);
|
||||
+ 2 * AESDATA_KEY_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -591,17 +589,17 @@ int validate_secure_key(int pkey_fd,
|
||||
size_t *clear_key_bitsize, int *is_old_mk,
|
||||
bool verbose)
|
||||
{
|
||||
- struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
|
||||
+ struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
struct pkey_verifykey verifykey;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
|
||||
- if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size < AESDATA_KEY_SIZE) {
|
||||
pr_verbose(verbose, "Size of secure key is too small: "
|
||||
"%lu expected %lu", secure_key_size,
|
||||
- SECURE_KEY_SIZE);
|
||||
+ AESDATA_KEY_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -624,7 +622,7 @@ int validate_secure_key(int pkey_fd,
|
||||
*clear_key_bitsize = verifykey.keysize;
|
||||
|
||||
/* XTS uses 2 secure key tokens concatenated to each other */
|
||||
- if (secure_key_size > SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size > AESDATA_KEY_SIZE) {
|
||||
rc = validate_secure_xts_key(pkey_fd,
|
||||
secure_key, secure_key_size,
|
||||
verifykey.keysize,
|
||||
@@ -656,7 +654,7 @@ int validate_secure_key(int pkey_fd,
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
-int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
+int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose)
|
||||
{
|
||||
int tfmfd = -1, opfd = -1, rc = 0;
|
||||
@@ -691,7 +689,7 @@ int generate_key_verification_pattern(co
|
||||
}
|
||||
|
||||
snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)",
|
||||
- key_size > SECURE_KEY_SIZE ? "xts" : "cbc");
|
||||
+ is_xts_key(key, key_size) ? "xts" : "cbc");
|
||||
|
||||
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
|
||||
if (tfmfd < 0) {
|
||||
@@ -788,15 +786,15 @@ int get_master_key_verification_pattern(
|
||||
size_t secure_key_size, u64 *mkvp,
|
||||
bool verbose)
|
||||
{
|
||||
- struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
|
||||
+ struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
util_assert(mkvp != NULL, "Internal error: mkvp is NULL");
|
||||
|
||||
- if (secure_key_size < SECURE_KEY_SIZE) {
|
||||
+ if (secure_key_size < AESDATA_KEY_SIZE) {
|
||||
pr_verbose(verbose, "Size of secure key is too small: "
|
||||
"%lu expected %lu", secure_key_size,
|
||||
- SECURE_KEY_SIZE);
|
||||
+ AESDATA_KEY_SIZE);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -817,7 +815,7 @@ bool is_cca_aes_data_key(const u8 *key,
|
||||
{
|
||||
struct tokenheader *hdr = (struct tokenheader *)key;
|
||||
|
||||
- if (key == NULL || key_size < SECURE_KEY_SIZE)
|
||||
+ if (key == NULL || key_size < AESDATA_KEY_SIZE)
|
||||
return false;
|
||||
|
||||
if (hdr->type != TOKEN_TYPE_CCA_INTERNAL)
|
||||
@@ -829,6 +827,57 @@ bool is_cca_aes_data_key(const u8 *key,
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Check if the specified key is an XTS type key
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ *
|
||||
+ * @returns true if the key is an XTS key type
|
||||
+ */
|
||||
+bool is_xts_key(const u8 *key, size_t key_size)
|
||||
+{
|
||||
+ if (is_cca_aes_data_key(key, key_size)) {
|
||||
+ if (key_size == 2 * AESDATA_KEY_SIZE &&
|
||||
+ is_cca_aes_data_key(key + AESDATA_KEY_SIZE,
|
||||
+ key_size - AESDATA_KEY_SIZE))
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Gets the size in bits of the effective key of the specified secure key
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ * @param[out] bitsize On return, contains the size in bits of the key.
|
||||
+ * If the key size can not be determined, then 0 is
|
||||
+ * passed back as bitsize.
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize)
|
||||
+{
|
||||
+ struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key;
|
||||
+
|
||||
+ util_assert(bitsize != NULL, "Internal error: bitsize is NULL");
|
||||
+
|
||||
+ if (is_cca_aes_data_key(key, key_size)) {
|
||||
+ *bitsize = datakey->bitsize;
|
||||
+ if (key_size == 2 * AESDATA_KEY_SIZE) {
|
||||
+ datakey = (struct aesdatakeytoken *)key +
|
||||
+ AESDATA_KEY_SIZE;
|
||||
+ *bitsize += datakey->bitsize;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Returns the type of the key
|
||||
*
|
||||
* @param[in] key the secure key token
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -30,10 +30,10 @@ struct tokenheader {
|
||||
|
||||
#define TOKEN_VERSION_AESDATA 0x04
|
||||
|
||||
-struct secaeskeytoken {
|
||||
- u8 type; /* 0x01 for internal key token */
|
||||
+struct aesdatakeytoken {
|
||||
+ u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
|
||||
u8 res0[3];
|
||||
- u8 version; /* should be 0x04 */
|
||||
+ u8 version; /* should be TOKEN_VERSION_AESDATA (0x04) */
|
||||
u8 res1[1];
|
||||
u8 flag; /* key flags */
|
||||
u8 res2[1];
|
||||
@@ -45,10 +45,13 @@ struct secaeskeytoken {
|
||||
u8 tvv[4]; /* token validation value */
|
||||
} __packed;
|
||||
|
||||
-#define SECURE_KEY_SIZE sizeof(struct secaeskeytoken)
|
||||
+#define AESDATA_KEY_SIZE sizeof(struct aesdatakeytoken)
|
||||
+
|
||||
+#define MAX_SECURE_KEY_SIZE AESDATA_KEY_SIZE
|
||||
+#define MIN_SECURE_KEY_SIZE AESDATA_KEY_SIZE
|
||||
|
||||
struct pkey_seckey {
|
||||
- u8 seckey[SECURE_KEY_SIZE]; /* the secure key blob */
|
||||
+ u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */
|
||||
};
|
||||
|
||||
struct pkey_clrkey {
|
||||
@@ -123,7 +126,7 @@ int validate_secure_key(int pkey_fd,
|
||||
size_t *clear_key_bitsize, int *is_old_mk,
|
||||
bool verbose);
|
||||
|
||||
-int generate_key_verification_pattern(const char *key, size_t key_size,
|
||||
+int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
int get_master_key_verification_pattern(const u8 *secure_key,
|
||||
@@ -131,6 +134,8 @@ int get_master_key_verification_pattern(
|
||||
bool verbose);
|
||||
|
||||
bool is_cca_aes_data_key(const u8 *key, size_t key_size);
|
||||
+bool is_xts_key(const u8 *key, size_t key_size);
|
||||
+int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
|
||||
const char *get_key_type(const u8 *key, size_t key_size);
|
||||
|
||||
#endif
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -1329,22 +1329,25 @@ static int activate_unbound_keyslot(int
|
||||
return rc;
|
||||
}
|
||||
|
||||
-static int check_keysize_and_cipher_mode(size_t keysize)
|
||||
+static int check_keysize_and_cipher_mode(const u8 *key, size_t keysize)
|
||||
{
|
||||
- if (keysize == 0) {
|
||||
+ if (keysize < MIN_SECURE_KEY_SIZE ||
|
||||
+ keysize > 2 * MAX_SECURE_KEY_SIZE) {
|
||||
warnx("Invalid volume key size");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) {
|
||||
- if (keysize != 2 * SECURE_KEY_SIZE) {
|
||||
+ if (keysize < 2 * MIN_SECURE_KEY_SIZE ||
|
||||
+ (key != NULL && !is_xts_key(key, keysize))) {
|
||||
warnx("The volume key size %lu is not valid for the "
|
||||
"cipher mode '%s'", keysize,
|
||||
crypt_get_cipher_mode(g.cd));
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
- if (keysize != SECURE_KEY_SIZE) {
|
||||
+ if (keysize > MAX_SECURE_KEY_SIZE ||
|
||||
+ (key != NULL && is_xts_key(key, keysize))) {
|
||||
warnx("The volume key size %lu is not valid for the "
|
||||
"cipher mode '%s'", keysize,
|
||||
crypt_get_cipher_mode(g.cd));
|
||||
@@ -1377,7 +1380,7 @@ static int open_keyslot(int keyslot, cha
|
||||
vkeysize = crypt_get_volume_key_size(g.cd);
|
||||
pr_verbose("Volume key size: %lu", vkeysize);
|
||||
|
||||
- rc = check_keysize_and_cipher_mode(vkeysize);
|
||||
+ rc = check_keysize_and_cipher_mode(NULL, vkeysize);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
@@ -1571,7 +1574,7 @@ static int reencipher_prepare(int token)
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
- rc = generate_key_verification_pattern(key, keysize,
|
||||
+ rc = generate_key_verification_pattern((u8 *)key, keysize,
|
||||
reenc_tok.verification_pattern,
|
||||
sizeof(reenc_tok.verification_pattern),
|
||||
g.verbose);
|
||||
@@ -1851,8 +1854,8 @@ static int reencipher_complete(int token
|
||||
|
||||
}
|
||||
|
||||
- rc = generate_key_verification_pattern(key, keysize, vp, sizeof(vp),
|
||||
- g.verbose);
|
||||
+ rc = generate_key_verification_pattern((u8 *)key, keysize, vp,
|
||||
+ sizeof(vp), g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the verification pattern: %s",
|
||||
strerror(-rc));
|
||||
@@ -1998,7 +2001,7 @@ static int command_validate(void)
|
||||
printf(" Status: %s\n", is_valid ? "Valid" : "Invalid");
|
||||
printf(" Secure key size: %lu bytes\n", keysize);
|
||||
printf(" XTS type key: %s\n",
|
||||
- keysize > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
+ is_xts_key((u8 *)key, keysize) ? "Yes" : "No");
|
||||
printf(" Key type: %s\n",
|
||||
get_key_type((u8 *)key, keysize));
|
||||
if (is_valid) {
|
||||
@@ -2076,7 +2079,7 @@ static int command_setvp(void)
|
||||
|
||||
token = find_token(g.cd, PAES_VP_TOKEN_NAME);
|
||||
|
||||
- rc = generate_key_verification_pattern(key, keysize,
|
||||
+ rc = generate_key_verification_pattern((const u8 *)key, keysize,
|
||||
vp_tok.verification_pattern,
|
||||
sizeof(vp_tok.verification_pattern),
|
||||
g.verbose);
|
||||
@@ -2131,7 +2134,7 @@ static int command_setkey(void)
|
||||
if (newkey == NULL)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
- rc = check_keysize_and_cipher_mode(newkey_size);
|
||||
+ rc = check_keysize_and_cipher_mode(newkey, newkey_size);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
@@ -2180,7 +2183,7 @@ static int command_setkey(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = generate_key_verification_pattern((char *)newkey, newkey_size, vp,
|
||||
+ rc = generate_key_verification_pattern(newkey, newkey_size, vp,
|
||||
sizeof(vp), g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("Failed to generate the verification pattern: %s",
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1413,7 +1413,7 @@ static int command_validate_file(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- rc = generate_key_verification_pattern((char *)secure_key,
|
||||
+ rc = generate_key_verification_pattern(secure_key,
|
||||
secure_key_size, vp, sizeof(vp),
|
||||
g.verbose);
|
||||
if (rc != 0) {
|
||||
@@ -1441,7 +1441,7 @@ static int command_validate_file(void)
|
||||
get_key_type(secure_key, secure_key_size));
|
||||
printf(" Clear key size: %lu bits\n", clear_key_size);
|
||||
printf(" XTS type key: %s\n",
|
||||
- secure_key_size > SECURE_KEY_SIZE ? "Yes" : "No");
|
||||
+ is_xts_key(secure_key, secure_key_size) ? "Yes" : "No");
|
||||
printf(" Enciphered with: %s CCA master key (MKVP: %016llx)\n",
|
||||
is_old_mk ? "OLD" : "CURRENT", mkvp);
|
||||
printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
@ -1,148 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: move SIGP related functions and definitions into separate header
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 675c854fa3239882c59a9419c776eb13bc70cf76
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: move SIGP related functions and definitions into separate header
|
||||
|
||||
Move SIGP related functions and definitions to
|
||||
`include/boot/sigp.h`. This allows the reuse of the definitions in
|
||||
assembler files.
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Acked-by: Janosch Frank <frankja@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/sigp.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zipl/boot/s390.h | 38 -----------------------------------
|
||||
2 files changed, 56 insertions(+), 37 deletions(-)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/boot/sigp.h
|
||||
@@ -0,0 +1,55 @@
|
||||
+/*
|
||||
+ * SIGP related definitions and functions.
|
||||
+ *
|
||||
+ * 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 S390_SIGP_H
|
||||
+#define S390_SIGP_H
|
||||
+
|
||||
+/* Signal Processor Order Codes */
|
||||
+#define SIGP_STOP_AND_STORE_STATUS 9
|
||||
+#define SIGP_SET_MULTI_THREADING 22
|
||||
+#define SIGP_STORE_ASTATUS_AT_ADDRESS 23
|
||||
+
|
||||
+/* Signal Processor Condition Codes */
|
||||
+#define SIGP_CC_ORDER_CODE_ACCEPTED 0
|
||||
+#define SIGP_CC_BUSY 2
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+static inline int sigp(uint16_t addr, uint8_t order, uint32_t parm,
|
||||
+ uint32_t *status)
|
||||
+{
|
||||
+ register unsigned int reg1 asm ("1") = parm;
|
||||
+ int cc;
|
||||
+
|
||||
+ asm volatile(
|
||||
+ " sigp %1,%2,0(%3)\n"
|
||||
+ " ipm %0\n"
|
||||
+ " srl %0,28\n"
|
||||
+ : "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc");
|
||||
+ if (status && cc == 1)
|
||||
+ *status = reg1;
|
||||
+ return cc;
|
||||
+}
|
||||
+
|
||||
+static inline int sigp_busy(uint16_t addr, uint8_t order, uint32_t parm,
|
||||
+ uint32_t *status)
|
||||
+{
|
||||
+ int cc;
|
||||
+
|
||||
+ do {
|
||||
+ cc = sigp(addr, order, parm, status);
|
||||
+ } while (cc == SIGP_CC_BUSY);
|
||||
+ return cc;
|
||||
+}
|
||||
+
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* S390_SIGP_H */
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "libc.h"
|
||||
+#include "boot/sigp.h"
|
||||
|
||||
#define __pa32(x) ((uint32_t)(unsigned long)(x))
|
||||
#define __pa(x) ((unsigned long)(x))
|
||||
@@ -295,43 +296,6 @@ static inline int diag308(unsigned long
|
||||
}
|
||||
|
||||
/*
|
||||
- * Signal Processor
|
||||
- */
|
||||
-#define SIGP_STOP_AND_STORE_STATUS 9
|
||||
-#define SIGP_SET_MULTI_THREADING 22
|
||||
-#define SIGP_STORE_ASTATUS_AT_ADDRESS 23
|
||||
-
|
||||
-#define SIGP_CC_ORDER_CODE_ACCEPTED 0
|
||||
-#define SIGP_CC_BUSY 2
|
||||
-
|
||||
-static inline int sigp(uint16_t addr, uint8_t order, uint32_t parm,
|
||||
- uint32_t *status)
|
||||
-{
|
||||
- register unsigned int reg1 asm ("1") = parm;
|
||||
- int cc;
|
||||
-
|
||||
- asm volatile(
|
||||
- " sigp %1,%2,0(%3)\n"
|
||||
- " ipm %0\n"
|
||||
- " srl %0,28\n"
|
||||
- : "=d" (cc), "+d" (reg1) : "d" (addr), "a" (order) : "cc");
|
||||
- if (status && cc == 1)
|
||||
- *status = reg1;
|
||||
- return cc;
|
||||
-}
|
||||
-
|
||||
-static inline int sigp_busy(uint16_t addr, uint8_t order, uint32_t parm,
|
||||
- uint32_t *status)
|
||||
-{
|
||||
- int cc;
|
||||
-
|
||||
- do {
|
||||
- cc = sigp(addr, order, parm, status);
|
||||
- } while (cc == SIGP_CC_BUSY);
|
||||
- return cc;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
* Store CPU address
|
||||
*/
|
||||
static inline unsigned short stap(void)
|
@ -1,452 +0,0 @@
|
||||
Subject: zkey: Introduce the CCA-AESCIPHER key type
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: ddde3f354f3506521877a4e2a6082c4d597629cb
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Introduce the CCA-AESCIPHER key type
|
||||
|
||||
Add definitions and helper functions to support the new
|
||||
CCA-AESCIPHER key type. Also enhance existing helper functions
|
||||
to support CCA-AESCIPHER keys.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 2
|
||||
zkey/pkey.c | 91 +++++++++++++++++++++++++++++----
|
||||
zkey/pkey.h | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
zkey/zkey.1 | 20 ++++---
|
||||
zkey/zkey.c | 4 -
|
||||
5 files changed, 235 insertions(+), 32 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -341,6 +341,8 @@ static int _keystore_valid_key_type(cons
|
||||
{
|
||||
if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0)
|
||||
return 1;
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0)
|
||||
+ return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -782,23 +782,21 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
-int get_master_key_verification_pattern(const u8 *secure_key,
|
||||
- size_t secure_key_size, u64 *mkvp,
|
||||
- bool verbose)
|
||||
+int get_master_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
+ u64 *mkvp, bool UNUSED(verbose))
|
||||
{
|
||||
- struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
+ struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key;
|
||||
+ struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
|
||||
|
||||
- util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
+ util_assert(key != NULL, "Internal error: secure_key is NULL");
|
||||
util_assert(mkvp != NULL, "Internal error: mkvp is NULL");
|
||||
|
||||
- if (secure_key_size < AESDATA_KEY_SIZE) {
|
||||
- pr_verbose(verbose, "Size of secure key is too small: "
|
||||
- "%lu expected %lu", secure_key_size,
|
||||
- AESDATA_KEY_SIZE);
|
||||
+ if (is_cca_aes_data_key(key, key_size))
|
||||
+ *mkvp = datakey->mkvp;
|
||||
+ else if (is_cca_aes_cipher_key(key, key_size))
|
||||
+ memcpy(mkvp, cipherkey->kvp, sizeof(*mkvp));
|
||||
+ else
|
||||
return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- *mkvp = token->mkvp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -827,6 +825,56 @@ bool is_cca_aes_data_key(const u8 *key,
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Check if the specified key is a CCA AESCIPHER key token.
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ *
|
||||
+ * @returns true if the key is an CCA AESCIPHER token type
|
||||
+ */
|
||||
+bool is_cca_aes_cipher_key(const u8 *key, size_t key_size)
|
||||
+{
|
||||
+ struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
|
||||
+
|
||||
+ if (key == NULL || key_size < AESCIPHER_KEY_SIZE)
|
||||
+ return false;
|
||||
+
|
||||
+ if (cipherkey->type != TOKEN_TYPE_CCA_INTERNAL)
|
||||
+ return false;
|
||||
+ if (cipherkey->version != TOKEN_VERSION_AESCIPHER)
|
||||
+ return false;
|
||||
+ if (cipherkey->length > key_size)
|
||||
+ return false;
|
||||
+
|
||||
+ if (cipherkey->kms != 0x03) /* key wrapped by master key */
|
||||
+ return false;
|
||||
+ if (cipherkey->kwm != 0x02) /* key wrapped using AESKW */
|
||||
+ return false;
|
||||
+ if (cipherkey->pfv != 0x00 && cipherkey->pfv != 0x01) /* V0 or V1 */
|
||||
+ return false;
|
||||
+ if (cipherkey->adv != 0x01) /* Should have ass. data sect. version 1 */
|
||||
+ return false;
|
||||
+ if (cipherkey->at != 0x02) /* Algorithm: AES */
|
||||
+ return false;
|
||||
+ if (cipherkey->kt != 0x0001) /* Key type: CIPHER */
|
||||
+ return false;
|
||||
+ if (cipherkey->adl != 26) /* Ass. data section length should be 26 */
|
||||
+ return false;
|
||||
+ if (cipherkey->kll != 0) /* Should have no key label */
|
||||
+ return false;
|
||||
+ if (cipherkey->eadl != 0) /* Should have no ext associated data */
|
||||
+ return false;
|
||||
+ if (cipherkey->uadl != 0) /* Should have no user associated data */
|
||||
+ return false;
|
||||
+ if (cipherkey->kufc != 2) /* Should have 2 KUFs */
|
||||
+ return false;
|
||||
+ if (cipherkey->kmfc != 3) /* Should have 3 KMFs */
|
||||
+ return false;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Check if the specified key is an XTS type key
|
||||
*
|
||||
* @param[in] key the secure key token
|
||||
@@ -841,6 +889,11 @@ bool is_xts_key(const u8 *key, size_t ke
|
||||
is_cca_aes_data_key(key + AESDATA_KEY_SIZE,
|
||||
key_size - AESDATA_KEY_SIZE))
|
||||
return true;
|
||||
+ } else if (is_cca_aes_cipher_key(key, key_size)) {
|
||||
+ if (key_size == 2 * AESCIPHER_KEY_SIZE &&
|
||||
+ is_cca_aes_cipher_key(key + AESCIPHER_KEY_SIZE,
|
||||
+ key_size - AESCIPHER_KEY_SIZE))
|
||||
+ return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -860,6 +913,7 @@ bool is_xts_key(const u8 *key, size_t ke
|
||||
int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize)
|
||||
{
|
||||
struct aesdatakeytoken *datakey = (struct aesdatakeytoken *)key;
|
||||
+ struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
|
||||
|
||||
util_assert(bitsize != NULL, "Internal error: bitsize is NULL");
|
||||
|
||||
@@ -870,6 +924,17 @@ int get_key_bit_size(const u8 *key, size
|
||||
AESDATA_KEY_SIZE;
|
||||
*bitsize += datakey->bitsize;
|
||||
}
|
||||
+ } else if (is_cca_aes_cipher_key(key, key_size)) {
|
||||
+ if (cipherkey->pfv == 0x00) /* V0 payload */
|
||||
+ *bitsize = cipherkey->pl - 384;
|
||||
+ else
|
||||
+ *bitsize = 0; /* Unknown */
|
||||
+ if (key_size > cipherkey->length) {
|
||||
+ cipherkey = (struct aescipherkeytoken *)key +
|
||||
+ cipherkey->length;
|
||||
+ if (cipherkey->pfv == 0x00) /* V0 payload */
|
||||
+ *bitsize += cipherkey->pl - 384;
|
||||
+ }
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -889,6 +954,8 @@ const char *get_key_type(const u8 *key,
|
||||
{
|
||||
if (is_cca_aes_data_key(key, key_size))
|
||||
return KEY_TYPE_CCA_AESDATA;
|
||||
+ if (is_cca_aes_cipher_key(key, key_size))
|
||||
+ return KEY_TYPE_CCA_AESCIPHER;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -29,6 +29,7 @@ struct tokenheader {
|
||||
#define TOKEN_TYPE_CCA_INTERNAL 0x01
|
||||
|
||||
#define TOKEN_VERSION_AESDATA 0x04
|
||||
+#define TOKEN_VERSION_AESCIPHER 0x05
|
||||
|
||||
struct aesdatakeytoken {
|
||||
u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
|
||||
@@ -45,10 +46,45 @@ struct aesdatakeytoken {
|
||||
u8 tvv[4]; /* token validation value */
|
||||
} __packed;
|
||||
|
||||
+struct aescipherkeytoken {
|
||||
+ u8 type; /* TOKEN_TYPE_INTERNAL (0x01) for internal key token */
|
||||
+ u8 res0;
|
||||
+ u16 length; /* length of token */
|
||||
+ u8 version; /* should be TOKEN_VERSION_CIPHER (0x05) */
|
||||
+ u8 res1[3];
|
||||
+ u8 kms; /* key material state, should be 0x03 */
|
||||
+ u8 kvptype; /* key verification pattern type */
|
||||
+ u8 kvp[16]; /* key verification pattern */
|
||||
+ u8 kwm; /* key wrapping method, should be 0x02 */
|
||||
+ u8 kwh; /* key wrapping hash algorithm */
|
||||
+ u8 pfv; /* payload format version, should be 0x00*/
|
||||
+ u8 res2;
|
||||
+ u8 adv; /* associated data section version */
|
||||
+ u8 res3;
|
||||
+ u16 adl; /* associated data length */
|
||||
+ u8 kll; /* length of optional key label */
|
||||
+ u8 eadl; /* extended associated data length */
|
||||
+ u8 uadl; /* user associated data length */
|
||||
+ u8 res4;
|
||||
+ u16 pl; /* payload bit length */
|
||||
+ u8 res5;
|
||||
+ u8 at; /* algorithm type, should be 0x02 (AES) */
|
||||
+ u16 kt; /* key type, should be 0x001 (CIPHER) */
|
||||
+ u8 kufc; /* key usage field count */
|
||||
+ u16 kuf1; /* key usage field 1 */
|
||||
+ u16 kuf2; /* key usage field 2 */
|
||||
+ u8 kmfc; /* key management field count */
|
||||
+ u16 kmf1; /* key management field 1 */
|
||||
+ u16 kmf2; /* key management field 2 */
|
||||
+ u16 kmf3; /* key management field 3 */
|
||||
+ u8 varpart[80]; /* variable part */
|
||||
+} __packed;
|
||||
+
|
||||
#define AESDATA_KEY_SIZE sizeof(struct aesdatakeytoken)
|
||||
+#define AESCIPHER_KEY_SIZE sizeof(struct aescipherkeytoken)
|
||||
|
||||
-#define MAX_SECURE_KEY_SIZE AESDATA_KEY_SIZE
|
||||
-#define MIN_SECURE_KEY_SIZE AESDATA_KEY_SIZE
|
||||
+#define MAX_SECURE_KEY_SIZE MAX(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
|
||||
+#define MIN_SECURE_KEY_SIZE MIN(AESDATA_KEY_SIZE, AESCIPHER_KEY_SIZE)
|
||||
|
||||
struct pkey_seckey {
|
||||
u8 seckey[AESDATA_KEY_SIZE]; /* the secure key blob */
|
||||
@@ -58,12 +94,12 @@ struct pkey_clrkey {
|
||||
u8 clrkey[32]; /* 16, 24, or 32 byte clear key value */
|
||||
};
|
||||
|
||||
-#define PKEY_IOCTL_MAGIC 'p'
|
||||
-#define AUTOSELECT 0xFFFF
|
||||
-#define PKEYDEVICE "/dev/pkey"
|
||||
-#define PKEY_KEYTYPE_AES_128 1
|
||||
-#define PKEY_KEYTYPE_AES_192 2
|
||||
-#define PKEY_KEYTYPE_AES_256 3
|
||||
+#define PKEY_IOCTL_MAGIC 'p'
|
||||
+#define AUTOSELECT 0xFFFF
|
||||
+#define PKEYDEVICE "/dev/pkey"
|
||||
+#define PKEY_KEYTYPE_AES_128 1
|
||||
+#define PKEY_KEYTYPE_AES_192 2
|
||||
+#define PKEY_KEYTYPE_AES_256 3
|
||||
|
||||
struct pkey_genseck {
|
||||
u16 cardnr; /* in: card to use or FFFF for any */
|
||||
@@ -97,7 +133,99 @@ struct pkey_verifykey {
|
||||
|
||||
#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
|
||||
|
||||
+enum pkey_key_type {
|
||||
+ PKEY_TYPE_CCA_DATA = (u32) 1,
|
||||
+ PKEY_TYPE_CCA_CIPHER = (u32) 2,
|
||||
+};
|
||||
+
|
||||
+enum pkey_key_size {
|
||||
+ PKEY_SIZE_AES_128 = (u32) 128,
|
||||
+ PKEY_SIZE_AES_192 = (u32) 192,
|
||||
+ PKEY_SIZE_AES_256 = (u32) 256,
|
||||
+ PKEY_SIZE_UNKNOWN = (u32) 0xFFFFFFFF,
|
||||
+};
|
||||
+
|
||||
+#define PKEY_FLAGS_MATCH_CUR_MKVP 0x00000002
|
||||
+#define PKEY_FLAGS_MATCH_ALT_MKVP 0x00000004
|
||||
+
|
||||
+#define PKEY_KEYGEN_XPRT_SYM 0x00008000
|
||||
+#define PKEY_KEYGEN_XPRT_UASY 0x00004000
|
||||
+#define PKEY_KEYGEN_XPRT_AASY 0x00002000
|
||||
+#define PKEY_KEYGEN_XPRT_RAW 0x00001000
|
||||
+#define PKEY_KEYGEN_XPRT_CPAC 0x00000800
|
||||
+#define PKEY_KEYGEN_XPRT_DES 0x00000080
|
||||
+#define PKEY_KEYGEN_XPRT_AES 0x00000040
|
||||
+#define PKEY_KEYGEN_XPRT_RSA 0x00000008
|
||||
+
|
||||
+struct pkey_apqn {
|
||||
+ u16 card;
|
||||
+ u16 domain;
|
||||
+};
|
||||
+
|
||||
+struct pkey_genseck2 {
|
||||
+ struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */
|
||||
+ u32 apqn_entries; /* in: # of apqn target list entries */
|
||||
+ enum pkey_key_type type; /* in: key type to generate */
|
||||
+ enum pkey_key_size size; /* in: key size to generate */
|
||||
+ u32 keygenflags; /* in: key generation flags */
|
||||
+ u8 *key; /* in: pointer to key blob buffer */
|
||||
+ u32 keylen; /* in: available key blob buffer size */
|
||||
+ /* out: actual key blob size */
|
||||
+};
|
||||
+
|
||||
+#define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2)
|
||||
+
|
||||
+struct pkey_clr2seck2 {
|
||||
+ struct pkey_apqn *apqns; /* in: ptr to list of apqn targets */
|
||||
+ u32 apqn_entries; /* in: # of apqn target list entries */
|
||||
+ enum pkey_key_type type; /* in: key type to generate */
|
||||
+ enum pkey_key_size size; /* in: key size to generate */
|
||||
+ u32 keygenflags; /* in: key generation flags */
|
||||
+ struct pkey_clrkey clrkey; /* in: the clear key value */
|
||||
+ u8 *key; /* in: pointer to key blob buffer */
|
||||
+ u32 keylen; /* in: available key blob buffer size */
|
||||
+ /* out: actual key blob size */
|
||||
+};
|
||||
+
|
||||
+#define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2)
|
||||
+
|
||||
+struct pkey_verifykey2 {
|
||||
+ u8 *key; /* in: pointer to key blob */
|
||||
+ u32 keylen; /* in: key blob size */
|
||||
+ u16 cardnr; /* in/out: card number */
|
||||
+ u16 domain; /* in/out: domain number */
|
||||
+ enum pkey_key_type type; /* out: the key type */
|
||||
+ enum pkey_key_size size; /* out: the key size */
|
||||
+ u32 flags; /* out: additional key info flags */
|
||||
+};
|
||||
+
|
||||
+#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2)
|
||||
+
|
||||
+struct pkey_apqns4key {
|
||||
+ u8 *key; /* in: pointer to key blob */
|
||||
+ u32 keylen; /* in: key blob size */
|
||||
+ u32 flags; /* in: match controlling flags */
|
||||
+ struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/
|
||||
+ u32 apqn_entries; /* in: max # of apqn entries in list */
|
||||
+ /* out: # apqns stored into the list */
|
||||
+};
|
||||
+
|
||||
+#define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key)
|
||||
+
|
||||
+struct pkey_apqns4keytype {
|
||||
+ enum pkey_key_type type; /* in: key type */
|
||||
+ u8 cur_mkvp[32]; /* in: current mkvp */
|
||||
+ u8 alt_mkvp[32]; /* in: alternate mkvp */
|
||||
+ u32 flags; /* in: match controlling flags */
|
||||
+ struct pkey_apqn *apqns; /* in/out: ptr to list of apqn targets*/
|
||||
+ u32 apqn_entries; /* in: max # of apqn entries in list */
|
||||
+ /* out: # apqns stored into the list */
|
||||
+};
|
||||
+
|
||||
+#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype)
|
||||
+
|
||||
#define KEY_TYPE_CCA_AESDATA "CCA-AESDATA"
|
||||
+#define KEY_TYPE_CCA_AESCIPHER "CCA-AESCIPHER"
|
||||
|
||||
#define PAES_BLOCK_SIZE 16
|
||||
#define ENC_ZERO_LEN (2 * PAES_BLOCK_SIZE)
|
||||
@@ -129,11 +257,11 @@ int validate_secure_key(int pkey_fd,
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
|
||||
-int get_master_key_verification_pattern(const u8 *secure_key,
|
||||
- size_t secure_key_size, u64 *mkvp,
|
||||
- bool verbose);
|
||||
+int get_master_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
+ u64 *mkvp, bool verbose);
|
||||
|
||||
bool is_cca_aes_data_key(const u8 *key, size_t key_size);
|
||||
+bool is_cca_aes_cipher_key(const u8 *key, size_t key_size);
|
||||
bool is_xts_key(const u8 *key, size_t key_size);
|
||||
int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
|
||||
const char *get_key_type(const u8 *key, size_t key_size);
|
||||
--- a/zkey/zkey.1
|
||||
+++ b/zkey/zkey.1
|
||||
@@ -134,10 +134,14 @@ additional information can be associated
|
||||
.B \-\-sector-size
|
||||
options.
|
||||
.PP
|
||||
-You can generate different types of secure keys: \fBCCA-AESDATA\fP keys.
|
||||
-Specify the type of the secure key using the
|
||||
+You can generate different types of secure keys: \fBCCA-AESDATA\fP keys, and
|
||||
+\fBCCA-AESCIPHER\fP keys. Specify the type of the secure key using the
|
||||
.B \-\-key\-type
|
||||
option. The default key type is CCA-AESDATA.
|
||||
+.PP
|
||||
+.B Note:
|
||||
+Secure keys of type \fBCCA-AESCIPHER\fP require an IBM cryptographic
|
||||
+adapter in CCA coprocessor mode of version 6 or later, e.g. a CEX6C.
|
||||
.
|
||||
.SS "Validating secure AES keys"
|
||||
.
|
||||
@@ -741,9 +745,11 @@ the default volume type is \fBplain\fP.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-K ", " \-\-key-type\~\fItype\fP
|
||||
-Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
|
||||
-If this option is omitted, then a secure key of type
|
||||
-CCA-AESDATA is generated.
|
||||
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
|
||||
+and \fBCCA-AESCIPHER\fP. If this option is omitted, then a secure key of type
|
||||
+CCA-AESDATA is generated. Secure keys of type \fBCCA-AESCIPHER\fP require an
|
||||
+IBM cryptographic adapter in CCA coprocessor mode of version 6 or later, e.g.
|
||||
+a CEX6C.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -925,8 +931,8 @@ has been compiled with LUKS2 support ena
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.TP
|
||||
.BR \-K ", " \-\-key-type\~\fItype\fP
|
||||
-Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP.
|
||||
-Only keys with the specified key type are listed.
|
||||
+Specifies the key type of the secure key. Possible values are \fBCCA-AESDATA\fP
|
||||
+and \fBCCA-AESCIPHER\fP. Only keys with the specified key type are listed.
|
||||
This option is only used for secure keys contained in the secure key repository.
|
||||
.
|
||||
.
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -221,7 +221,7 @@ static struct util_opt opt_vec[] = {
|
||||
.option = { "key-type", required_argument, NULL, 'K'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the key. Possible values are '"
|
||||
- KEY_TYPE_CCA_AESDATA"'. "
|
||||
+ KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
|
||||
"When this option is omitted, the default is '"
|
||||
KEY_TYPE_CCA_AESDATA"'",
|
||||
.command = COMMAND_GENERATE,
|
||||
@@ -446,7 +446,7 @@ static struct util_opt opt_vec[] = {
|
||||
.option = { "key-type", required_argument, NULL, 'K'},
|
||||
.argument = "type",
|
||||
.desc = "The type of the key. Possible values are '"
|
||||
- KEY_TYPE_CCA_AESDATA"'. "
|
||||
+ KEY_TYPE_CCA_AESDATA"' and '"KEY_TYPE_CCA_AESCIPHER"'. "
|
||||
"Use this option to list all keys with the specified "
|
||||
"key type.",
|
||||
.command = COMMAND_LIST,
|
@ -1,117 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: add SIGP_SET_ARCHITECTURE to sigp.h and use it
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 0e385a81caf7c266c0784613e0264c03271eb99a
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: add SIGP_SET_ARCHITECTURE to sigp.h and use it
|
||||
|
||||
This makes the code easier to read.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/sigp.h | 1 +
|
||||
zipl/boot/head.S | 6 ++++--
|
||||
zipl/boot/stage3.c | 6 ++++--
|
||||
zipl/boot/tape0.S | 6 ++++--
|
||||
4 files changed, 13 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/include/boot/sigp.h
|
||||
+++ b/include/boot/sigp.h
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
/* Signal Processor Order Codes */
|
||||
#define SIGP_STOP_AND_STORE_STATUS 9
|
||||
+#define SIGP_SET_ARCHITECTURE 18
|
||||
#define SIGP_SET_MULTI_THREADING 22
|
||||
#define SIGP_STORE_ASTATUS_AT_ADDRESS 23
|
||||
|
||||
--- a/zipl/boot/head.S
|
||||
+++ b/zipl/boot/head.S
|
||||
@@ -9,16 +9,18 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "boot/sigp.h"
|
||||
+
|
||||
.section .text.start
|
||||
.globl _start
|
||||
_start:
|
||||
basr %r13,0
|
||||
0: la %r7,2 /* First try code 2: */
|
||||
la %r6,0 /* 64 bit psws are restored */
|
||||
- sigp %r7,%r6,0x12 /* Switch to 64 bit */
|
||||
+ sigp %r7,%r6,SIGP_SET_ARCHITECTURE /* Switch to 64 bit */
|
||||
bc 8,.Lswitched_64-0b(%r13) /* Accepted ? */
|
||||
la %r7,1 /* Failed - try code 1 */
|
||||
- sigp %r7,%r6,0x12 /* Switch to 64 bit */
|
||||
+ sigp %r7,%r6,SIGP_SET_ARCHITECTURE /* Switch to 64 bit */
|
||||
.Lswitched_64:
|
||||
sam64 /* Switch to 64 bit addr mode */
|
||||
basr %r13,0
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
#include "libc.h"
|
||||
+#include "boot/sigp.h"
|
||||
#include "s390.h"
|
||||
#include "stage3.h"
|
||||
#include "error.h"
|
||||
@@ -194,11 +195,12 @@ static inline void __noreturn start_kern
|
||||
" sam31\n"
|
||||
" sr %r1,%r1\n"
|
||||
" sr %r2,%r2\n"
|
||||
- " sigp %r1,%r2,0x12\n"
|
||||
+ " sigp %r1,%r2,%[order]\n"
|
||||
" lpsw 0\n"
|
||||
: [addr] "=&d" (addr),
|
||||
[code] "+&d" (code)
|
||||
- : [psw] "a" (psw) );
|
||||
+ : [psw] "a" (psw),
|
||||
+ [order] "L" (SIGP_SET_ARCHITECTURE));
|
||||
while (1);
|
||||
}
|
||||
|
||||
--- a/zipl/boot/tape0.S
|
||||
+++ b/zipl/boot/tape0.S
|
||||
@@ -7,6 +7,8 @@
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
+#include "boot/sigp.h"
|
||||
+
|
||||
IPL_BS = 1024 # block size for tape access
|
||||
IPL_OFF = 0x4000 # temporary kernel load addr
|
||||
COMMAND_LINE_SIZE = 896 # max command line length
|
||||
@@ -184,10 +186,10 @@ iplstart:
|
||||
0:
|
||||
la %r7,2 #/* First try code 2: */
|
||||
la %r6,0 #/* 64 bit psws are restored */
|
||||
- sigp %r7,%r6,0x12 #/* Switch to 64 bit */
|
||||
+ sigp %r7,%r6,SIGP_SET_ARCHITECTURE #/* Switch to 64 bit */
|
||||
bc 8,.Lswitched_64-0b(%r13) #/* Accepted ? */
|
||||
la %r7,1 #/* Failed - try code 1 */
|
||||
- sigp %r7,%r6,0x12 #/* Switch to 64 bit */
|
||||
+ sigp %r7,%r6,SIGP_SET_ARCHITECTURE #/* Switch to 64 bit */
|
||||
.Lswitched_64:
|
||||
sam64 #/* Switch to 64 bit addr mode */
|
||||
basr %r13,0
|
@ -1,278 +0,0 @@
|
||||
Subject: zkey: Add wrappers for the new IOCTLs with fallback to the old once
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: d4027e6506963fbf995992e32490d56a6f7ea587
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add wrappers for the new IOCTLs with fallback to the old once
|
||||
|
||||
By default the new pkey IOCTL are used. In case the pkey device does not
|
||||
support the new IOCTLs (i.e. errno ENOTTY is returned), then the wrapper
|
||||
falls back to the old IOCTLs. The old IOCTLs only support secure keys of
|
||||
type CCA-AESDATA.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/pkey.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 228 insertions(+)
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -270,6 +270,234 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Returns the PKEY_KEYTYPE_xxx value for the specified key size.
|
||||
+ *
|
||||
+ * @param[in] keysize the key size in bits
|
||||
+ *
|
||||
+ * @returns the PKEY_KEYTYPE_xxx value or 0 for an unknown key size
|
||||
+ */
|
||||
+static u32 keysize_to_keytype(enum pkey_key_size keysize)
|
||||
+{
|
||||
+ switch (keysize) {
|
||||
+ case PKEY_SIZE_AES_128:
|
||||
+ return PKEY_KEYTYPE_AES_128;
|
||||
+ case PKEY_SIZE_AES_192:
|
||||
+ return PKEY_KEYTYPE_AES_192;
|
||||
+ case PKEY_SIZE_AES_256:
|
||||
+ return PKEY_KEYTYPE_AES_256;
|
||||
+ default:
|
||||
+ return 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Returns the PKEY_SIZE_xxx value for the specified keybits.
|
||||
+ *
|
||||
+ * @param[in] keybits the key size in bits
|
||||
+ *
|
||||
+ * @returns thePKEY_SIZE_xxx value or 0 for an unknown key size
|
||||
+ */
|
||||
+static enum pkey_key_size keybits_to_keysize(u32 keybits)
|
||||
+{
|
||||
+ switch (keybits) {
|
||||
+ case 128:
|
||||
+ return PKEY_SIZE_AES_128;
|
||||
+ case 192:
|
||||
+ return PKEY_SIZE_AES_192;
|
||||
+ case 256:
|
||||
+ return PKEY_SIZE_AES_256;
|
||||
+ default:
|
||||
+ return PKEY_SIZE_UNKNOWN;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Wrapper for the PKEY_GENSECK/PKEY_GENSECK2 IOCTL to generate a secure
|
||||
+ * key of any type by random. If the newer PKEY_GENSECK2 IOCTL is not supported
|
||||
+ * by the pkey device, then it falls back to the older PKEY_GENSECK IOCTL
|
||||
+ *
|
||||
+ * @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in/out] genseck info about key to generate
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int pkey_genseck2(int pkey_fd, struct pkey_genseck2 *genseck2,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ struct pkey_genseck genseck;
|
||||
+ int rc;
|
||||
+ u32 i;
|
||||
+
|
||||
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
+ util_assert(genseck2 != NULL, "Internal error: genseck2 is NULL");
|
||||
+
|
||||
+ rc = ioctl(pkey_fd, PKEY_GENSECK2, genseck2);
|
||||
+ if (rc != 0 && errno != ENOTTY)
|
||||
+ return -errno;
|
||||
+ if (rc == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* New IOCTL is not available, fall back to old one */
|
||||
+ pr_verbose(verbose, "ioctl PKEY_GENSECK2 not supported, fall back to "
|
||||
+ "PKEY_GENSECK");
|
||||
+
|
||||
+ if (genseck2->type != PKEY_TYPE_CCA_DATA) {
|
||||
+ warnx("Key-type is not supported");
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
+
|
||||
+ if (genseck2->keylen < AESDATA_KEY_SIZE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memset(&genseck, 0, sizeof(genseck));
|
||||
+
|
||||
+ genseck.keytype = keysize_to_keytype(genseck2->size);
|
||||
+ if (genseck.keytype == 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for (i = 0; i < genseck2->apqn_entries; i++) {
|
||||
+ genseck.cardnr = genseck2->apqns[i].card;
|
||||
+ genseck.domain = genseck2->apqns[i].domain;
|
||||
+
|
||||
+ rc = ioctl(pkey_fd, PKEY_GENSECK, &genseck);
|
||||
+ if (rc != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ memcpy(genseck2->key, &genseck.seckey.seckey, AESDATA_KEY_SIZE);
|
||||
+ genseck2->keylen = AESDATA_KEY_SIZE;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -errno;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Wrapper for the PKEY_CLR2SECK/PKEY_CLR2SECK2 IOCTL to generate a secure
|
||||
+ * key of any type from a clear key. If the newer PKEY_CLR2SECK2 IOCTL is not
|
||||
+ * supported by the pkey device, then it falls back to the older PKEY_CLR2SECK
|
||||
+ * IOCTL
|
||||
+ *
|
||||
+ * @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in/out] clr2seck2 info about key to generate
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int pkey_clr2seck2(int pkey_fd, struct pkey_clr2seck2 *clr2seck2,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ struct pkey_clr2seck clr2seck;
|
||||
+ int rc;
|
||||
+ u32 i;
|
||||
+
|
||||
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
+ util_assert(clr2seck2 != NULL, "Internal error: clr2seck2 is NULL");
|
||||
+
|
||||
+ rc = ioctl(pkey_fd, PKEY_CLR2SECK2, clr2seck2);
|
||||
+ if (rc != 0 && errno != ENOTTY)
|
||||
+ return -errno;
|
||||
+ if (rc == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* New IOCTL is not available, fall back to old one */
|
||||
+ pr_verbose(verbose, "ioctl PKEY_CLR2SECK2 not supported, fall back to "
|
||||
+ "PKEY_CLR2SECK");
|
||||
+
|
||||
+ if (clr2seck2->type != PKEY_TYPE_CCA_DATA) {
|
||||
+ warnx("Key-type is not supported");
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
+
|
||||
+ if (clr2seck2->keylen < AESDATA_KEY_SIZE)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memset(&clr2seck, 0, sizeof(clr2seck));
|
||||
+ clr2seck.clrkey = clr2seck2->clrkey;
|
||||
+
|
||||
+ clr2seck.keytype = keysize_to_keytype(clr2seck2->size);
|
||||
+ if (clr2seck.keytype == 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for (i = 0; i < clr2seck2->apqn_entries; i++) {
|
||||
+ clr2seck.cardnr = clr2seck2->apqns[i].card;
|
||||
+ clr2seck.domain = clr2seck2->apqns[i].domain;
|
||||
+
|
||||
+ rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2seck);
|
||||
+ if (rc != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ memcpy(clr2seck2->key, &clr2seck.seckey.seckey,
|
||||
+ AESDATA_KEY_SIZE);
|
||||
+ clr2seck2->keylen = AESDATA_KEY_SIZE;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -errno;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Wrapper for the PKEY_VERIFYKEY/PKEY_VERIFYKEY2 IOCTL to verify a secure
|
||||
+ * key of any type. If the newer PKEY_VERIFYKEY2 IOCTL is not supported
|
||||
+ * by the pkey device, then it falls back to the older PKEY_VERIFYKEY IOCTL
|
||||
+ *
|
||||
+ * @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in/out] verifykey2 info about key to verify
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int pkey_verifyseck2(int pkey_fd, struct pkey_verifykey2 *verifykey2,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ struct pkey_verifykey verifykey;
|
||||
+ int rc;
|
||||
+
|
||||
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
+ util_assert(verifykey2 != NULL, "Internal error: verifyseck2 is NULL");
|
||||
+
|
||||
+ rc = ioctl(pkey_fd, PKEY_VERIFYKEY2, verifykey2);
|
||||
+ if (rc != 0 && errno != ENOTTY)
|
||||
+ return -errno;
|
||||
+ if (rc == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* New IOCTL is not available, fall back to old one */
|
||||
+ pr_verbose(verbose, "ioctl PKEY_VERIFYKEY2 not supported, fall back to "
|
||||
+ "PKEY_VERIFYKEY");
|
||||
+
|
||||
+ if (!is_cca_aes_data_key(verifykey2->key, verifykey2->keylen))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ memset(&verifykey, 0, sizeof(verifykey));
|
||||
+ memcpy(&verifykey.seckey, verifykey2->key, sizeof(verifykey.seckey));
|
||||
+
|
||||
+ /*
|
||||
+ * Note: the old IOCTL does not support to check a specific card and
|
||||
+ * domain. If falling back to the old IOCTL, this input is silently
|
||||
+ * ignored, and all APQNs currently available in the system are used.
|
||||
+ */
|
||||
+ rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
|
||||
+ if (rc != 0)
|
||||
+ return -errno;
|
||||
+
|
||||
+ if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ verifykey2->type = PKEY_TYPE_CCA_DATA;
|
||||
+ verifykey2->cardnr = verifykey.cardnr;
|
||||
+ verifykey2->domain = verifykey.domain;
|
||||
+ verifykey2->size = keybits_to_keysize(verifykey.keysize);
|
||||
+
|
||||
+ if (verifykey.attributes & PKEY_VERIFY_ATTR_OLD_MKVP)
|
||||
+ verifykey2->flags = PKEY_FLAGS_MATCH_ALT_MKVP;
|
||||
+ else
|
||||
+ verifykey2->flags = PKEY_FLAGS_MATCH_CUR_MKVP;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Generate a secure key by random
|
||||
*
|
||||
* @param[in] pkey_fd the pkey file descriptor
|
@ -1,56 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/stage3: make IPL_DEVICE definition consistent with tape0.S
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: d884fb8db4c4f383780d6fc8087abd8f80e1c8b8
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/stage3: make IPL_DEVICE definition consistent with tape0.S
|
||||
|
||||
Make `IPL_DEVICE` definition consistent with the kernel definition and
|
||||
the definition in tape0.S. This allows us to refactor the code later.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/stage3.c | 2 +-
|
||||
zipl/boot/stage3.h | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -292,7 +292,7 @@ void start(void)
|
||||
/* store subchannel ID into low core and into new kernel space */
|
||||
subchannel_id = S390_lowcore.subchannel_id;
|
||||
*(unsigned int *)__LC_IPLDEV = subchannel_id;
|
||||
- *(unsigned int *)IPL_DEVICE = subchannel_id;
|
||||
+ *(unsigned long long *)IPL_DEVICE = subchannel_id;
|
||||
|
||||
/* if valid command line is given, copy it into new kernel space */
|
||||
if (_parm_addr != UNSPECIFIED_ADDRESS) {
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "boot/ipl.h"
|
||||
|
||||
-#define IPL_DEVICE 0x10404UL
|
||||
+#define IPL_DEVICE 0x10400UL
|
||||
#define INITRD_START 0x10408UL
|
||||
#define INITRD_SIZE 0x10410UL
|
||||
#define OLDMEM_BASE 0x10418UL
|
@ -1,439 +0,0 @@
|
||||
Subject: zkey: Add helper functions to build lists of APQNs
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 663d362ff3b1036476bfce9e2563272bab087013
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add helper functions to build lists of APQNs
|
||||
|
||||
The new IOCTLs are based on list of APQNs that they try to send
|
||||
the request to. Add some helper functions to build such lists
|
||||
of APQNs based on the key type, and optionally a given mkvp.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/pkey.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 383 insertions(+)
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
#define DEFAULT_KEYBITS 256
|
||||
|
||||
+#define INITIAL_APQN_ENTRIES 16
|
||||
+
|
||||
/**
|
||||
* Opens the pkey device and returns its file descriptor.
|
||||
*
|
||||
@@ -498,6 +500,387 @@ static int pkey_verifyseck2(int pkey_fd,
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Print a list of APQNs if verbose is set
|
||||
+ */
|
||||
+static void pr_verbose_apqn_list(bool verbose, struct pkey_apqn *list, u32 num)
|
||||
+{
|
||||
+ u32 i;
|
||||
+
|
||||
+ if (!verbose)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; i < num ; i++)
|
||||
+ warnx(" APQN: %02x.%04x", list[i].card, list[i].domain);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Filter a n array list of APQNs (struct pkey_apqn) by a list of APQN strings.
|
||||
+ *
|
||||
+ * @param[in] apqn_list a zero terminated array of pointers to C-strings
|
||||
+ * @param[in/out] apqns A list of APQNs as array of struct pkey_apqn to
|
||||
+ * filter. The list is modified during filtering.
|
||||
+ * @param[in/out] apqn_entries Number of entries in the list of APQNs. The
|
||||
+ * number is modified during filtering.
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int filter_apqn_list(const char **apqn_list, struct pkey_apqn **apqns,
|
||||
+ u32 *apqn_entries)
|
||||
+{
|
||||
+ unsigned int count, i, k, card, domain;
|
||||
+ struct pkey_apqn *list = *apqns;
|
||||
+ bool found;
|
||||
+
|
||||
+ if (apqn_list == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (count = 0; apqn_list[count] != NULL; count++)
|
||||
+ ;
|
||||
+ if (count == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < *apqn_entries; i++) {
|
||||
+ found = false;
|
||||
+ for (k = 0; apqn_list[k] != NULL; k++) {
|
||||
+ if (sscanf(apqn_list[k], "%x.%x", &card, &domain) != 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (list[i].card == card && list[i].domain == domain) {
|
||||
+ found = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!found) {
|
||||
+ if (i < *apqn_entries - 1)
|
||||
+ memmove(&list[i], &list[i+1],
|
||||
+ (*apqn_entries - i - 1) *
|
||||
+ sizeof(struct pkey_apqn));
|
||||
+ (*apqn_entries)--;
|
||||
+ i--;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Build a list of APQNs in the form accepted by the pkey IOCTLs from the
|
||||
+ * List of APQNs as zero terminated array of pointers to C-strings that
|
||||
+ * are usable for the CCA-AESDATA key type.
|
||||
+ *
|
||||
+ * @param[in] apqn_list a zero terminated array of pointers to C-strings
|
||||
+ * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The
|
||||
+ * list must be freed by the caller using free().
|
||||
+ * @param[out] apqn_entries Number of entries in the list of APQNs
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int build_apqn_list_for_aes_data(const char **apqn_list,
|
||||
+ struct pkey_apqn **apqns,
|
||||
+ u32 *apqn_entries, bool verbose)
|
||||
+{
|
||||
+ unsigned int card, domain, count = 0;
|
||||
+ struct pkey_apqn *list = NULL;
|
||||
+ u32 list_entries = 0;
|
||||
+ int i;
|
||||
+
|
||||
+ pr_verbose(verbose, "Build a list of APQNs for CCA-AESDATA");
|
||||
+
|
||||
+ if (apqn_list != NULL)
|
||||
+ for (count = 0; apqn_list[count] != NULL; count++)
|
||||
+ ;
|
||||
+
|
||||
+ if (count > 0) {
|
||||
+ list = util_malloc(count * sizeof(struct pkey_apqn));
|
||||
+ list_entries = count;
|
||||
+
|
||||
+ for (i = 0; apqn_list[i] != NULL; i++) {
|
||||
+ if (sscanf(apqn_list[i], "%x.%x", &card, &domain) != 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ list[i].card = card;
|
||||
+ list[i].domain = domain;
|
||||
+ }
|
||||
+
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * Although the new pkey IOCTLs do not support APQN entries
|
||||
+ * with ANY indication, build an ANY-list here. If we get here,
|
||||
+ * then the new IOCTLs are not available, and it will fall back
|
||||
+ * to the old IOCTL which do support ANY specifications.
|
||||
+ */
|
||||
+ list = util_malloc(sizeof(struct pkey_apqn));
|
||||
+ list_entries = 1;
|
||||
+
|
||||
+ list[0].card = AUTOSELECT;
|
||||
+ list[0].domain = AUTOSELECT;
|
||||
+ }
|
||||
+
|
||||
+ *apqns = list;
|
||||
+ *apqn_entries = list_entries;
|
||||
+
|
||||
+ pr_verbose(verbose, "%u APQNs found", list_entries);
|
||||
+ pr_verbose_apqn_list(verbose, list, list_entries);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Build a list of APQNs in the form accepted by the pkey IOCTLs from the
|
||||
+ * List of APQNs as zero terminated array of pointers to C-strings that
|
||||
+ * are usable for the specified key type.
|
||||
+ *
|
||||
+ * @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in] type the key type
|
||||
+ * @param[in] apqn_list a zero terminated array of pointers to C-strings
|
||||
+ * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The
|
||||
+ * list must be freed by the caller using free().
|
||||
+ * @param[out] apqn_entries Number of entries in the list of APQNs
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int build_apqn_list_for_key_type(int pkey_fd, enum pkey_key_type type,
|
||||
+ const char **apqn_list,
|
||||
+ struct pkey_apqn **apqns,
|
||||
+ u32 *apqn_entries, bool verbose)
|
||||
+{
|
||||
+ struct pkey_apqns4keytype apqns4keytype;
|
||||
+ int rc;
|
||||
+
|
||||
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
+ util_assert(apqns != NULL, "Internal error: apqns is NULL");
|
||||
+ util_assert(apqn_entries != NULL,
|
||||
+ "Internal error: apqn_entries is NULL");
|
||||
+
|
||||
+ pr_verbose(verbose, "Build a list of APQNs for key type %d", type);
|
||||
+
|
||||
+ memset(&apqns4keytype, 0, sizeof(apqns4keytype));
|
||||
+ apqns4keytype.type = type;
|
||||
+ apqns4keytype.apqn_entries = INITIAL_APQN_ENTRIES;
|
||||
+ apqns4keytype.apqns = (struct pkey_apqn *)util_malloc(
|
||||
+ apqns4keytype.apqn_entries * sizeof(struct pkey_apqn));
|
||||
+
|
||||
+ do {
|
||||
+ rc = ioctl(pkey_fd, PKEY_APQNS4KT, &apqns4keytype);
|
||||
+ if (rc == 0)
|
||||
+ break;
|
||||
+ rc = -errno;
|
||||
+ pr_verbose(verbose, "ioctl PKEY_APQNS4KT rc: %s",
|
||||
+ strerror(-rc));
|
||||
+
|
||||
+ switch (rc) {
|
||||
+ case -ENOSPC:
|
||||
+ free(apqns4keytype.apqns);
|
||||
+ apqns4keytype.apqns = (struct pkey_apqn *)
|
||||
+ util_malloc(apqns4keytype.apqn_entries *
|
||||
+ sizeof(struct pkey_apqn));
|
||||
+ continue;
|
||||
+ case -ENOTTY:
|
||||
+ /*
|
||||
+ * New IOCTL is not available: build the list
|
||||
+ * manually (Key type CCA-AESDATA only)
|
||||
+ */
|
||||
+ free(apqns4keytype.apqns);
|
||||
+
|
||||
+ if (type != PKEY_TYPE_CCA_DATA)
|
||||
+ return -ENOTSUP;
|
||||
+
|
||||
+ rc = build_apqn_list_for_aes_data(apqn_list, apqns,
|
||||
+ apqn_entries,
|
||||
+ verbose);
|
||||
+ return rc;
|
||||
+ default:
|
||||
+ goto out;
|
||||
+ }
|
||||
+ } while (rc != 0);
|
||||
+
|
||||
+ if (apqns4keytype.apqn_entries == 0) {
|
||||
+ pr_verbose(verbose, "No APQN available for key type %d", type);
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = filter_apqn_list(apqn_list, &apqns4keytype.apqns,
|
||||
+ &apqns4keytype.apqn_entries);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (apqns4keytype.apqn_entries == 0) {
|
||||
+ pr_verbose(verbose, "No APQN available for key type %d", type);
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "%u APQNs found", apqns4keytype.apqn_entries);
|
||||
+ pr_verbose_apqn_list(verbose, apqns4keytype.apqns,
|
||||
+ apqns4keytype.apqn_entries);
|
||||
+
|
||||
+out:
|
||||
+ if (rc == 0) {
|
||||
+ *apqns = apqns4keytype.apqns;
|
||||
+ *apqn_entries = apqns4keytype.apqn_entries;
|
||||
+ } else {
|
||||
+ *apqns = NULL;
|
||||
+ *apqn_entries = 0;
|
||||
+ free(apqns4keytype.apqns);
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Build a list of APQNs in the form accepted by the pkey IOCTLs from the
|
||||
+ * List of APQNs as zero terminated array of pointers to C-strings that are
|
||||
+ * usable for the specufied key.
|
||||
+ *
|
||||
+ * @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in] key the key
|
||||
+ * @param[in] keylen the length of the key
|
||||
+ * @param[in] flags PKEY_FLAGS_MATCH_xxx flags
|
||||
+ * @param[in] apqn_list a zero terminated array of pointers to C-strings
|
||||
+ * @param[out] apqns A list of APQNs as array of struct pkey_apqn. The
|
||||
+ * list must be freed by the caller using free().
|
||||
+ * @param[out] apqn_entries Number of entries in the list of APQNs
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+static int build_apqn_list_for_key(int pkey_fd, u8 *key, u32 keylen, u32 flags,
|
||||
+ const char **apqn_list,
|
||||
+ struct pkey_apqn **apqns,
|
||||
+ u32 *apqn_entries, bool verbose)
|
||||
+{
|
||||
+ struct pkey_apqns4key apqns4key;
|
||||
+ u64 mkvp;
|
||||
+ int rc;
|
||||
+
|
||||
+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
+ util_assert(key != NULL, "Internal error: key is NULL");
|
||||
+ util_assert(apqns != NULL, "Internal error: apqns is NULL");
|
||||
+ util_assert(apqn_entries != NULL,
|
||||
+ "Internal error: apqn_entries is NULL");
|
||||
+
|
||||
+ pr_verbose(verbose, "Build a list of APQNs for the key");
|
||||
+
|
||||
+ memset(&apqns4key, 0, sizeof(apqns4key));
|
||||
+ apqns4key.key = key;
|
||||
+ apqns4key.keylen = keylen;
|
||||
+ apqns4key.flags = flags;
|
||||
+ apqns4key.apqn_entries = INITIAL_APQN_ENTRIES;
|
||||
+ apqns4key.apqns = (struct pkey_apqn *)util_malloc(
|
||||
+ apqns4key.apqn_entries * sizeof(struct pkey_apqn));
|
||||
+
|
||||
+ do {
|
||||
+ rc = ioctl(pkey_fd, PKEY_APQNS4K, &apqns4key);
|
||||
+ if (rc == 0)
|
||||
+ break;
|
||||
+ rc = -errno;
|
||||
+ pr_verbose(verbose, "ioctl PKEY_APQNS4K rc: %s", strerror(-rc));
|
||||
+
|
||||
+ switch (rc) {
|
||||
+ case -ENOSPC:
|
||||
+ free(apqns4key.apqns);
|
||||
+ apqns4key.apqns = (struct pkey_apqn *)
|
||||
+ util_malloc(apqns4key.apqn_entries *
|
||||
+ sizeof(struct pkey_apqn));
|
||||
+ continue;
|
||||
+ case -ENOTTY:
|
||||
+ /*
|
||||
+ * New IOCTL is not available: build the list manually
|
||||
+ * (Key type CCA-AESDATA only)
|
||||
+ */
|
||||
+ free(apqns4key.apqns);
|
||||
+
|
||||
+ if (!is_cca_aes_data_key(key, keylen))
|
||||
+ return -ENOTSUP;
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(key, keylen,
|
||||
+ &mkvp,
|
||||
+ verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+
|
||||
+ rc = build_apqn_list_for_aes_data(apqn_list, apqns,
|
||||
+ apqn_entries,
|
||||
+ verbose);
|
||||
+ return rc;
|
||||
+ default:
|
||||
+ goto out;
|
||||
+ }
|
||||
+ } while (rc != 0);
|
||||
+
|
||||
+ if (apqns4key.apqn_entries == 0) {
|
||||
+ pr_verbose(verbose, "No APQN available for the key");
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = filter_apqn_list(apqn_list, &apqns4key.apqns,
|
||||
+ &apqns4key.apqn_entries);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (apqns4key.apqn_entries == 0) {
|
||||
+ pr_verbose(verbose, "No APQN available for the key");
|
||||
+ rc = -ENODEV;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "%u APQNs found", apqns4key.apqn_entries);
|
||||
+ pr_verbose_apqn_list(verbose, apqns4key.apqns, apqns4key.apqn_entries);
|
||||
+
|
||||
+out:
|
||||
+ if (rc == 0) {
|
||||
+ *apqns = apqns4key.apqns;
|
||||
+ *apqn_entries = apqns4key.apqn_entries;
|
||||
+ } else {
|
||||
+ *apqns = NULL;
|
||||
+ *apqn_entries = 0;
|
||||
+ free(apqns4key.apqns);
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Convert the key type string into the pkey enumeration
|
||||
+ *
|
||||
+ * @param[in] key_type the type of the key
|
||||
+ *
|
||||
+ * @returns the pkey key type or 0 for an u known key type
|
||||
+ */
|
||||
+static enum pkey_key_type key_type_to_pkey_type(const char *key_type)
|
||||
+{
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0)
|
||||
+ return PKEY_TYPE_CCA_DATA;
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0)
|
||||
+ return PKEY_TYPE_CCA_CIPHER;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * Return the size of a key blob for a specific type
|
||||
+ *
|
||||
+ * @param[in] type the type of the key
|
||||
+ *
|
||||
+ * @returns the size of the key or 0 for an invalid key type
|
||||
+ */
|
||||
+static size_t key_size_for_type(enum pkey_key_type type)
|
||||
+{
|
||||
+ switch (type) {
|
||||
+ case PKEY_TYPE_CCA_DATA:
|
||||
+ return AESDATA_KEY_SIZE;
|
||||
+ case PKEY_TYPE_CCA_CIPHER:
|
||||
+ return AESCIPHER_KEY_SIZE;
|
||||
+ default:
|
||||
+ return 0;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Generate a secure key by random
|
||||
*
|
||||
* @param[in] pkey_fd the pkey file descriptor
|
@ -1,109 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: move Linux layout definitions into separate header
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 7e37a1d4e0605ea120db18f82d039c055fd5d737
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: move Linux layout definitions into separate header
|
||||
|
||||
Move the Linux layout values to `include/boot/linux_layout.h`. This
|
||||
allows the reuse of the definitions, e.g. in assembler files, and
|
||||
later for the creation of linker scripts.
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/linux_layout.h | 33 +++++++++++++++++++++++++++++++++
|
||||
zipl/boot/stage3.h | 9 ++-------
|
||||
zipl/include/zipl.h | 3 +--
|
||||
3 files changed, 36 insertions(+), 9 deletions(-)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/boot/linux_layout.h
|
||||
@@ -0,0 +1,33 @@
|
||||
+/*
|
||||
+ * s390 Linux layout 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 LINUX_LAYOUT_H
|
||||
+#define LINUX_LAYOUT_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+/* Entry address offsets */
|
||||
+#define IMAGE_ENTRY _AC(0x10000, UL)
|
||||
+#define IMAGE_ENTRY_KDUMP _AC(0x10010, UL)
|
||||
+
|
||||
+/* Parameter address offsets */
|
||||
+#define IPL_DEVICE _AC(0x10400, UL)
|
||||
+#define INITRD_START _AC(0x10408, UL)
|
||||
+#define INITRD_SIZE _AC(0x10410, UL)
|
||||
+#define OLDMEM_BASE _AC(0x10418, UL)
|
||||
+#define OLDMEM_SIZE _AC(0x10420, UL)
|
||||
+#define COMMAND_LINE _AC(0x10480, UL)
|
||||
+
|
||||
+/* Parameter sizes */
|
||||
+#define COMMAND_LINE_SIZE 896
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* LINUX_LAYOUT_H */
|
||||
--- a/zipl/boot/stage3.h
|
||||
+++ b/zipl/boot/stage3.h
|
||||
@@ -16,14 +16,9 @@
|
||||
#include "s390.h"
|
||||
|
||||
#include "boot/ipl.h"
|
||||
+#include "boot/linux_layout.h"
|
||||
+
|
||||
|
||||
-#define IPL_DEVICE 0x10400UL
|
||||
-#define INITRD_START 0x10408UL
|
||||
-#define INITRD_SIZE 0x10410UL
|
||||
-#define OLDMEM_BASE 0x10418UL
|
||||
-#define OLDMEM_SIZE 0x10420UL
|
||||
-#define COMMAND_LINE 0x10480UL
|
||||
-#define COMMAND_LINE_SIZE 896
|
||||
#define COMMAND_LINE_EXTRA 0xE000
|
||||
|
||||
#define STAGE3_FLAG_SCSI 0x0001000000000000ULL
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -14,14 +14,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "lib/zt_common.h"
|
||||
+#include "boot/linux_layout.h"
|
||||
|
||||
#define ZIPL_MAGIC "zIPL"
|
||||
#define ZIPL_MAGIC_SIZE 4
|
||||
#define DISK_LAYOUT_ID 0x00000001
|
||||
|
||||
#define STAGE3_ENTRY 0xa000UL
|
||||
-#define IMAGE_ENTRY 0x10000UL
|
||||
-#define IMAGE_ENTRY_KDUMP 0x10010UL
|
||||
|
||||
#define STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
#define STAGE3_LOAD_ADDRESS 0xa000UL
|
@ -1,542 +0,0 @@
|
||||
Subject: zkey: Add support for generating AES CIPHER keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: b56c74fe7b6100b9a2ef17b8847cd850309cf487
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add support for generating AES CIPHER keys
|
||||
|
||||
Add support for generating secure keys using the new pkey
|
||||
IOCTLs. This allows to generate secure keys of type CCA-AESDATA
|
||||
as well as CCA-AESCIPHER, either by random inside the crypto
|
||||
card, or from a given clear key.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 60 +------------
|
||||
zkey/pkey.c | 258 +++++++++++++++++++++++++++++++++-----------------------
|
||||
zkey/pkey.h | 5 -
|
||||
zkey/zkey.c | 6 -
|
||||
4 files changed, 168 insertions(+), 161 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1667,52 +1667,6 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
- * Extracts an online card/domain pair from the specified APQns. If none of the
|
||||
- * specified APQNs are online, then -ENODEV is returned.
|
||||
- * If no APQNs are specified at all, then it uses AUTOSELECT and returns zero.
|
||||
- */
|
||||
-static int _keystore_get_card_domain(const char *apqns, unsigned int *card,
|
||||
- unsigned int *domain)
|
||||
-{
|
||||
- struct apqn_check apqn_check = { .noonlinecheck = 0, .nomsg = 1 };
|
||||
- char **apqn_list;
|
||||
- char *normalized = NULL;
|
||||
- int rc = 0;
|
||||
- int i;
|
||||
-
|
||||
- *card = AUTOSELECT;
|
||||
- *domain = AUTOSELECT;
|
||||
-
|
||||
- if (apqns == NULL)
|
||||
- return 0;
|
||||
-
|
||||
- apqn_list = str_list_split(apqns);
|
||||
- if (apqn_list[0] == NULL)
|
||||
- goto out;
|
||||
-
|
||||
- for (i = 0; apqn_list[i] != NULL; i++) {
|
||||
- rc = _keystore_apqn_check(apqn_list[i], 0, 0, &normalized,
|
||||
- &apqn_check);
|
||||
- if (normalized != NULL)
|
||||
- free(normalized);
|
||||
- if (rc == -EINVAL)
|
||||
- goto out;
|
||||
- if (rc != 0)
|
||||
- continue;
|
||||
-
|
||||
- if (sscanf(apqn_list[i], "%x.%x", card, domain) == 2)
|
||||
- goto found;
|
||||
- }
|
||||
-
|
||||
- warnx("None of the specified APQNs is online or of type CCA");
|
||||
- rc = -ENODEV;
|
||||
-found:
|
||||
-out:
|
||||
- str_list_free_string_array(apqn_list);
|
||||
- return rc;
|
||||
-}
|
||||
-
|
||||
-/**
|
||||
* Generates a secure key by random and adds it to the key store
|
||||
*
|
||||
* @param[in] keystore the key store
|
||||
@@ -1748,7 +1702,7 @@ int keystore_generate_key(struct keystor
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
- unsigned int card, domain;
|
||||
+ char **apqn_list = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
@@ -1776,21 +1730,21 @@ int keystore_generate_key(struct keystor
|
||||
goto out_free_key_filenames;
|
||||
}
|
||||
|
||||
- rc = _keystore_get_card_domain(apqns, &card, &domain);
|
||||
- if (rc != 0)
|
||||
- goto out_free_key_filenames;
|
||||
+ if (apqns != NULL)
|
||||
+ apqn_list = str_list_split(apqns);
|
||||
|
||||
if (clear_key_file == NULL)
|
||||
rc = generate_secure_key_random(pkey_fd,
|
||||
file_names.skey_filename,
|
||||
keybits, xts, key_type,
|
||||
- card, domain,
|
||||
+ (const char **)apqn_list,
|
||||
keystore->verbose);
|
||||
else
|
||||
rc = generate_secure_key_clear(pkey_fd,
|
||||
file_names.skey_filename,
|
||||
keybits, xts, clear_key_file,
|
||||
- key_type, card, domain,
|
||||
+ key_type,
|
||||
+ (const char **)apqn_list,
|
||||
keystore->verbose);
|
||||
if (rc != 0)
|
||||
goto out_free_props;
|
||||
@@ -1812,6 +1766,8 @@ int keystore_generate_key(struct keystor
|
||||
file_names.info_filename);
|
||||
|
||||
out_free_props:
|
||||
+ if (apqn_list != NULL)
|
||||
+ str_list_free_string_array(apqn_list);
|
||||
if (key_props != NULL)
|
||||
properties_free(key_props);
|
||||
if (rc != 0)
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -888,86 +888,109 @@ static size_t key_size_for_type(enum pke
|
||||
* @param[in] keybits the cryptographic size of the key in bits
|
||||
* @param[in] xts if true an XTS key is generated
|
||||
* @param[in] key_type the type of the key
|
||||
- * @param[in] card the card number to use (or AUTOSELECT)
|
||||
- * @param[in] domain the domain number to use (or AUTOSELECT)
|
||||
+ * @param[in] apqns a zero terminated array of pointers to APQN-strings,
|
||||
+ * or NULL for AUTOSELECT
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts, const char *key_type,
|
||||
- u16 card, u16 domain, bool verbose)
|
||||
+ const char **apqns, bool verbose)
|
||||
{
|
||||
- struct pkey_genseck gensec;
|
||||
- size_t secure_key_size;
|
||||
- u8 *secure_key;
|
||||
+ struct pkey_genseck2 genseck2;
|
||||
+ size_t secure_key_size, size;
|
||||
+ u8 *secure_key = NULL;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
|
||||
util_assert(key_type != NULL, "Internal error: key_type is NULL");
|
||||
|
||||
- if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) != 0) {
|
||||
- warnx("Invalid key-type: %s", key_type);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
if (keybits == 0)
|
||||
keybits = DEFAULT_KEYBITS;
|
||||
|
||||
- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts);
|
||||
- secure_key = util_malloc(secure_key_size);
|
||||
+ pr_verbose(verbose, "Generate secure key by random");
|
||||
|
||||
- pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
|
||||
+ memset(&genseck2, 0, sizeof(genseck2));
|
||||
|
||||
- gensec.cardnr = card;
|
||||
- gensec.domain = domain;
|
||||
- switch (keybits) {
|
||||
- case 128:
|
||||
- gensec.keytype = PKEY_KEYTYPE_AES_128;
|
||||
- break;
|
||||
- case 192:
|
||||
- if (xts) {
|
||||
- warnx("Invalid value for '--keybits'|'-c' "
|
||||
- "for XTS: '%lu'", keybits);
|
||||
- rc = -EINVAL;
|
||||
- goto out;
|
||||
- }
|
||||
- gensec.keytype = PKEY_KEYTYPE_AES_192;
|
||||
- break;
|
||||
- case 256:
|
||||
- gensec.keytype = PKEY_KEYTYPE_AES_256;
|
||||
- break;
|
||||
- default:
|
||||
+ genseck2.type = key_type_to_pkey_type(key_type);
|
||||
+ if (genseck2.type == 0) {
|
||||
+ warnx("Key-type not supported; %s", key_type);
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
+
|
||||
+ genseck2.size = keybits_to_keysize(keybits);
|
||||
+ if (genseck2.size == 0) {
|
||||
warnx("Invalid value for '--keybits'/'-c': '%lu'", keybits);
|
||||
- rc = -EINVAL;
|
||||
- goto out;
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (keybits == 192 && xts) {
|
||||
+ warnx("Invalid value for '--keybits'|'-c' "
|
||||
+ "for XTS: '%lu'", keybits);
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
- rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
|
||||
- if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- warnx("Failed to generate a secure key: %s", strerror(errno));
|
||||
- warnx("Make sure that all available CCA crypto adapters are "
|
||||
- "setup with the same master key");
|
||||
- goto out;
|
||||
+ rc = build_apqn_list_for_key_type(pkey_fd, genseck2.type, apqns,
|
||||
+ &genseck2.apqns,
|
||||
+ &genseck2.apqn_entries, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ if (rc == -ENODEV || rc == -ENOTSUP)
|
||||
+ warnx("No APQN is available that can generate a secure "
|
||||
+ "key of type %s", key_type);
|
||||
+ else
|
||||
+ warnx("Failed to build a list of APQNs that can "
|
||||
+ "generate a secure key of type %s: %s", key_type,
|
||||
+ strerror(-rc));
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
- memcpy(secure_key, &gensec.seckey, AESDATA_KEY_SIZE);
|
||||
+ size = key_size_for_type(genseck2.type);
|
||||
+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(size, xts);
|
||||
+ secure_key = util_zalloc(secure_key_size);
|
||||
+
|
||||
+ genseck2.key = secure_key;
|
||||
+ genseck2.keylen = size;
|
||||
+
|
||||
+ rc = pkey_genseck2(pkey_fd, &genseck2, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to generate a secure key: %s", strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
|
||||
if (xts) {
|
||||
- rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
|
||||
- if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- warnx("Failed to generate a secure key: %s",
|
||||
- strerror(errno));
|
||||
- warnx("Make sure that all available CCA crypto "
|
||||
- "adapters are setup with the same master key");
|
||||
+ free(genseck2.apqns);
|
||||
+ genseck2.apqns = NULL;
|
||||
+ genseck2.apqn_entries = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Ensure to generate 2nd key with an APQN that has the same
|
||||
+ * master key that is used by the 1st key.
|
||||
+ */
|
||||
+ rc = build_apqn_list_for_key(pkey_fd, secure_key, size,
|
||||
+ PKEY_FLAGS_MATCH_CUR_MKVP, apqns,
|
||||
+ &genseck2.apqns,
|
||||
+ &genseck2.apqn_entries, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ if (rc == -ENODEV || rc == -ENOTSUP)
|
||||
+ warnx("No APQN is available that can generate "
|
||||
+ "a secure key of type %s", key_type);
|
||||
+ else
|
||||
+ warnx("Failed to build a list of APQNs that "
|
||||
+ "can generate a secure key of type %s: "
|
||||
+ "%s", key_type, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key + AESDATA_KEY_SIZE, &gensec.seckey,
|
||||
- AESDATA_KEY_SIZE);
|
||||
+ genseck2.key = secure_key + size;
|
||||
+ genseck2.keylen = size;
|
||||
+
|
||||
+ rc = pkey_genseck2(pkey_fd, &genseck2, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to generate a secure key: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
pr_verbose(verbose, "Successfully generated a secure key");
|
||||
@@ -975,6 +998,7 @@ int generate_secure_key_random(int pkey_
|
||||
rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
|
||||
|
||||
out:
|
||||
+ free(genseck2.apqns);
|
||||
free(secure_key);
|
||||
return rc;
|
||||
}
|
||||
@@ -991,8 +1015,8 @@ out:
|
||||
* @param[in] xts if true an XTS key is generated
|
||||
* @param[in] clearkeyfile the file name of the clear key to read
|
||||
* @param[in] key_type the type of the key
|
||||
- * @param[in] card the card number to use (or AUTOSELECT)
|
||||
- * @param[in] domain the domain number to use (or AUTOSELECT)
|
||||
+ * @param[in] apqns a zero terminated array of pointers to APQN-strings,
|
||||
+ * or NULL for AUTOSELECT
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
@@ -1000,14 +1024,14 @@ out:
|
||||
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts,
|
||||
const char *clearkeyfile, const char *key_type,
|
||||
- u16 card, u16 domain,
|
||||
- bool verbose)
|
||||
+ const char **apqns, bool verbose)
|
||||
{
|
||||
- struct pkey_clr2seck clr2sec;
|
||||
+ struct pkey_clr2seck2 clr2seck2;
|
||||
size_t secure_key_size;
|
||||
size_t clear_key_size;
|
||||
u8 *secure_key;
|
||||
u8 *clear_key;
|
||||
+ size_t size;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
@@ -1016,70 +1040,99 @@ int generate_secure_key_clear(int pkey_f
|
||||
"Internal error: clearkeyfile is NULL");
|
||||
util_assert(key_type != NULL, "Internal error: key_type is NULL");
|
||||
|
||||
- if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) != 0) {
|
||||
- warnx("Invalid key-type: %s", key_type);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(AESDATA_KEY_SIZE, xts);
|
||||
- secure_key = util_malloc(secure_key_size);
|
||||
+ pr_verbose(verbose, "Generate secure key from a clear key");
|
||||
|
||||
clear_key = read_clear_key(clearkeyfile, keybits, xts, &clear_key_size,
|
||||
verbose);
|
||||
if (clear_key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
- pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
|
||||
+ memset(&clr2seck2, 0, sizeof(clr2seck2));
|
||||
+
|
||||
+ memcpy(&clr2seck2.clrkey, clear_key,
|
||||
+ HALF_KEYSIZE_FOR_XTS(clear_key_size, xts));
|
||||
+
|
||||
+ clr2seck2.type = key_type_to_pkey_type(key_type);
|
||||
+ if (clr2seck2.type == 0) {
|
||||
+ warnx("Key-type not supported; %s", key_type);
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
|
||||
- clr2sec.cardnr = card;
|
||||
- clr2sec.domain = domain;
|
||||
- switch (HALF_KEYSIZE_FOR_XTS(clear_key_size * 8, xts)) {
|
||||
- case 128:
|
||||
- clr2sec.keytype = PKEY_KEYTYPE_AES_128;
|
||||
- break;
|
||||
- case 192:
|
||||
- clr2sec.keytype = PKEY_KEYTYPE_AES_192;
|
||||
- break;
|
||||
- case 256:
|
||||
- clr2sec.keytype = PKEY_KEYTYPE_AES_256;
|
||||
- break;
|
||||
- default:
|
||||
+ clr2seck2.size = keybits_to_keysize(HALF_KEYSIZE_FOR_XTS(
|
||||
+ clear_key_size * 8, xts));
|
||||
+ if (clr2seck2.size == 0) {
|
||||
warnx("Invalid clear key size: '%lu' bytes", clear_key_size);
|
||||
- rc = -EINVAL;
|
||||
- goto out;
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ if (keybits == 192 && xts) {
|
||||
+ warnx("Invalid clear key size for XTS: '%lu' bytes",
|
||||
+ clear_key_size);
|
||||
+ return -EINVAL;
|
||||
}
|
||||
|
||||
- memcpy(&clr2sec.clrkey, clear_key,
|
||||
- HALF_KEYSIZE_FOR_XTS(clear_key_size, xts));
|
||||
+ rc = build_apqn_list_for_key_type(pkey_fd, clr2seck2.type, apqns,
|
||||
+ &clr2seck2.apqns,
|
||||
+ &clr2seck2.apqn_entries, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ if (rc == -ENODEV || rc == -ENOTSUP)
|
||||
+ warnx("No APQN is available that can generate a secure "
|
||||
+ "key of type %s", key_type);
|
||||
+ else
|
||||
+ warnx("Failed to build a list of APQNs that can "
|
||||
+ "generate a secure key of type %s: %s", key_type,
|
||||
+ strerror(-rc));
|
||||
+ return rc;
|
||||
+ }
|
||||
|
||||
- rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
|
||||
- if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- warnx("Failed to generate a secure key from a "
|
||||
- "clear key: %s", strerror(errno));
|
||||
- warnx("Make sure that all available CCA crypto adapters are "
|
||||
- "setup with the same master key");
|
||||
+ size = key_size_for_type(clr2seck2.type);
|
||||
+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(size, xts);
|
||||
+ secure_key = util_zalloc(secure_key_size);
|
||||
+
|
||||
+ clr2seck2.key = secure_key;
|
||||
+ clr2seck2.keylen = size;
|
||||
+
|
||||
+ rc = pkey_clr2seck2(pkey_fd, &clr2seck2, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to generate a secure key: %s", strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key, &clr2sec.seckey, AESDATA_KEY_SIZE);
|
||||
-
|
||||
if (xts) {
|
||||
- memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2,
|
||||
+ free(clr2seck2.apqns);
|
||||
+ clr2seck2.apqns = NULL;
|
||||
+ clr2seck2.apqn_entries = 0;
|
||||
+
|
||||
+ memcpy(&clr2seck2.clrkey, clear_key + clear_key_size / 2,
|
||||
clear_key_size / 2);
|
||||
|
||||
- rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
|
||||
- if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- warnx("Failed to generate a secure key from "
|
||||
- "a clear key: %s", strerror(errno));
|
||||
- warnx("Make sure that all available CCA crypto "
|
||||
- "adapters are setup with the same master key");
|
||||
+ /*
|
||||
+ * Ensure to generate 2nd key with an APQN that has the same
|
||||
+ * master key that is used by the 1st key.
|
||||
+ */
|
||||
+ rc = build_apqn_list_for_key(pkey_fd, secure_key, size,
|
||||
+ PKEY_FLAGS_MATCH_CUR_MKVP, apqns,
|
||||
+ &clr2seck2.apqns,
|
||||
+ &clr2seck2.apqn_entries, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ if (rc == -ENODEV || rc == -ENOTSUP)
|
||||
+ warnx("No APQN is available that can generate "
|
||||
+ "a secure key of type %s", key_type);
|
||||
+ else
|
||||
+ warnx("Failed to build a list of APQNs that "
|
||||
+ "can generate a secure key of type %s: "
|
||||
+ "%s", key_type, strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
- memcpy(secure_key + AESDATA_KEY_SIZE, &clr2sec.seckey,
|
||||
- AESDATA_KEY_SIZE);
|
||||
+ clr2seck2.key = secure_key + size;
|
||||
+ clr2seck2.keylen = size;
|
||||
+
|
||||
+ rc = pkey_clr2seck2(pkey_fd, &clr2seck2, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to generate a secure key: %s",
|
||||
+ strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
pr_verbose(verbose,
|
||||
@@ -1088,10 +1141,11 @@ int generate_secure_key_clear(int pkey_f
|
||||
rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
|
||||
|
||||
out:
|
||||
- memset(&clr2sec, 0, sizeof(clr2sec));
|
||||
+ memset(&clr2seck2, 0, sizeof(clr2seck2));
|
||||
memset(clear_key, 0, clear_key_size);
|
||||
free(clear_key);
|
||||
free(secure_key);
|
||||
+ free(clr2seck2.apqns);
|
||||
return rc;
|
||||
}
|
||||
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -235,13 +235,12 @@ int open_pkey_device(bool verbose);
|
||||
|
||||
int generate_secure_key_random(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts, const char *key_type,
|
||||
- u16 card, u16 domain, bool verbose);
|
||||
+ const char **apqns, bool verbose);
|
||||
|
||||
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
|
||||
size_t keybits, bool xts,
|
||||
const char *clearkeyfile, const char *key_type,
|
||||
- u16 card, u16 domain,
|
||||
- bool verbose);
|
||||
+ const char **apqns, bool verbose);
|
||||
|
||||
u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
|
||||
bool verbose);
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1029,8 +1029,7 @@ static int command_generate_clear(void)
|
||||
rc = generate_secure_key_clear(g.pkey_fd, g.pos_arg,
|
||||
g.keybits, g.xts,
|
||||
g.clearkeyfile, g.key_type,
|
||||
- AUTOSELECT, AUTOSELECT,
|
||||
- g.verbose);
|
||||
+ NULL, g.verbose);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1046,8 +1045,7 @@ static int command_generate_random(void)
|
||||
|
||||
rc = generate_secure_key_random(g.pkey_fd, g.pos_arg,
|
||||
g.keybits, g.xts, g.key_type,
|
||||
- AUTOSELECT, AUTOSELECT,
|
||||
- g.verbose);
|
||||
+ NULL, g.verbose);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: tape0: use constants defined in linux_layout.h
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: c871050097ecb2ec83cf3018ea36e01cd22cbe7d
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: tape0: use constants defined in linux_layout.h
|
||||
|
||||
Use the constants defined in `linux_layout.h`. Therefore move the
|
||||
`PARMAREA` address offset to `linux_layout.h` and include the header.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/linux_layout.h | 1 +
|
||||
zipl/boot/tape0.S | 14 +++-----------
|
||||
2 files changed, 4 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/include/boot/linux_layout.h
|
||||
+++ b/include/boot/linux_layout.h
|
||||
@@ -17,6 +17,7 @@
|
||||
#define IMAGE_ENTRY_KDUMP _AC(0x10010, UL)
|
||||
|
||||
/* Parameter address offsets */
|
||||
+#define PARMAREA _AC(0x10400, UL)
|
||||
#define IPL_DEVICE _AC(0x10400, UL)
|
||||
#define INITRD_START _AC(0x10408, UL)
|
||||
#define INITRD_SIZE _AC(0x10410, UL)
|
||||
--- a/zipl/boot/tape0.S
|
||||
+++ b/zipl/boot/tape0.S
|
||||
@@ -8,29 +8,21 @@
|
||||
#
|
||||
|
||||
#include "boot/sigp.h"
|
||||
+#include "boot/linux_layout.h"
|
||||
|
||||
IPL_BS = 1024 # block size for tape access
|
||||
IPL_OFF = 0x4000 # temporary kernel load addr
|
||||
-COMMAND_LINE_SIZE = 896 # max command line length
|
||||
-KERNEL_OFF = 0x10000 # kernel start code offset
|
||||
+KERNEL_OFF = IMAGE_ENTRY # kernel start code offset
|
||||
# relative to image start
|
||||
__LC_IO_NEW_PSW = 0x1f0 # IO New PSW addr
|
||||
|
||||
|
||||
-# Parameter address offsets
|
||||
-
|
||||
-PARMAREA = 0x10400 # Parameter area offset
|
||||
-IPL_DEVICE = 0x10400 # IPL device offset
|
||||
-INITRD_START = 0x10408 # ramdisk addr offset
|
||||
-INITRD_SIZE = 0x10410 # ramdisk size offset
|
||||
-COMMAND_LINE = 0x10480 # command line offset
|
||||
-
|
||||
# Default IPL parameter - will be overwritten by zIPL
|
||||
|
||||
RAMDISK_ORIGIN = 0x800000 # default ramdisk load addr
|
||||
RAMDISK_SIZE = 0x800000 # default ramdisk size
|
||||
PARMFILE_ADDR = 0x1000 # default parmfile load addr
|
||||
-KERNEL_ADDR = 0x10000 # default kernel load addr
|
||||
+KERNEL_ADDR = IMAGE_ENTRY # default kernel load addr
|
||||
|
||||
|
||||
.org 0x0
|
@ -1,425 +0,0 @@
|
||||
Subject: zkey: Add support for validating AES CIPHER keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 0fab6bdf2aa01e093f8a4f3d86c9183889a587fe
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add support for validating AES CIPHER keys
|
||||
|
||||
Add support for validating secure keys using the new pkey
|
||||
IOCTLs. This allows to validate secure keys of type CCA-AESDATA
|
||||
as well as CCA-AESCIPHER.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 24 ++++++
|
||||
zkey/pkey.c | 178 +++++++++++++++++++++++++------------------------
|
||||
zkey/pkey.h | 2
|
||||
zkey/zkey-cryptsetup.c | 6 -
|
||||
zkey/zkey.c | 4 -
|
||||
5 files changed, 120 insertions(+), 94 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -2451,8 +2451,10 @@ static int _keystore_process_validate(st
|
||||
void *private)
|
||||
{
|
||||
struct validate_info *info = (struct validate_info *)private;
|
||||
+ char **apqn_list = NULL;
|
||||
size_t clear_key_bitsize;
|
||||
size_t secure_key_size;
|
||||
+ char *apqns = NULL;
|
||||
u8 *secure_key;
|
||||
int is_old_mk;
|
||||
int rc, valid;
|
||||
@@ -2469,9 +2471,13 @@ static int _keystore_process_validate(st
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
+ if (apqns != NULL)
|
||||
+ apqn_list = str_list_split(apqns);
|
||||
+
|
||||
rc = validate_secure_key(info->pkey_fd, secure_key, secure_key_size,
|
||||
&clear_key_bitsize, &is_old_mk,
|
||||
- keystore->verbose);
|
||||
+ (const char **)apqn_list, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
valid = 0;
|
||||
info->num_invalid++;
|
||||
@@ -2510,6 +2516,10 @@ static int _keystore_process_validate(st
|
||||
info->num_warnings++;
|
||||
|
||||
out:
|
||||
+ if (apqns != NULL)
|
||||
+ free(apqns);
|
||||
+ if (apqn_list != NULL)
|
||||
+ str_list_free_string_array(apqn_list);
|
||||
if (rc != 0)
|
||||
pr_verbose(keystore, "Failed to validate key '%s': %s",
|
||||
name, strerror(-rc));
|
||||
@@ -2726,7 +2736,9 @@ static int _keystore_process_reencipher(
|
||||
struct reencipher_params params = info->params;
|
||||
size_t clear_key_bitsize;
|
||||
size_t secure_key_size;
|
||||
+ char **apqn_list = NULL;
|
||||
u8 *secure_key = NULL;
|
||||
+ char *apqns = NULL;
|
||||
char *out_file;
|
||||
int is_old_mk;
|
||||
char *temp;
|
||||
@@ -2763,9 +2775,13 @@ static int _keystore_process_reencipher(
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
+ if (apqns != NULL)
|
||||
+ apqn_list = str_list_split(apqns);
|
||||
+
|
||||
rc = validate_secure_key(info->pkey_fd, secure_key, secure_key_size,
|
||||
&clear_key_bitsize, &is_old_mk,
|
||||
- keystore->verbose);
|
||||
+ (const char **)apqn_list, keystore->verbose);
|
||||
if (rc != 0) {
|
||||
if (params.complete) {
|
||||
warnx("Key '%s' is not valid, re-enciphering is not "
|
||||
@@ -2864,6 +2880,10 @@ static int _keystore_process_reencipher(
|
||||
info->num_reenciphered++;
|
||||
|
||||
out:
|
||||
+ if (apqns != NULL)
|
||||
+ free(apqns);
|
||||
+ if (apqn_list != NULL)
|
||||
+ str_list_free_string_array(apqn_list);
|
||||
if (secure_key != NULL)
|
||||
free(secure_key);
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -1153,84 +1153,58 @@ out:
|
||||
* Validates an XTS secure key (the second part)
|
||||
*
|
||||
* @param[in] pkey_fd the pkey file descriptor
|
||||
+ * @param[in] apqn the APQN to verify the key with
|
||||
* @param[in] secure_key a buffer containing the secure key
|
||||
* @param[in] secure_key_size the secure key size
|
||||
* @param[in] part1_keysize the key size of the first key part
|
||||
- * @param[in] part1_attributes the attributes of the first key part
|
||||
+ * @param[in] part1_flags the flags of the first key part
|
||||
* @param[out] clear_key_bitsize on return , the cryptographic size of the
|
||||
* clear key
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
*/
|
||||
-static int validate_secure_xts_key(int pkey_fd,
|
||||
+static int validate_secure_xts_key(int pkey_fd, struct pkey_apqn *apqn,
|
||||
u8 *secure_key, size_t secure_key_size,
|
||||
- u16 part1_keysize, u32 part1_attributes,
|
||||
- size_t *clear_key_bitsize, bool verbose)
|
||||
+ enum pkey_key_size part1_keysize,
|
||||
+ u32 part1_flags, size_t *clear_key_bitsize,
|
||||
+ bool verbose)
|
||||
{
|
||||
- struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
- struct pkey_verifykey verifykey;
|
||||
- struct aesdatakeytoken *token2;
|
||||
+ struct pkey_verifykey2 verifykey2;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
+ util_assert(apqn != NULL, "Internal error: apqn is NULL");
|
||||
|
||||
- /* XTS uses 2 secure key tokens concatenated to each other */
|
||||
- token2 = (struct aesdatakeytoken *)(secure_key + AESDATA_KEY_SIZE);
|
||||
+ memset(&verifykey2, 0, sizeof(verifykey2));
|
||||
+ verifykey2.key = secure_key + (secure_key_size / 2);
|
||||
+ verifykey2.keylen = secure_key_size / 2;
|
||||
+ verifykey2.cardnr = apqn->card;
|
||||
+ verifykey2.domain = apqn->domain;
|
||||
|
||||
- if (secure_key_size != 2 * AESDATA_KEY_SIZE) {
|
||||
- pr_verbose(verbose, "Size of secure key is too small: "
|
||||
- "%lu expected %lu", secure_key_size,
|
||||
- 2 * AESDATA_KEY_SIZE);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- if (token->bitsize != token2->bitsize) {
|
||||
- pr_verbose(verbose, "XTS secure key contains 2 clear keys of "
|
||||
- "different sizes");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- if (token->keysize != token2->keysize) {
|
||||
- pr_verbose(verbose, "XTS secure key contains 2 keys of "
|
||||
- "different sizes");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
- if (memcmp(&token->mkvp, &token2->mkvp, sizeof(token->mkvp)) != 0) {
|
||||
- pr_verbose(verbose, "XTS secure key contains 2 keys using "
|
||||
- "different CCA master keys");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- memcpy(&verifykey.seckey, token2, sizeof(verifykey.seckey));
|
||||
-
|
||||
- rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
|
||||
+ rc = pkey_verifyseck2(pkey_fd, &verifykey2, verbose);
|
||||
if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- pr_verbose(verbose, "Failed to validate a secure key: %s",
|
||||
- strerror(-rc));
|
||||
+ pr_verbose(verbose, "Failed to validate the 2nd part of the "
|
||||
+ "XTS secure key on APQN %02x.%04x: %s", apqn->card,
|
||||
+ apqn->domain, strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
- if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
|
||||
- pr_verbose(verbose, "Secure key is not an AES key");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- if (verifykey.keysize != part1_keysize) {
|
||||
+ if (verifykey2.size != part1_keysize) {
|
||||
pr_verbose(verbose, "XTS secure key contains 2 keys using "
|
||||
"different key sizes");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (verifykey.attributes != part1_attributes) {
|
||||
+ if (verifykey2.flags != part1_flags) {
|
||||
pr_verbose(verbose, "XTS secure key contains 2 keys using "
|
||||
- "different attributes");
|
||||
+ "different master keys");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- if (clear_key_bitsize)
|
||||
- *clear_key_bitsize += verifykey.keysize;
|
||||
+ if (clear_key_bitsize && verifykey2.size != PKEY_SIZE_UNKNOWN)
|
||||
+ *clear_key_bitsize += verifykey2.size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1245,6 +1219,8 @@ static int validate_secure_xts_key(int p
|
||||
* clear key
|
||||
* @param[out] is_old_mk in return set to 1 to indicate if the secure key
|
||||
* is currently enciphered by the OLD CCA master key
|
||||
+ * @param[in] apqns a zero terminated array of pointers to APQN-strings,
|
||||
+ * or NULL for AUTOSELECT
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
*
|
||||
* @returns 0 on success, a negative errno in case of an error
|
||||
@@ -1252,59 +1228,89 @@ static int validate_secure_xts_key(int p
|
||||
int validate_secure_key(int pkey_fd,
|
||||
u8 *secure_key, size_t secure_key_size,
|
||||
size_t *clear_key_bitsize, int *is_old_mk,
|
||||
- bool verbose)
|
||||
+ const char **apqns, bool verbose)
|
||||
{
|
||||
- struct aesdatakeytoken *token = (struct aesdatakeytoken *)secure_key;
|
||||
- struct pkey_verifykey verifykey;
|
||||
+ struct pkey_verifykey2 verifykey2;
|
||||
+ struct pkey_apqn *list = NULL;
|
||||
+ u32 i, list_entries = 0;
|
||||
+ bool xts, valid;
|
||||
int rc;
|
||||
|
||||
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
|
||||
- if (secure_key_size < AESDATA_KEY_SIZE) {
|
||||
- pr_verbose(verbose, "Size of secure key is too small: "
|
||||
- "%lu expected %lu", secure_key_size,
|
||||
- AESDATA_KEY_SIZE);
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey));
|
||||
+ xts = is_xts_key(secure_key, secure_key_size);
|
||||
|
||||
- rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
|
||||
- if (rc < 0) {
|
||||
- rc = -errno;
|
||||
- pr_verbose(verbose, "Failed to validate a secure key: %s",
|
||||
- strerror(-rc));
|
||||
+ rc = build_apqn_list_for_key(pkey_fd, secure_key,
|
||||
+ HALF_KEYSIZE_FOR_XTS(secure_key_size, xts),
|
||||
+ PKEY_FLAGS_MATCH_CUR_MKVP |
|
||||
+ PKEY_FLAGS_MATCH_ALT_MKVP,
|
||||
+ apqns, &list, &list_entries, verbose);
|
||||
+ if (rc != 0) {
|
||||
+ pr_verbose(verbose, "Failed to build a list of APQNs that can "
|
||||
+ "validate this secure key: %s", strerror(-rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
- if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
|
||||
- pr_verbose(verbose, "Secure key is not an AES key");
|
||||
- return -EINVAL;
|
||||
- }
|
||||
-
|
||||
- if (clear_key_bitsize)
|
||||
- *clear_key_bitsize = verifykey.keysize;
|
||||
-
|
||||
- /* XTS uses 2 secure key tokens concatenated to each other */
|
||||
- if (secure_key_size > AESDATA_KEY_SIZE) {
|
||||
- rc = validate_secure_xts_key(pkey_fd,
|
||||
- secure_key, secure_key_size,
|
||||
- verifykey.keysize,
|
||||
- verifykey.attributes,
|
||||
- clear_key_bitsize,
|
||||
- verbose);
|
||||
- if (rc != 0)
|
||||
- return rc;
|
||||
+ if (is_old_mk != NULL)
|
||||
+ *is_old_mk = true;
|
||||
+ if (clear_key_bitsize != NULL)
|
||||
+ *clear_key_bitsize = 0;
|
||||
+
|
||||
+ valid = false;
|
||||
+ for (i = 0; i < list_entries; i++) {
|
||||
+ memset(&verifykey2, 0, sizeof(verifykey2));
|
||||
+ verifykey2.key = secure_key;
|
||||
+ verifykey2.keylen = HALF_KEYSIZE_FOR_XTS(secure_key_size, xts);
|
||||
+ verifykey2.cardnr = list[i].card;
|
||||
+ verifykey2.domain = list[i].domain;
|
||||
+
|
||||
+ rc = pkey_verifyseck2(pkey_fd, &verifykey2, verbose);
|
||||
+ if (rc < 0) {
|
||||
+ pr_verbose(verbose, "Failed to validate the secure key "
|
||||
+ "on APQN %02x.%04x: %s", list[i].card,
|
||||
+ list[i].domain, strerror(-rc));
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (is_xts_key(secure_key, secure_key_size)) {
|
||||
+ rc = validate_secure_xts_key(pkey_fd, &list[i],
|
||||
+ secure_key,
|
||||
+ secure_key_size,
|
||||
+ verifykey2.size,
|
||||
+ verifykey2.flags,
|
||||
+ clear_key_bitsize,
|
||||
+ verbose);
|
||||
+ if (rc != 0)
|
||||
+ continue;
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ valid = true;
|
||||
+
|
||||
+ if (clear_key_bitsize) {
|
||||
+ if (verifykey2.size != PKEY_SIZE_UNKNOWN)
|
||||
+ *clear_key_bitsize += verifykey2.size;
|
||||
+ clear_key_bitsize = NULL; /* Set it only once */
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * If at least one of the APQNs have a matching current MK,
|
||||
+ * then don't report OLD, even if some match the old MK.
|
||||
+ */
|
||||
+ if (is_old_mk &&
|
||||
+ (verifykey2.flags & PKEY_FLAGS_MATCH_CUR_MKVP))
|
||||
+ *is_old_mk = false;
|
||||
}
|
||||
|
||||
- if (is_old_mk)
|
||||
- *is_old_mk = (verifykey.attributes &
|
||||
- PKEY_VERIFY_ATTR_OLD_MKVP) != 0;
|
||||
+ if (!valid)
|
||||
+ return -ENODEV;
|
||||
|
||||
pr_verbose(verbose, "Secure key validation completed successfully");
|
||||
|
||||
- return 0;
|
||||
+ if (list != NULL)
|
||||
+ free(list);
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -251,7 +251,7 @@ int write_secure_key(const char *keyfile
|
||||
int validate_secure_key(int pkey_fd,
|
||||
u8 *secure_key, size_t secure_key_size,
|
||||
size_t *clear_key_bitsize, int *is_old_mk,
|
||||
- bool verbose);
|
||||
+ const char **apqns, bool verbose);
|
||||
|
||||
int generate_key_verification_pattern(const u8 *key, size_t key_size,
|
||||
char *vp, size_t vp_len, bool verbose);
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -1492,7 +1492,7 @@ static int validate_keyslot(int keyslot,
|
||||
keyslot = rc;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, (u8 *)vkey, vkeysize, clear_keysize,
|
||||
- &is_old, g.verbose);
|
||||
+ &is_old, NULL, g.verbose);
|
||||
if (rc != 0) {
|
||||
if (invalid_msg != NULL)
|
||||
warnx("%s", invalid_msg);
|
||||
@@ -1972,7 +1972,7 @@ static int command_validate(void)
|
||||
goto out;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, (u8 *)key, keysize, &clear_keysize,
|
||||
- &is_old_mk, g.verbose);
|
||||
+ &is_old_mk, NULL, g.verbose);
|
||||
is_valid = (rc == 0);
|
||||
|
||||
token = find_token(g.cd, PAES_REENC_TOKEN_NAME);
|
||||
@@ -2139,7 +2139,7 @@ static int command_setkey(void)
|
||||
goto out;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, newkey, newkey_size, NULL,
|
||||
- &is_old_mk, g.verbose);
|
||||
+ &is_old_mk, NULL, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("The secure key in file '%s' is not valid",
|
||||
g.master_key_file);
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1188,7 +1188,7 @@ static int command_reencipher_file(void)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
|
||||
- &is_old_mk, g.verbose);
|
||||
+ &is_old_mk, NULL, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
||||
rc = EXIT_FAILURE;
|
||||
@@ -1404,7 +1404,7 @@ static int command_validate_file(void)
|
||||
return EXIT_FAILURE;
|
||||
|
||||
rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size,
|
||||
- &clear_key_size, &is_old_mk, g.verbose);
|
||||
+ &clear_key_size, &is_old_mk, NULL, g.verbose);
|
||||
if (rc != 0) {
|
||||
warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
||||
rc = EXIT_FAILURE;
|
@ -1,45 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: use STAGE3_ENTRY for STAGE3_LOAD_ADDRESS
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: c07104dbc734ec6e55accf1bd2091b251f312ed8
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: use STAGE3_ENTRY for STAGE3_LOAD_ADDRESS
|
||||
|
||||
Use STAGE3_ENTRY for STAGE3_LOAD_ADDRESS as they have the same value
|
||||
and this makes it more clear that the load address of stage3 is also
|
||||
its entry point.
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/include/zipl.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -23,7 +23,7 @@
|
||||
#define STAGE3_ENTRY 0xa000UL
|
||||
|
||||
#define STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
-#define STAGE3_LOAD_ADDRESS 0xa000UL
|
||||
+#define STAGE3_LOAD_ADDRESS STAGE3_ENTRY
|
||||
#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
|
||||
|
||||
#define ADDRESS_LIMIT 0x80000000UL
|
@ -1,194 +0,0 @@
|
||||
Subject: zkey: Add support for re-enciphering AES CIPHER keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 560b672bfad3c7bb6631ed4e1676a8b2c836e030
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add support for re-enciphering AES CIPHER keys
|
||||
|
||||
For secure keys of type CCA-AESCIPHER the CCA verb CSNBKTC2
|
||||
(Key Token Change2) is used. CCA-AESDATA keys will continue
|
||||
to use CCA verb CSNBKTC (Key Token Change).
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++------------
|
||||
zkey/cca.h | 10 +++++++
|
||||
2 files changed, 76 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -142,6 +142,9 @@ int load_cca_library(struct cca_lib *cca
|
||||
/* Get the Key Token Change function */
|
||||
cca->dll_CSNBKTC = (t_CSNBKTC)dlsym(cca->lib_csulcca, "CSNBKTC");
|
||||
|
||||
+ /* Get the Key Token Change 2 function */
|
||||
+ cca->dll_CSNBKTC2 = (t_CSNBKTC2)dlsym(cca->lib_csulcca, "CSNBKTC2");
|
||||
+
|
||||
/* Get the Cryptographic Facility Query function */
|
||||
cca->dll_CSUACFQ = (t_CSUACFQ)dlsym(cca->lib_csulcca, "CSUACFQ");
|
||||
|
||||
@@ -153,6 +156,7 @@ int load_cca_library(struct cca_lib *cca
|
||||
|
||||
if (cca->dll_CSUACFV == NULL ||
|
||||
cca->dll_CSNBKTC == NULL ||
|
||||
+ cca->dll_CSNBKTC2 == NULL ||
|
||||
cca->dll_CSUACFQ == NULL ||
|
||||
cca->dll_CSUACRA == NULL ||
|
||||
cca->dll_CSUACRD == NULL) {
|
||||
@@ -187,10 +191,13 @@ int key_token_change(struct cca_lib *cca
|
||||
u8 *secure_key, unsigned int secure_key_size,
|
||||
char *method, bool verbose)
|
||||
{
|
||||
+ struct aescipherkeytoken *cipherkey =
|
||||
+ (struct aescipherkeytoken *)secure_key;
|
||||
long exit_data_len = 0, rule_array_count;
|
||||
unsigned char rule_array[2 * 8] = { 0, };
|
||||
unsigned char exit_data[4] = { 0, };
|
||||
long return_code, reason_code;
|
||||
+ long key_token_length;
|
||||
|
||||
util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
@@ -202,33 +209,77 @@ int key_token_change(struct cca_lib *cca
|
||||
memcpy(rule_array + 8, "AES ", 8);
|
||||
rule_array_count = 2;
|
||||
|
||||
- cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
- &exit_data_len, exit_data,
|
||||
- &rule_array_count, rule_array,
|
||||
- secure_key);
|
||||
-
|
||||
- pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' returned: "
|
||||
- "return_code: %ld, reason_code: %ld", method, return_code,
|
||||
- reason_code);
|
||||
- if (return_code != 0) {
|
||||
- print_CCA_error(return_code, reason_code);
|
||||
- return -EIO;
|
||||
- }
|
||||
-
|
||||
- if (secure_key_size == 2 * AESDATA_KEY_SIZE) {
|
||||
+ if (is_cca_aes_data_key(secure_key, secure_key_size)) {
|
||||
cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
&exit_data_len, exit_data,
|
||||
&rule_array_count, rule_array,
|
||||
- secure_key + AESDATA_KEY_SIZE);
|
||||
+ secure_key);
|
||||
|
||||
pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
|
||||
"returned: return_code: %ld, reason_code: %ld",
|
||||
method, return_code, reason_code);
|
||||
+ } else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
|
||||
+ key_token_length = cipherkey->length;
|
||||
+ cca->dll_CSNBKTC2(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &key_token_length,
|
||||
+ (unsigned char *)cipherkey);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with '%s' "
|
||||
+ "returned: return_code: %ld, reason_code: %ld",
|
||||
+ method, return_code, reason_code);
|
||||
+
|
||||
+ pr_verbose(verbose, "key_token_length: %lu", key_token_length);
|
||||
+ } else {
|
||||
+ warnx("Invalid key type specified");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ if (is_xts_key(secure_key, secure_key_size)) {
|
||||
+ if (is_cca_aes_data_key(secure_key, secure_key_size)) {
|
||||
+ cca->dll_CSNBKTC(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ secure_key + AESDATA_KEY_SIZE);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTC (Key Token Change) with "
|
||||
+ "'%s' returned: return_code: %ld, "
|
||||
+ "reason_code: %ld", method, return_code,
|
||||
+ reason_code);
|
||||
+ } else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
|
||||
+ cipherkey = (struct aescipherkeytoken *)(secure_key +
|
||||
+ AESCIPHER_KEY_SIZE);
|
||||
+ key_token_length = cipherkey->length;
|
||||
+ cca->dll_CSNBKTC2(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &key_token_length,
|
||||
+ (unsigned char *)cipherkey);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTC2 (Key Token Change2) with "
|
||||
+ "'%s' returned: return_code: %ld, "
|
||||
+ "reason_code: %ld", method, return_code,
|
||||
+ reason_code);
|
||||
+
|
||||
+ pr_verbose(verbose, "key_token_length: %lu",
|
||||
+ key_token_length);
|
||||
+ } else {
|
||||
+ warnx("Invalid key type specified");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
if (return_code != 0) {
|
||||
print_CCA_error(return_code, reason_code);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -25,6 +25,15 @@ typedef void (*t_CSNBKTC)(long *return_c
|
||||
unsigned char *rule_array,
|
||||
unsigned char *key_identifier);
|
||||
|
||||
+typedef void (*t_CSNBKTC2)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *key_identifier_length,
|
||||
+ unsigned char *key_identifier);
|
||||
+
|
||||
typedef void (*t_CSUACFV)(long *return_code,
|
||||
long *reason_code,
|
||||
long *exit_data_length,
|
||||
@@ -68,6 +77,7 @@ struct cca_version {
|
||||
struct cca_lib {
|
||||
void *lib_csulcca;
|
||||
t_CSNBKTC dll_CSNBKTC;
|
||||
+ t_CSNBKTC2 dll_CSNBKTC2;
|
||||
t_CSUACFV dll_CSUACFV;
|
||||
t_CSUACFQ dll_CSUACFQ;
|
||||
t_CSUACRA dll_CSUACRA;
|
@ -1,105 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: move loaders layout definitions into separate header
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 97ab8fb4e98c84a89d421c08b392db665125a3c0
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: move loaders layout definitions into separate header
|
||||
|
||||
Move the loaders (stage2/stage3) layout values to
|
||||
`include/boot/loaders_layout.h` and use the `_AC` macro for the
|
||||
constants. This allows the reuse of the definitions, e.g. in assembler
|
||||
files, and later for the creation of linker scripts.
|
||||
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/loaders_layout.h | 32 ++++++++++++++++++++++++++++++++
|
||||
zipl/include/zipl.h | 14 +-------------
|
||||
2 files changed, 33 insertions(+), 13 deletions(-)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/boot/loaders_layout.h
|
||||
@@ -0,0 +1,32 @@
|
||||
+/*
|
||||
+ * zipl stage2/stage3 layout 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 LOADERS_LAYOUT_H
|
||||
+#define LOADERS_LAYOUT_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+#include "linux_layout.h"
|
||||
+
|
||||
+#define STAGE3_ENTRY _AC(0xa000, UL)
|
||||
+
|
||||
+#define STAGE2_LOAD_ADDRESS _AC(0x2000, UL)
|
||||
+#define STAGE3_LOAD_ADDRESS STAGE3_ENTRY
|
||||
+#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
|
||||
+
|
||||
+#define STAGE3_HEAP_SIZE _AC(0x4000, UL)
|
||||
+#define STAGE3_HEAP_ADDRESS _AC(0x2000, UL)
|
||||
+#define STAGE3_STACK_SIZE _AC(0x1000, UL)
|
||||
+#define STAGE3_STACK_ADDRESS _AC(0xF000, UL)
|
||||
+#define STAGE3_PARAMS_ADDRESS _AC(0x9000, UL)
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* LOADERS_LAYOUT_H */
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -14,30 +14,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "lib/zt_common.h"
|
||||
-#include "boot/linux_layout.h"
|
||||
+#include "boot/loaders_layout.h"
|
||||
|
||||
#define ZIPL_MAGIC "zIPL"
|
||||
#define ZIPL_MAGIC_SIZE 4
|
||||
#define DISK_LAYOUT_ID 0x00000001
|
||||
|
||||
-#define STAGE3_ENTRY 0xa000UL
|
||||
-
|
||||
-#define STAGE2_LOAD_ADDRESS 0x2000UL
|
||||
-#define STAGE3_LOAD_ADDRESS STAGE3_ENTRY
|
||||
-#define IMAGE_LOAD_ADDRESS IMAGE_ENTRY
|
||||
-
|
||||
#define ADDRESS_LIMIT 0x80000000UL
|
||||
#define ADDRESS_LIMIT_KDUMP 0x2000000UL /* HSA size: 32 MiB */
|
||||
#define UNSPECIFIED_ADDRESS -1UL
|
||||
#define MAXIMUM_PARMLINE_SIZE 0x380UL
|
||||
#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000UL
|
||||
|
||||
-#define STAGE3_HEAP_SIZE 0x4000UL
|
||||
-#define STAGE3_HEAP_ADDRESS 0x2000UL
|
||||
-#define STAGE3_STACK_SIZE 0x1000UL
|
||||
-#define STAGE3_STACK_ADDRESS 0xF000UL
|
||||
-#define STAGE3_PARAMS_ADDRESS 0x9000UL
|
||||
-
|
||||
#define PSW_ADDRESS_MASK 0x000000007fffffffUL
|
||||
#define PSW_LOAD 0x0008000080000000UL
|
||||
#define PSW_DISABLED_WAIT 0x000a000000000000UL
|
@ -1,361 +0,0 @@
|
||||
Subject: zkey: Check crypto card level during APQN cross checking
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: b7bb90c552f9b62c0b4ddc1295e76769149ee6bb
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Check crypto card level during APQN cross checking
|
||||
|
||||
Secure keys of type CCA-AESCIPHER require a CEX6C or newer crypto
|
||||
card. Also check for the minimum required card level during cross
|
||||
checking of APQNs. Also display the card level in the APQN report.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 25 +++++++++++++----
|
||||
zkey/pkey.c | 20 ++++++++++++++
|
||||
zkey/pkey.h | 1
|
||||
zkey/utils.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
|
||||
zkey/utils.h | 6 ++--
|
||||
zkey/zkey.c | 9 ++++--
|
||||
6 files changed, 126 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1722,7 +1722,9 @@ int keystore_generate_key(struct keystor
|
||||
if (rc != 0)
|
||||
goto out_free_key_filenames;
|
||||
|
||||
- rc = cross_check_apqns(apqns, 0, true, keystore->verbose);
|
||||
+ rc = cross_check_apqns(apqns, 0,
|
||||
+ get_min_card_level_for_keytype(key_type), true,
|
||||
+ keystore->verbose);
|
||||
if (rc == -EINVAL)
|
||||
goto out_free_key_filenames;
|
||||
if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) {
|
||||
@@ -1850,7 +1852,9 @@ int keystore_import_key(struct keystore
|
||||
goto out_free_key;
|
||||
}
|
||||
|
||||
- rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose);
|
||||
+ rc = cross_check_apqns(apqns, mkvp,
|
||||
+ get_min_card_level_for_keytype(key_type), true,
|
||||
+ keystore->verbose);
|
||||
if (rc == -EINVAL)
|
||||
goto out_free_key;
|
||||
if (rc != 0 && rc != -ENOTSUP && noapqncheck == 0) {
|
||||
@@ -1937,8 +1941,8 @@ int keystore_change_key(struct keystore
|
||||
.nomsg = 0 };
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
+ char *apqns_prop, *key_type;
|
||||
size_t secure_key_size;
|
||||
- char *apqns_prop;
|
||||
u8 *secure_key;
|
||||
char temp[30];
|
||||
u64 mkvp;
|
||||
@@ -2005,9 +2009,12 @@ int keystore_change_key(struct keystore
|
||||
goto out;
|
||||
|
||||
apqns_prop = properties_get(key_props, PROP_NAME_APQNS);
|
||||
- rc = cross_check_apqns(apqns_prop, mkvp, true,
|
||||
- keystore->verbose);
|
||||
+ key_type = properties_get(key_props, PROP_NAME_KEY_TYPE);
|
||||
+ rc = cross_check_apqns(apqns_prop, mkvp,
|
||||
+ get_min_card_level_for_keytype(key_type),
|
||||
+ true, keystore->verbose);
|
||||
free(apqns_prop);
|
||||
+ free(key_type);
|
||||
if (rc == -ENOTSUP)
|
||||
rc = 0;
|
||||
if (rc != 0 && noapqncheck == 0) {
|
||||
@@ -2373,12 +2380,17 @@ static int _keystore_display_apqn_status
|
||||
{
|
||||
int rc, warning = 0;
|
||||
char *apqns;
|
||||
+ char *key_type;
|
||||
|
||||
apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
if (apqns == NULL)
|
||||
return 0;
|
||||
|
||||
- rc = cross_check_apqns(apqns, mkvp, true, keystore->verbose);
|
||||
+ apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
+ key_type = properties_get(properties, PROP_NAME_KEY_TYPE);
|
||||
+ rc = cross_check_apqns(apqns, mkvp,
|
||||
+ get_min_card_level_for_keytype(key_type), true,
|
||||
+ keystore->verbose);
|
||||
if (rc != 0 && rc != -ENOTSUP)
|
||||
warning = 1;
|
||||
|
||||
@@ -2386,6 +2398,7 @@ static int _keystore_display_apqn_status
|
||||
printf("\n");
|
||||
|
||||
free(apqns);
|
||||
+ free(key_type);
|
||||
return warning;
|
||||
}
|
||||
/**
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -1630,3 +1630,23 @@ const char *get_key_type(const u8 *key,
|
||||
|
||||
return NULL;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Returns the minimum card level for a specific key type
|
||||
+ *
|
||||
+ * @param[in] key_type the type of the key
|
||||
+ *
|
||||
+ * @returns the minimum card level, or -1 for unknown key types
|
||||
+ */
|
||||
+int get_min_card_level_for_keytype(const char *key_type)
|
||||
+{
|
||||
+ if (key_type == NULL)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESDATA) == 0)
|
||||
+ return 3;
|
||||
+ if (strcasecmp(key_type, KEY_TYPE_CCA_AESCIPHER) == 0)
|
||||
+ return 6;
|
||||
+
|
||||
+ return -1;
|
||||
+}
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -264,5 +264,6 @@ bool is_cca_aes_cipher_key(const u8 *key
|
||||
bool is_xts_key(const u8 *key, size_t key_size);
|
||||
int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
|
||||
const char *get_key_type(const u8 *key, size_t key_size);
|
||||
+int get_min_card_level_for_keytype(const char *key_type);
|
||||
|
||||
#endif
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -119,6 +119,49 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Returns the level of the card. For a CEX3C 3 is returned, for a CEX4C 4,
|
||||
+ * and so on.
|
||||
+ *
|
||||
+ * @param[in] card card number
|
||||
+ *
|
||||
+ * @returns The card level, or -1 of the level can not be determined.
|
||||
+ */
|
||||
+int sysfs_get_card_level(int card)
|
||||
+{
|
||||
+ char *dev_path;
|
||||
+ char type[20];
|
||||
+ int rc;
|
||||
+
|
||||
+ dev_path = util_path_sysfs("bus/ap/devices/card%02x", card);
|
||||
+ if (!util_path_is_dir(dev_path)) {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (util_file_read_line(type, sizeof(type), "%s/type", dev_path) != 0) {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (strncmp(type, "CEX", 3) != 0 || strlen(type) < 5) {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (type[4] != 'C') {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (type[3] < '1' || type[3] > '9') {
|
||||
+ rc = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = type[3] - '0';
|
||||
+
|
||||
+out:
|
||||
+ free(dev_path);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Gets the 8 character ASCII serial number string of an card from the sysfs.
|
||||
*
|
||||
* @param[in] card card number
|
||||
@@ -436,12 +479,14 @@ static int print_apqn_mk_info(int card,
|
||||
{
|
||||
struct print_apqn_info *info = (struct print_apqn_info *)handler_data;
|
||||
struct mk_info mk_info;
|
||||
- int rc;
|
||||
+ int rc, level;
|
||||
|
||||
rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
|
||||
if (rc == -ENOTSUP)
|
||||
return rc;
|
||||
|
||||
+ level = sysfs_get_card_level(card);
|
||||
+
|
||||
util_rec_set(info->rec, "APQN", "%02x.%04x", card, domain);
|
||||
|
||||
if (rc == 0) {
|
||||
@@ -470,6 +515,11 @@ static int print_apqn_mk_info(int card,
|
||||
util_rec_set(info->rec, "OLD", "?");
|
||||
}
|
||||
|
||||
+ if (level > 0)
|
||||
+ util_rec_set(info->rec, "TYPE", "CEX%dC", level);
|
||||
+ else
|
||||
+ util_rec_set(info->rec, "TYPE", "?");
|
||||
+
|
||||
util_rec_print(info->rec);
|
||||
|
||||
return 0;
|
||||
@@ -499,6 +549,7 @@ int print_mk_info(const char *apqns, boo
|
||||
util_rec_def(info.rec, "NEW", UTIL_REC_ALIGN_LEFT, 16, "NEW MK");
|
||||
util_rec_def(info.rec, "CUR", UTIL_REC_ALIGN_LEFT, 16, "CURRENT MK");
|
||||
util_rec_def(info.rec, "OLD", UTIL_REC_ALIGN_LEFT, 16, "OLD MK");
|
||||
+ util_rec_def(info.rec, "TYPE", UTIL_REC_ALIGN_LEFT, 6, "TYPE");
|
||||
util_rec_print_hdr(info.rec);
|
||||
|
||||
rc = handle_apqns(apqns, print_apqn_mk_info, &info, verbose);
|
||||
@@ -511,6 +562,7 @@ struct cross_check_info {
|
||||
u64 mkvp;
|
||||
u64 new_mkvp;
|
||||
bool key_mkvp;
|
||||
+ int min_level;
|
||||
u32 num_cur_match;
|
||||
u32 num_old_match;
|
||||
u32 num_new_match;
|
||||
@@ -525,7 +577,7 @@ static int cross_check_mk_info(int card,
|
||||
struct cross_check_info *info = (struct cross_check_info *)handler_data;
|
||||
struct mk_info mk_info;
|
||||
char temp[200];
|
||||
- int rc;
|
||||
+ int rc, level;
|
||||
|
||||
rc = sysfs_get_mkvps(card, domain, &mk_info, info->verbose);
|
||||
if (rc == -ENODEV) {
|
||||
@@ -539,6 +591,19 @@ static int cross_check_mk_info(int card,
|
||||
|
||||
info->num_checked++;
|
||||
|
||||
+ if (info->min_level >= 0) {
|
||||
+ level = sysfs_get_card_level(card);
|
||||
+
|
||||
+ if (level < info->min_level) {
|
||||
+ info->print_mks = 1;
|
||||
+ info->mismatch = 1;
|
||||
+ sprintf(temp, "WARNING: APQN %02x.%04x: The card level "
|
||||
+ "is less than CEX%dC.", card, domain,
|
||||
+ info->min_level);
|
||||
+ util_print_indented(temp, 0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (mk_info.new_mk.mk_state == MK_STATE_PARTIAL) {
|
||||
info->print_mks = 1;
|
||||
sprintf(temp, "INFO: APQN %02x.%04x: The NEW master key "
|
||||
@@ -662,6 +727,8 @@ static int cross_check_mk_info(int card,
|
||||
* @param[in] mkvp The master key verification pattern of a secure key.
|
||||
* If this is all zero, then the master keys are not
|
||||
* matched against it.
|
||||
+ * @param[in] min_level The minimum card level required. If min_level is -1 then
|
||||
+ * the card level is not checked.
|
||||
* @param[in] print_mks if true, then a the full master key info of all
|
||||
* specified APQns is printed, in case of a mismatch.
|
||||
* @param[in] verbose if true, verbose messages are printed
|
||||
@@ -671,7 +738,8 @@ static int cross_check_mk_info(int card,
|
||||
* -ENOTSUP is returned when the mkvps sysfs attribute is not
|
||||
* available, because the zcrypt kernel module is on an older level.
|
||||
*/
|
||||
-int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks, bool verbose)
|
||||
+int cross_check_apqns(const char *apqns, u64 mkvp, int min_level,
|
||||
+ bool print_mks, bool verbose)
|
||||
{
|
||||
struct cross_check_info info;
|
||||
char temp[200];
|
||||
@@ -680,10 +748,12 @@ int cross_check_apqns(const char *apqns,
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.key_mkvp = mkvp != 0;
|
||||
info.mkvp = mkvp;
|
||||
+ info.min_level = min_level;
|
||||
info.verbose = verbose;
|
||||
|
||||
- pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx: %s",
|
||||
- mkvp, apqns != NULL ? apqns : "ANY");
|
||||
+ pr_verbose(verbose, "Cross checking APQNs with mkvp 0x%016llx and "
|
||||
+ "min-level %d: %s", mkvp, min_level,
|
||||
+ apqns != NULL ? apqns : "ANY");
|
||||
|
||||
rc = handle_apqns(apqns, cross_check_mk_info, &info, verbose);
|
||||
if (rc != 0)
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -18,6 +18,8 @@ int sysfs_is_card_online(int card);
|
||||
|
||||
int sysfs_is_apqn_online(int card, int domain);
|
||||
|
||||
+int sysfs_get_card_level(int card);
|
||||
+
|
||||
int sysfs_get_serialnr(int card, char serialnr[9], bool verbose);
|
||||
|
||||
#define MK_STATE_EMPTY 0
|
||||
@@ -48,7 +50,7 @@ int handle_apqns(const char *apqns, apqn
|
||||
|
||||
int print_mk_info(const char *apqns, bool verbose);
|
||||
|
||||
-int cross_check_apqns(const char *apqns, u64 mkvp, bool print_mks,
|
||||
- bool verbose);
|
||||
+int cross_check_apqns(const char *apqns, u64 mkvp, int min_level,
|
||||
+ bool print_mks, bool verbose);
|
||||
|
||||
#endif
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1122,7 +1122,9 @@ static int command_generate(void)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
- rc = cross_check_apqns(NULL, 0, true, g.verbose);
|
||||
+ rc = cross_check_apqns(NULL, 0,
|
||||
+ get_min_card_level_for_keytype(g.key_type),
|
||||
+ true, g.verbose);
|
||||
if (rc == -EINVAL)
|
||||
return EXIT_FAILURE;
|
||||
if (rc != 0 && rc != -ENOTSUP) {
|
||||
@@ -1447,7 +1449,10 @@ static int command_validate_file(void)
|
||||
printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2,
|
||||
&vp[VERIFICATION_PATTERN_LEN / 2]);
|
||||
|
||||
- rc = cross_check_apqns(NULL, mkvp, true, g.verbose);
|
||||
+ rc = cross_check_apqns(NULL, mkvp,
|
||||
+ get_min_card_level_for_keytype(
|
||||
+ get_key_type(secure_key, secure_key_size)),
|
||||
+ true, g.verbose);
|
||||
if (rc == -EINVAL)
|
||||
return EXIT_FAILURE;
|
||||
if (rc != 0 && rc != -ENOTSUP) {
|
@ -1,192 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/s390.h: rename `inline` macro into `__always_inline`
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 67e76b8ebd8acb4aef1d22309287776892b7267e
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/s390.h: rename `inline` macro into `__always_inline`
|
||||
|
||||
Rename `inline` macro into `__always_inline` so one can differentiate
|
||||
between the macro and the C keyword. While at it, undefine the
|
||||
previous `__always_inline` macro so s390.h can be used in combination
|
||||
with glibc.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/s390.h | 39 ++++++++++++++++++++++-----------------
|
||||
1 file changed, 22 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -19,7 +19,12 @@
|
||||
#define __pa(x) ((unsigned long)(x))
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
-#define inline inline __attribute__((always_inline))
|
||||
+/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||
+ * __always_inline. Therefore undefine it first to allow the headers
|
||||
+ * to be included first.
|
||||
+ */
|
||||
+#undef __always_inline
|
||||
+#define __always_inline inline __attribute__((always_inline))
|
||||
|
||||
/*
|
||||
* Helper macro for exception table entries
|
||||
@@ -214,7 +219,7 @@ do { \
|
||||
libc_stop(reason); \
|
||||
} while (0)
|
||||
|
||||
-static inline int page_is_valid(unsigned long addr)
|
||||
+static __always_inline int page_is_valid(unsigned long addr)
|
||||
{
|
||||
unsigned long tmp;
|
||||
int rc;
|
||||
@@ -234,7 +239,7 @@ static inline int page_is_valid(unsigned
|
||||
return rc;
|
||||
}
|
||||
|
||||
-static inline uint32_t csum_partial(const void *buf, int len, uint32_t sum)
|
||||
+static __always_inline uint32_t csum_partial(const void *buf, int len, uint32_t sum)
|
||||
{
|
||||
register unsigned long reg2 asm("2") = (unsigned long) buf;
|
||||
register unsigned long reg3 asm("3") = (unsigned long) len;
|
||||
@@ -262,7 +267,7 @@ static inline uint32_t csum_partial(cons
|
||||
"i" (low), "i" (high)); \
|
||||
})
|
||||
|
||||
-static inline void __ctl_set_bit(unsigned int cr, unsigned int bit)
|
||||
+static __always_inline void __ctl_set_bit(unsigned int cr, unsigned int bit)
|
||||
{
|
||||
unsigned long reg;
|
||||
|
||||
@@ -282,7 +287,7 @@ enum diag308_subcode {
|
||||
DIAG308_STORE = 6,
|
||||
};
|
||||
|
||||
-static inline int diag308(unsigned long subcode, void *addr)
|
||||
+static __always_inline int diag308(unsigned long subcode, void *addr)
|
||||
{
|
||||
register unsigned long _addr asm("0") = (unsigned long) addr;
|
||||
register unsigned long _rc asm("1") = 0;
|
||||
@@ -298,7 +303,7 @@ static inline int diag308(unsigned long
|
||||
/*
|
||||
* Store CPU address
|
||||
*/
|
||||
-static inline unsigned short stap(void)
|
||||
+static __always_inline unsigned short stap(void)
|
||||
{
|
||||
unsigned short cpu_address;
|
||||
|
||||
@@ -309,7 +314,7 @@ static inline unsigned short stap(void)
|
||||
/*
|
||||
* Program the clock comparator
|
||||
*/
|
||||
-static inline void set_clock_comparator(uint64_t time)
|
||||
+static __always_inline void set_clock_comparator(uint64_t time)
|
||||
{
|
||||
asm volatile("sckc %0" : : "Q" (time));
|
||||
}
|
||||
@@ -317,7 +322,7 @@ static inline void set_clock_comparator(
|
||||
/*
|
||||
* Program the CPU timer
|
||||
*/
|
||||
-static inline void set_cpu_timer(uint64_t timer)
|
||||
+static __always_inline void set_cpu_timer(uint64_t timer)
|
||||
{
|
||||
asm volatile("spt %0" : : "Q" (timer));
|
||||
}
|
||||
@@ -325,7 +330,7 @@ static inline void set_cpu_timer(uint64_
|
||||
/*
|
||||
* Get current time (store clock)
|
||||
*/
|
||||
-static inline unsigned long long get_tod_clock(void)
|
||||
+static __always_inline unsigned long long get_tod_clock(void)
|
||||
{
|
||||
unsigned long long clk;
|
||||
|
||||
@@ -343,7 +348,7 @@ struct cpuid {
|
||||
unsigned int unused:16;
|
||||
} __packed __aligned(8);
|
||||
|
||||
-static inline void get_cpu_id(struct cpuid *ptr)
|
||||
+static __always_inline void get_cpu_id(struct cpuid *ptr)
|
||||
{
|
||||
asm volatile("stidp %0" : "=Q" (*ptr));
|
||||
}
|
||||
@@ -351,7 +356,7 @@ static inline void get_cpu_id(struct cpu
|
||||
/*
|
||||
* Check if we run under z/VM
|
||||
*/
|
||||
-static inline int is_zvm(void)
|
||||
+static __always_inline int is_zvm(void)
|
||||
{
|
||||
struct cpuid cpuid;
|
||||
|
||||
@@ -369,7 +374,7 @@ typedef struct {
|
||||
/*
|
||||
* Save vector registers
|
||||
*/
|
||||
-static inline void save_vx_regs(__vector128 *vxrs)
|
||||
+static __always_inline void save_vx_regs(__vector128 *vxrs)
|
||||
{
|
||||
typedef struct { __vector128 _[32]; } addrtype;
|
||||
|
||||
@@ -383,7 +388,7 @@ static inline void save_vx_regs(__vector
|
||||
/*
|
||||
* Save vector registers safe
|
||||
*/
|
||||
-static inline void save_vx_regs_safe(__vector128 *vxrs)
|
||||
+static __always_inline void save_vx_regs_safe(__vector128 *vxrs)
|
||||
{
|
||||
unsigned long cr0;
|
||||
|
||||
@@ -396,7 +401,7 @@ static inline void save_vx_regs_safe(__v
|
||||
|
||||
#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
|
||||
|
||||
-static inline int __test_facility(unsigned long nr, void *facilities)
|
||||
+static __always_inline int __test_facility(unsigned long nr, void *facilities)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
|
||||
@@ -411,12 +416,12 @@ static inline int __test_facility(unsign
|
||||
* That makes it easier to query facility bits with the bit number as
|
||||
* documented in the Principles of Operation.
|
||||
*/
|
||||
-static inline int test_facility(unsigned long nr)
|
||||
+static __always_inline int test_facility(unsigned long nr)
|
||||
{
|
||||
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
|
||||
}
|
||||
|
||||
-static inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, int size)
|
||||
+static __always_inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, int size)
|
||||
{
|
||||
register unsigned long reg0 asm("0") = size - 1;
|
||||
|
||||
@@ -433,7 +438,7 @@ static inline unsigned long __stfle_asm(
|
||||
* @stfle_fac_list: array where facility list can be stored
|
||||
* @size: size of passed in array in double words
|
||||
*/
|
||||
-static inline void stfle(uint64_t *stfle_fac_list, int size)
|
||||
+static __always_inline void stfle(uint64_t *stfle_fac_list, int size)
|
||||
{
|
||||
unsigned long nr;
|
||||
|
@ -1,101 +0,0 @@
|
||||
Subject: zkey: Add helper function to query the CCA firmware version
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: b0cc0e47378de9cd82b0cd14228b26be4d615ffc
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add helper function to query the CCA firmware version
|
||||
|
||||
Some future functions are dependent on the firmware version of the
|
||||
CCA crypto adapter. This helper function allows to query the version
|
||||
of the currently selected CCA adapter.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 52 insertions(+)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -474,6 +474,58 @@ static int get_cca_adapter_serialnr(stru
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Queries the firmware version of the current CCA adapter
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[out] version the struct where the version is returned
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error.
|
||||
+ */
|
||||
+static int get_cca_adapter_version(struct cca_lib *cca,
|
||||
+ struct cca_version *version,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ long exit_data_len = 0, rule_array_count, verb_data_length = 0;
|
||||
+ unsigned char rule_array[6 * 8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+ char version_data[9];
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+
|
||||
+ memset(rule_array, 0, sizeof(rule_array));
|
||||
+ memcpy(rule_array, "STATCCA ", 8);
|
||||
+ rule_array_count = 1;
|
||||
+
|
||||
+ cca->dll_CSUACFQ(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &verb_data_length, NULL);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSUACFQ (Cryptographic Facility Query) returned: "
|
||||
+ "return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(version_data, rule_array+3*8, 8);
|
||||
+ version_data[8] = '\0';
|
||||
+
|
||||
+ pr_verbose(verbose, "CCA firmware version string: %s", version_data);
|
||||
+
|
||||
+ if (sscanf((char *)version_data, "%u.%u.%uz", &version->ver,
|
||||
+ &version->rel, &version->mod) != 3) {
|
||||
+ warnx("CCA formware version is invalid: %s", version_data);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Selects the specified APQN to be used for the CCA host library.
|
||||
*
|
||||
* @param[in] cca the CCA library structure
|
@ -1,74 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: move __always_inline/barrier/__pa32/pa to zt_common.h
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 24fe8c1d1b75185f341ec2d0efc6c34f0b9263f1
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: move __always_inline/barrier/__pa32/pa to zt_common.h
|
||||
|
||||
Move `__always_inline/barrier/__pa32/pa` to `lib/zt_common.h` as this
|
||||
is non-architecture dependent code.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/zt_common.h | 12 ++++++++++++
|
||||
zipl/boot/s390.h | 9 ---------
|
||||
2 files changed, 12 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -55,6 +55,18 @@
|
||||
#define __may_alias __attribute__((may_alias))
|
||||
#define __section(x) __attribute__((__section__(#x)))
|
||||
#define __noinline __attribute__((__noinline__))
|
||||
+/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||
+ * __always_inline. Therefore undefine it first to allow the headers
|
||||
+ * to be included first.
|
||||
+ */
|
||||
+#undef __always_inline
|
||||
+#define __always_inline inline __attribute__((always_inline))
|
||||
+
|
||||
+#define __pa32(x) ((uint32_t)(unsigned long)(x))
|
||||
+#define __pa(x) ((unsigned long)(x))
|
||||
+
|
||||
+#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
+
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -15,16 +15,7 @@
|
||||
#include "libc.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
-#define __pa32(x) ((uint32_t)(unsigned long)(x))
|
||||
-#define __pa(x) ((unsigned long)(x))
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
-#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
-/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||
- * __always_inline. Therefore undefine it first to allow the headers
|
||||
- * to be included first.
|
||||
- */
|
||||
-#undef __always_inline
|
||||
-#define __always_inline inline __attribute__((always_inline))
|
||||
|
||||
/*
|
||||
* Helper macro for exception table entries
|
@ -1,279 +0,0 @@
|
||||
Subject: zkey: Add helper function to convert secure keys between key types
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 7d4b1e18b6195f48414f42b4655f900872fed1e7
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add helper function to convert secure keys between key types
|
||||
|
||||
Add a helper function to convert a secure key from key type
|
||||
CCA-AESDATA to CCA-AESCIPHER.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
zkey/cca.h | 22 +++++++
|
||||
2 files changed, 192 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -55,6 +55,14 @@ static void print_CCA_error(int return_c
|
||||
warnx("The secure key has a CCA master key "
|
||||
"verification pattern that is not valid");
|
||||
break;
|
||||
+ case 90:
|
||||
+ warnx("The operation has been rejected due to access "
|
||||
+ "control checking");
|
||||
+ break;
|
||||
+ case 2143:
|
||||
+ warnx("The operation has been rejected due to key "
|
||||
+ "export restrictions of the secure key");
|
||||
+ break;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
@@ -154,12 +162,16 @@ int load_cca_library(struct cca_lib *cca
|
||||
/* Cryptographic Resource Deallocate function */
|
||||
cca->dll_CSUACRD = (t_CSUACRD)dlsym(cca->lib_csulcca, "CSUACRD");
|
||||
|
||||
+ /* Get the Key Translate 2 function */
|
||||
+ cca->dll_CSNBKTR2 = (t_CSNBKTR2)dlsym(cca->lib_csulcca, "CSNBKTR2");
|
||||
+
|
||||
if (cca->dll_CSUACFV == NULL ||
|
||||
cca->dll_CSNBKTC == NULL ||
|
||||
cca->dll_CSNBKTC2 == NULL ||
|
||||
cca->dll_CSUACFQ == NULL ||
|
||||
cca->dll_CSUACRA == NULL ||
|
||||
- cca->dll_CSUACRD == NULL) {
|
||||
+ cca->dll_CSUACRD == NULL ||
|
||||
+ cca->dll_CSNBKTR2 == NULL) {
|
||||
pr_verbose(verbose, "%s", dlerror());
|
||||
warnx("The command requires the IBM CCA Host Libraries and "
|
||||
"Tools.\nFor the supported environments and downloads, "
|
||||
@@ -729,3 +741,160 @@ void print_msg_for_cca_envvars(const cha
|
||||
util_print_indented(msg, 0);
|
||||
free(msg);
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * Convert a secure key of type CCA-AESDATA into a secure key of type
|
||||
+ * CCA-AESCIPHER.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] input_key the secure key to convert
|
||||
+ * @param[in] input_key_size the size of the secure key to convert
|
||||
+ * @param[in] output_key buffer for the converted secure key
|
||||
+ * @param[in/out] output_key_size on input: size of the output buffer.
|
||||
+ * on exit: size of the converted secure key
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error.
|
||||
+ */
|
||||
+int convert_aes_data_to_cipher_key(struct cca_lib *cca,
|
||||
+ u8 *input_key, unsigned int input_key_size,
|
||||
+ u8 *output_key,
|
||||
+ unsigned int *output_key_size,
|
||||
+ bool verbose)
|
||||
+{
|
||||
+ long input_token_size, output_token_size, zero = 0;
|
||||
+ long exit_data_len = 0, rule_array_count = 0;
|
||||
+ unsigned char *input_token, *output_token;
|
||||
+ unsigned char rule_array[8 * 2] = { 0, };
|
||||
+ unsigned char null_token[64] = { 0, };
|
||||
+ long null_token_len = sizeof(null_token);
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ struct aescipherkeytoken *cipherkey;
|
||||
+ long return_code, reason_code;
|
||||
+ struct cca_version version;
|
||||
+ unsigned char buffer[800];
|
||||
+ int rc;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+ util_assert(input_key != NULL, "Internal error: input_key is NULL");
|
||||
+ util_assert(output_key != NULL, "Internal error: output_key is NULL");
|
||||
+ util_assert(output_key_size != NULL,
|
||||
+ "Internal error: output_key_size is NULL");
|
||||
+
|
||||
+ if (is_cca_aes_cipher_key(input_key, input_key_size)) {
|
||||
+ warnx("Invalid key-type specified");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if (*output_key_size < (is_xts_key(input_key, input_key_size) ?
|
||||
+ 2 * AESCIPHER_KEY_SIZE : AESCIPHER_KEY_SIZE))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /*
|
||||
+ * We need a CCA firmware version 6.3.27 or later to support
|
||||
+ * conversion of secure keys that are exportable to CPACF protected keys
|
||||
+ */
|
||||
+ rc = get_cca_adapter_version(cca, &version, verbose);
|
||||
+ if (rc != 0)
|
||||
+ return rc;
|
||||
+ if (version.ver < 6 ||
|
||||
+ (version.ver == 6 && version.rel < 3) ||
|
||||
+ (version.ver == 6 && version.rel < 3 && version.mod < 27)) {
|
||||
+ util_print_indented("The used CCA firmware version does not "
|
||||
+ "support converting a secure key that can "
|
||||
+ "be used with the PAES cipher. The "
|
||||
+ "required CCA firmware version is 6.3.27 "
|
||||
+ "or later. For the supported environments "
|
||||
+ "and updates, see: " CCA_WEB_PAGE, 0);
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
+
|
||||
+ input_token = input_key;
|
||||
+ input_token_size = AESDATA_KEY_SIZE;
|
||||
+ output_token = buffer;
|
||||
+ output_token_size = sizeof(buffer);
|
||||
+ memset(buffer, 0, sizeof(buffer));
|
||||
+
|
||||
+ memcpy(rule_array, "AES ", 8);
|
||||
+ memcpy(rule_array + 8, "REFORMAT", 8);
|
||||
+ rule_array_count = 2;
|
||||
+
|
||||
+ cca->dll_CSNBKTR2(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &input_token_size, input_token,
|
||||
+ &null_token_len, null_token,
|
||||
+ &zero, NULL,
|
||||
+ &output_token_size, output_token);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTR2 (Key Translate2) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "output_token_size: %lu", output_token_size);
|
||||
+ if (output_token_size > (long)AESCIPHER_KEY_SIZE) {
|
||||
+ pr_verbose(verbose, "Output key token too large");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Check if the converted key allows export to CPACF protected key.
|
||||
+ * If not, then the CCA host library or firmware code level is too low.
|
||||
+ */
|
||||
+ cipherkey = (struct aescipherkeytoken *)buffer;
|
||||
+ if ((cipherkey->kmf1 & 0x0800) == 0) {
|
||||
+ util_print_indented("The used CCA firmware version does not "
|
||||
+ "support converting a secure key that can "
|
||||
+ "be used with the PAES cipher. The "
|
||||
+ "required CCA firmware version is 6.3.27 "
|
||||
+ "or later. For the supported environments "
|
||||
+ "and updates, see: " CCA_WEB_PAGE, 0);
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
+
|
||||
+ memset(output_key, 0, *output_key_size);
|
||||
+ memcpy(output_key, buffer, output_token_size);
|
||||
+ *output_key_size = AESCIPHER_KEY_SIZE;
|
||||
+
|
||||
+ if (is_xts_key(input_key, input_key_size)) {
|
||||
+ input_token = input_key + AESDATA_KEY_SIZE;
|
||||
+ input_token_size = AESDATA_KEY_SIZE;
|
||||
+ output_token = buffer;
|
||||
+ output_token_size = sizeof(buffer);
|
||||
+ memset(buffer, 0, sizeof(buffer));
|
||||
+
|
||||
+ cca->dll_CSNBKTR2(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &input_token_size, input_token,
|
||||
+ &null_token_len, null_token,
|
||||
+ &zero, NULL,
|
||||
+ &output_token_size, output_token);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBKTR2 (Key Translate2) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld",
|
||||
+ return_code, reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose(verbose, "output_token_size: %lu",
|
||||
+ output_token_size);
|
||||
+ if (output_token_size > (long)AESCIPHER_KEY_SIZE) {
|
||||
+ pr_verbose(verbose, "Output key token too large");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ memcpy(output_key + AESCIPHER_KEY_SIZE, buffer,
|
||||
+ output_token_size);
|
||||
+ *output_key_size += AESCIPHER_KEY_SIZE;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -68,6 +68,21 @@ typedef void (*t_CSUACRD)(long *return_c
|
||||
long *ressource_name_length,
|
||||
unsigned char *ressource_name);
|
||||
|
||||
+typedef void (*t_CSNBKTR2)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *input_key_token_length,
|
||||
+ unsigned char *input_key_token,
|
||||
+ long *input_KEK_key_identifier_length,
|
||||
+ unsigned char *input_KEK_key_identifier,
|
||||
+ long *output_KEK_key_identifier_length,
|
||||
+ unsigned char *output_KEK_key_identifier,
|
||||
+ long *output_key_token_length,
|
||||
+ unsigned char *output_key_token);
|
||||
+
|
||||
struct cca_version {
|
||||
unsigned int ver;
|
||||
unsigned int rel;
|
||||
@@ -82,6 +97,7 @@ struct cca_lib {
|
||||
t_CSUACFQ dll_CSUACFQ;
|
||||
t_CSUACRA dll_CSUACRA;
|
||||
t_CSUACRD dll_CSUACRD;
|
||||
+ t_CSNBKTR2 dll_CSNBKTR2;
|
||||
struct cca_version version;
|
||||
};
|
||||
|
||||
@@ -102,4 +118,10 @@ int select_cca_adapter_by_mkvp(struct cc
|
||||
|
||||
void print_msg_for_cca_envvars(const char *key_name);
|
||||
|
||||
+int convert_aes_data_to_cipher_key(struct cca_lib *cca,
|
||||
+ u8 *input_key, unsigned int input_key_size,
|
||||
+ u8 *output_key,
|
||||
+ unsigned int *output_key_size,
|
||||
+ bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,44 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: make BLK_PWRT unsigned int
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 2e28291c75d73b92921f7769eaa803fe3222f383
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: make BLK_PWRT unsigned int
|
||||
|
||||
Otherwise there might be a compiler warning when using 'MIN(bl_count,
|
||||
BLK_PWRT)'.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/fba2dump.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/fba2dump.c
|
||||
+++ b/zipl/boot/fba2dump.c
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "fba.h"
|
||||
#include "stage2dump.h"
|
||||
|
||||
-#define BLK_PWRT 64 /* Blocks per write */
|
||||
+#define BLK_PWRT 64U /* Blocks per write */
|
||||
#define BLK_SIZE 0x200 /* FBA block size */
|
||||
#define BLK_PER_PAGE (PAGE_SIZE / BLK_SIZE) /* FBA blocks per page */
|
||||
|
@ -1,182 +0,0 @@
|
||||
Subject: zkey: Add helper function to restrict export of secure keys
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: e7d79d5c5c0928c1bdbd6b669a6e70b8fd3352a5
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add helper function to restrict export of secure keys
|
||||
|
||||
Secure keys of type CCA-AESCIPHER can be export restricted, so that
|
||||
these keys can not be exported by another key.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/cca.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
zkey/cca.h | 19 +++++++++++++
|
||||
2 files changed, 101 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zkey/cca.c
|
||||
+++ b/zkey/cca.c
|
||||
@@ -165,13 +165,17 @@ int load_cca_library(struct cca_lib *cca
|
||||
/* Get the Key Translate 2 function */
|
||||
cca->dll_CSNBKTR2 = (t_CSNBKTR2)dlsym(cca->lib_csulcca, "CSNBKTR2");
|
||||
|
||||
+ /* Get the Restrict Key Attribute function */
|
||||
+ cca->dll_CSNBRKA = (t_CSNBRKA)dlsym(cca->lib_csulcca, "CSNBRKA");
|
||||
+
|
||||
if (cca->dll_CSUACFV == NULL ||
|
||||
cca->dll_CSNBKTC == NULL ||
|
||||
cca->dll_CSNBKTC2 == NULL ||
|
||||
cca->dll_CSUACFQ == NULL ||
|
||||
cca->dll_CSUACRA == NULL ||
|
||||
cca->dll_CSUACRD == NULL ||
|
||||
- cca->dll_CSNBKTR2 == NULL) {
|
||||
+ cca->dll_CSNBKTR2 == NULL ||
|
||||
+ cca->dll_CSNBRKA == NULL) {
|
||||
pr_verbose(verbose, "%s", dlerror());
|
||||
warnx("The command requires the IBM CCA Host Libraries and "
|
||||
"Tools.\nFor the supported environments and downloads, "
|
||||
@@ -898,3 +902,80 @@ int convert_aes_data_to_cipher_key(struc
|
||||
return 0;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Restrict the exportability of an AES CIPHER key. It restricts export by means
|
||||
+ * of NOEX-AES, NOEX-DES, NOEX-RSA, NOEX-SYM, NOEXUASY, NOEXAASY, NOEX-RAW
|
||||
+ * keywords.
|
||||
+ * When this function is called with an AES DATA key, it does nothing and
|
||||
+ * returns 0. AES DATA keys can not be export restricted.
|
||||
+ *
|
||||
+ * @param[in] cca the CCA library structure
|
||||
+ * @param[in] secure_key the secure key to restrict
|
||||
+ * @param[in] secure_key_size the size of the secure key to restrict
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error.
|
||||
+ */
|
||||
+int restrict_key_export(struct cca_lib *cca, u8 *secure_key,
|
||||
+ unsigned int secure_key_size, bool verbose)
|
||||
+{
|
||||
+ struct aescipherkeytoken *cipherkey =
|
||||
+ (struct aescipherkeytoken *)secure_key;
|
||||
+ long exit_data_len = 0, rule_array_count = 0;
|
||||
+ unsigned char rule_array[8 * 8] = { 0, };
|
||||
+ unsigned char exit_data[4] = { 0, };
|
||||
+ long return_code, reason_code;
|
||||
+ long token_length, zero = 0;
|
||||
+
|
||||
+ util_assert(cca != NULL, "Internal error: cca is NULL");
|
||||
+ util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
|
||||
+
|
||||
+ if (!is_cca_aes_cipher_key(secure_key, secure_key_size))
|
||||
+ return 0;
|
||||
+
|
||||
+ memcpy(rule_array, "AES ", 8);
|
||||
+ memcpy(rule_array + 8, "NOEX-AES", 8);
|
||||
+ memcpy(rule_array + 16, "NOEX-DES", 8);
|
||||
+ memcpy(rule_array + 24, "NOEX-RSA", 8);
|
||||
+ memcpy(rule_array + 32, "NOEX-SYM", 8);
|
||||
+ memcpy(rule_array + 40, "NOEXUASY", 8);
|
||||
+ memcpy(rule_array + 48, "NOEXAASY", 8);
|
||||
+ memcpy(rule_array + 56, "NOEX-RAW", 8);
|
||||
+ rule_array_count = 8;
|
||||
+
|
||||
+ token_length = cipherkey->length;
|
||||
+ cca->dll_CSNBRKA(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &token_length, (unsigned char *)secure_key,
|
||||
+ &zero, NULL, &zero, NULL, &zero, NULL);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBRKA (Restrict Key Attribute) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld", return_code,
|
||||
+ reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ if (is_xts_key(secure_key, secure_key_size)) {
|
||||
+ cipherkey = (struct aescipherkeytoken *)(secure_key +
|
||||
+ AESCIPHER_KEY_SIZE);
|
||||
+ token_length = cipherkey->length;
|
||||
+ cca->dll_CSNBRKA(&return_code, &reason_code,
|
||||
+ &exit_data_len, exit_data,
|
||||
+ &rule_array_count, rule_array,
|
||||
+ &token_length, (unsigned char *)cipherkey,
|
||||
+ &zero, NULL, &zero, NULL, &zero, NULL);
|
||||
+
|
||||
+ pr_verbose(verbose, "CSNBRKA (Restrict Key Attribute) "
|
||||
+ "returned: return_code: %ld, reason_code: %ld",
|
||||
+ return_code, reason_code);
|
||||
+ if (return_code != 0) {
|
||||
+ print_CCA_error(return_code, reason_code);
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
--- a/zkey/cca.h
|
||||
+++ b/zkey/cca.h
|
||||
@@ -83,6 +83,21 @@ typedef void (*t_CSNBKTR2)(long *return_
|
||||
long *output_key_token_length,
|
||||
unsigned char *output_key_token);
|
||||
|
||||
+typedef void (*t_CSNBRKA)(long *return_code,
|
||||
+ long *reason_code,
|
||||
+ long *exit_data_length,
|
||||
+ unsigned char *exit_data,
|
||||
+ long *rule_array_count,
|
||||
+ unsigned char *rule_array,
|
||||
+ long *key_identifier_length,
|
||||
+ unsigned char *key_identifier,
|
||||
+ long *ey_encrypting_key_identifier_length,
|
||||
+ unsigned char *ey_encrypting_key_identifier,
|
||||
+ long *opt_parameter1_length,
|
||||
+ unsigned char *opt_parameter1,
|
||||
+ long *opt_parameter2_length,
|
||||
+ unsigned char *opt_parameter2);
|
||||
+
|
||||
struct cca_version {
|
||||
unsigned int ver;
|
||||
unsigned int rel;
|
||||
@@ -98,6 +113,7 @@ struct cca_lib {
|
||||
t_CSUACRA dll_CSUACRA;
|
||||
t_CSUACRD dll_CSUACRD;
|
||||
t_CSNBKTR2 dll_CSNBKTR2;
|
||||
+ t_CSNBRKA dll_CSNBRKA;
|
||||
struct cca_version version;
|
||||
};
|
||||
|
||||
@@ -124,4 +140,7 @@ int convert_aes_data_to_cipher_key(struc
|
||||
unsigned int *output_key_size,
|
||||
bool verbose);
|
||||
|
||||
+int restrict_key_export(struct cca_lib *cca, u8 *secure_key,
|
||||
+ unsigned int secure_key_size, bool verbose);
|
||||
+
|
||||
#endif
|
@ -1,105 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] Consolidate MIN and MAX macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: c55ceabc6726a7806922d288149003661f673a2f
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
Consolidate MIN and MAX macros
|
||||
|
||||
Consolidate MIN and MAX macros and make sure it can be used in
|
||||
combination with glib.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/lib/util_base.h | 17 +----------------
|
||||
include/lib/zt_common.h | 17 +++++++++++++++++
|
||||
zipl/boot/s390.h | 1 -
|
||||
3 files changed, 18 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/include/lib/util_base.h
|
||||
+++ b/include/lib/util_base.h
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
+#include "zt_common.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,
|
||||
@@ -22,22 +23,6 @@ void util_print_indented(const char *str
|
||||
|
||||
#define UTIL_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
-#define MIN(x, y) \
|
||||
-({ \
|
||||
- __typeof__(x) _x = (x); \
|
||||
- __typeof__(y) _y = (y); \
|
||||
- \
|
||||
- _x < _y ? _x : _y; \
|
||||
-})
|
||||
-
|
||||
-#define MAX(x, y) \
|
||||
-({ \
|
||||
- __typeof__(x) _x = (x); \
|
||||
- __typeof__(y) _y = (y); \
|
||||
- \
|
||||
- _x > _y ? _x : _y; \
|
||||
-})
|
||||
-
|
||||
static inline void util_ptr_vec_free(void **ptr_vec, int count)
|
||||
{
|
||||
int i;
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -67,6 +67,23 @@
|
||||
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
|
||||
+#undef MIN
|
||||
+#define MIN(x, y) \
|
||||
+ ({ \
|
||||
+ __typeof__(x) _x = (x); \
|
||||
+ __typeof__(y) _y = (y); \
|
||||
+ \
|
||||
+ _x < _y ? _x : _y; \
|
||||
+ })
|
||||
+
|
||||
+#undef MAX
|
||||
+#define MAX(x, y) \
|
||||
+ ({ \
|
||||
+ __typeof__(x) _x = (x); \
|
||||
+ __typeof__(y) _y = (y); \
|
||||
+ \
|
||||
+ _x > _y ? _x : _y; \
|
||||
+ })
|
||||
|
||||
typedef unsigned long long u64;
|
||||
typedef signed long long s64;
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "libc.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
||||
/*
|
||||
* Helper macro for exception table entries
|
@ -1,192 +0,0 @@
|
||||
Subject: zkey: Add helper function to check an AES CIPHER key
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 7fede7021ece58b9960532e17d963f844fe0de02
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add helper function to check an AES CIPHER key
|
||||
|
||||
The helper function performs a deep check of the AES CIPHER key
|
||||
token and checks for any potentially insecure attributes.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/pkey.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/pkey.h | 1
|
||||
2 files changed, 138 insertions(+)
|
||||
|
||||
--- a/zkey/pkey.c
|
||||
+++ b/zkey/pkey.c
|
||||
@@ -1650,3 +1650,140 @@ int get_min_card_level_for_keytype(const
|
||||
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * Performs extended checks on an AES CIPHER key. It checks the key usage
|
||||
+ * fields (KUFs) and key management fields (KMFs) of the key. The function
|
||||
+ * returns -EINVAL and issues warning messages if a mismatch is detected.
|
||||
+ *
|
||||
+ * @param[in] key the secure key token
|
||||
+ * @param[in] key_size the size of the secure key
|
||||
+ *
|
||||
+ * @returns 0 on success, a negative errno in case of an error
|
||||
+ */
|
||||
+int check_aes_cipher_key(const u8 *key, size_t key_size)
|
||||
+{
|
||||
+ struct aescipherkeytoken *cipherkey = (struct aescipherkeytoken *)key;
|
||||
+ bool mismatch = false;
|
||||
+
|
||||
+ if (!is_cca_aes_cipher_key(key, key_size)) {
|
||||
+ warnx("The key is not of type '"KEY_TYPE_CCA_AESCIPHER"'");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ if ((cipherkey->kuf1 & 0x8000) == 0) {
|
||||
+ printf("WARNING: The secure key can not be used for "
|
||||
+ "encryption\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kuf1 & 0x4000) == 0) {
|
||||
+ printf("WARNING: The secure key can not be used for "
|
||||
+ "decryption\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kuf1 & 0x2000) {
|
||||
+ printf("INFO: The secure key can be used for data translate\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kuf1 & 0x1000) {
|
||||
+ printf("WARNING: The secure key can only be used in UDXs\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+
|
||||
+ if (cipherkey->kmf1 & 0x8000) {
|
||||
+ printf("WARNING: The secure key can be exported using a "
|
||||
+ "symmetric key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf1 & 0x4000) {
|
||||
+ printf("WARNING: The secure key can be exported using an "
|
||||
+ "unauthenticated asymmetric key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf1 & 0x2000) {
|
||||
+ printf("WARNING: The secure key can be exported using an "
|
||||
+ "authenticated asymmetric key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf1 & 0x1000) {
|
||||
+ printf("WARNING: The secure key can be exported using a RAW "
|
||||
+ "key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf1 & 0x0800) == 0) {
|
||||
+ printf("WARNING: The secure key can not be transformed into a "
|
||||
+ "CPACF protected key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf1 & 0x0080) == 0) {
|
||||
+ printf("WARNING: The secure key can be exported using a DES "
|
||||
+ "key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf1 & 0x0040) == 0) {
|
||||
+ printf("WARNING: The secure key can be exported using an AES "
|
||||
+ "key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf1 & 0x0008) == 0) {
|
||||
+ printf("WARNING: The secure key can be exported using an RSA "
|
||||
+ "key\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+
|
||||
+ if (cipherkey->kmf2 & 0xC000) {
|
||||
+ printf("WARNING: The secure key is incomplete\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf2 & 0x0010) {
|
||||
+ printf("WARNING: The secure key was previously encrypted with "
|
||||
+ "an untrusted KEK\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf2 & 0x0008) {
|
||||
+ printf("WARNING: The secure key was previously in a format "
|
||||
+ "without type or usage attributes\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf2 & 0x0004) {
|
||||
+ printf("WARNING: The secure key was previously encrypted with "
|
||||
+ "a key weaker than itself\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf2 & 0x0002) {
|
||||
+ printf("WARNING: The secure key was previously in a non-CCA "
|
||||
+ "format\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if (cipherkey->kmf2 & 0x0001) {
|
||||
+ printf("WARNING: The secure key was previously encrypted in "
|
||||
+ "ECB mode\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+
|
||||
+ if ((cipherkey->kmf3 & 0xFF00) == 0x0000 ||
|
||||
+ (cipherkey->kmf3 & 0x00FF) == 0x0000) {
|
||||
+ printf("WARNING: The secure key was created by an unknown "
|
||||
+ "method\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf3 & 0xFF00) == 0x0400 ||
|
||||
+ (cipherkey->kmf3 & 0x00FF) == 0x0004) {
|
||||
+ printf("WARNING: The secure key was created from cleartext key "
|
||||
+ "components\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf3 & 0xFF00) == 0x0500 ||
|
||||
+ (cipherkey->kmf3 & 0x00FF) == 0x0005) {
|
||||
+ printf("WARNING: The secure key was entered as a cleartext key "
|
||||
+ "value\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+ if ((cipherkey->kmf3 & 0x00FF) == 0x0012) {
|
||||
+ printf("WARNING: The secure key was converted from a CCA "
|
||||
+ "key-token that had no export control attributes\n");
|
||||
+ mismatch = true;
|
||||
+ }
|
||||
+
|
||||
+ return mismatch ? -EINVAL : 0;
|
||||
+}
|
||||
--- a/zkey/pkey.h
|
||||
+++ b/zkey/pkey.h
|
||||
@@ -265,5 +265,6 @@ bool is_xts_key(const u8 *key, size_t ke
|
||||
int get_key_bit_size(const u8 *key, size_t key_size, size_t *bitsize);
|
||||
const char *get_key_type(const u8 *key, size_t key_size);
|
||||
int get_min_card_level_for_keytype(const char *key_type);
|
||||
+int check_aes_cipher_key(const u8 *key, size_t key_size);
|
||||
|
||||
#endif
|
@ -1,76 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: remove libc.h include in s390.h
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: f454c6825f5087cf671d0dfbe96f7f3d148569d6
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: remove libc.h include in s390.h
|
||||
|
||||
This allows the use of s390.h in combination with other libc
|
||||
implementations than our minimal libc, e.g. with glibc.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/s390.h | 1 -
|
||||
zipl/boot/sclp.c | 1 +
|
||||
zipl/boot/sclp_stage3.c | 1 +
|
||||
zipl/boot/stage2dump.c | 1 +
|
||||
4 files changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/s390.h
|
||||
+++ b/zipl/boot/s390.h
|
||||
@@ -12,7 +12,6 @@
|
||||
#define S390_H
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
-#include "libc.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
|
||||
--- a/zipl/boot/sclp.c
|
||||
+++ b/zipl/boot/sclp.c
|
||||
@@ -9,6 +9,7 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "libc.h"
|
||||
#include "error.h"
|
||||
#include "s390.h"
|
||||
#include "sclp.h"
|
||||
--- a/zipl/boot/sclp_stage3.c
|
||||
+++ b/zipl/boot/sclp_stage3.c
|
||||
@@ -9,6 +9,7 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "libc.h"
|
||||
#include "sclp.h"
|
||||
#include "sclp_stage3.h"
|
||||
|
||||
--- a/zipl/boot/stage2dump.c
|
||||
+++ b/zipl/boot/stage2dump.c
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
+#include "libc.h"
|
||||
#include "error.h"
|
||||
#include "sclp.h"
|
||||
#include "stage2dump.h"
|
@ -1,225 +0,0 @@
|
||||
Subject: zkey: Add key checks when importing a CCA-AESCIPHER key
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: 0d9e42264db9935e28f663802c5b95795af79160
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add key checks when importing a CCA-AESCIPHER key
|
||||
|
||||
Perform extended checks on a secure key that is imported into
|
||||
the key repository. Warn the user if the imported key is by
|
||||
any means insecure, e.g. has been originally created in an
|
||||
insecure way. Prompt the user to continue the import if a
|
||||
potential insecurity is detected.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++----------
|
||||
zkey/keystore.h | 3 +-
|
||||
zkey/utils.c | 24 ++++++++++++++++++++++
|
||||
zkey/utils.h | 2 +
|
||||
zkey/zkey.1 | 6 +++++
|
||||
zkey/zkey.c | 2 -
|
||||
6 files changed, 85 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -1801,18 +1801,21 @@ out_free_key_filenames:
|
||||
* default is used.
|
||||
* @param[in] import_file The name of a secure key containing the key to import
|
||||
* @param[in] volume_type the type of volume
|
||||
+ * @param[in] cca the CCA library struct
|
||||
*
|
||||
* @returns 0 for success or a negative errno in case of an error
|
||||
*/
|
||||
int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck, size_t sector_size,
|
||||
- const char *import_file, const char *volume_type)
|
||||
+ const char *import_file, const char *volume_type,
|
||||
+ struct cca_lib *cca)
|
||||
{
|
||||
struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
struct properties *key_props = NULL;
|
||||
size_t secure_key_size;
|
||||
const char *key_type;
|
||||
+ int selected = 1;
|
||||
u8 *secure_key;
|
||||
u64 mkvp;
|
||||
int rc;
|
||||
@@ -1862,6 +1865,51 @@ int keystore_import_key(struct keystore
|
||||
goto out_free_key;
|
||||
}
|
||||
|
||||
+ if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
|
||||
+ if (cca->lib_csulcca == NULL) {
|
||||
+ rc = load_cca_library(cca, keystore->verbose);
|
||||
+ if (rc != 0)
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+
|
||||
+ rc = select_cca_adapter_by_mkvp(cca, mkvp, apqns,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP |
|
||||
+ FLAG_SEL_CCA_MATCH_OLD_MKVP,
|
||||
+ keystore->verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ warnx("No APQN found that is suitable for "
|
||||
+ "working with the secure AES key '%s'", name);
|
||||
+ rc = 0;
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+
|
||||
+ rc = restrict_key_export(cca, secure_key, secure_key_size,
|
||||
+ keystore->verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to export-restrict the imported secure "
|
||||
+ "key: %s", strerror(-rc));
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+
|
||||
+ rc = check_aes_cipher_key(secure_key, secure_key_size);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("The secure key to import might not be secure");
|
||||
+ printf("%s: Do you want to import it anyway [y/N]? ",
|
||||
+ program_invocation_short_name);
|
||||
+ if (!prompt_for_yes(keystore->verbose)) {
|
||||
+ warnx("Operation aborted");
|
||||
+ rc = -ECANCELED;
|
||||
+ goto out_free_key;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
rc = write_secure_key(file_names.skey_filename, secure_key,
|
||||
secure_key_size, keystore->verbose);
|
||||
free(secure_key);
|
||||
@@ -3180,7 +3228,6 @@ static int _keystore_prompt_for_remove(s
|
||||
struct key_filenames *file_names)
|
||||
{
|
||||
struct properties *key_prop;
|
||||
- char str[20];
|
||||
char *msg;
|
||||
int rc;
|
||||
|
||||
@@ -3198,14 +3245,7 @@ static int _keystore_prompt_for_remove(s
|
||||
|
||||
printf("%s: Remove key '%s' [y/N]? ", program_invocation_short_name,
|
||||
name);
|
||||
- if (fgets(str, sizeof(str), stdin) == NULL) {
|
||||
- rc = -EIO;
|
||||
- goto out;
|
||||
- }
|
||||
- if (str[strlen(str) - 1] == '\n')
|
||||
- str[strlen(str) - 1] = '\0';
|
||||
- pr_verbose(keystore, "Prompt reply: '%s'", str);
|
||||
- if (strcasecmp(str, "y") != 0 && strcasecmp(str, "yes") != 0) {
|
||||
+ if (!prompt_for_yes(keystore->verbose)) {
|
||||
warnx("Operation aborted");
|
||||
rc = -ECANCELED;
|
||||
goto out;
|
||||
--- a/zkey/keystore.h
|
||||
+++ b/zkey/keystore.h
|
||||
@@ -37,7 +37,8 @@ int keystore_generate_key(struct keystor
|
||||
int keystore_import_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
const char *apqns, bool noapqncheck, size_t sector_size,
|
||||
- const char *import_file, const char *volume_type);
|
||||
+ const char *import_file, const char *volume_type,
|
||||
+ struct cca_lib *cca);
|
||||
|
||||
int keystore_change_key(struct keystore *keystore, const char *name,
|
||||
const char *description, const char *volumes,
|
||||
--- a/zkey/utils.c
|
||||
+++ b/zkey/utils.c
|
||||
@@ -793,3 +793,27 @@ int cross_check_apqns(const char *apqns,
|
||||
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+/*
|
||||
+ * Prompts for yes or no. Returns true if 'y' or 'yes' was entered.
|
||||
+ *
|
||||
+ * @param[in] verbose if true, verbose messages are printed
|
||||
+ *
|
||||
+ * @returns true if 'y' or 'yes' was entered (case insensitive). Returns false
|
||||
+ * otherwise.
|
||||
+ */
|
||||
+bool prompt_for_yes(bool verbose)
|
||||
+{
|
||||
+ char str[20];
|
||||
+
|
||||
+ if (fgets(str, sizeof(str), stdin) == NULL)
|
||||
+ return false;
|
||||
+
|
||||
+ if (str[strlen(str) - 1] == '\n')
|
||||
+ str[strlen(str) - 1] = '\0';
|
||||
+ pr_verbose(verbose, "Prompt reply: '%s'", str);
|
||||
+ if (strcasecmp(str, "y") == 0 || strcasecmp(str, "yes") == 0)
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
--- a/zkey/utils.h
|
||||
+++ b/zkey/utils.h
|
||||
@@ -53,4 +53,6 @@ int print_mk_info(const char *apqns, boo
|
||||
int cross_check_apqns(const char *apqns, u64 mkvp, int min_level,
|
||||
bool print_mks, bool verbose);
|
||||
|
||||
+bool prompt_for_yes(bool verbose);
|
||||
+
|
||||
#endif
|
||||
--- a/zkey/zkey.1
|
||||
+++ b/zkey/zkey.1
|
||||
@@ -349,6 +349,12 @@ additional information can be associated
|
||||
, or the
|
||||
.B \-\-sector-size
|
||||
options.
|
||||
+.PP
|
||||
+.B Note:
|
||||
+The \fBimport\fP command requires the CCA host library (libcsulcca.so)
|
||||
+to be installed when secure keys of type \fBCCA-AESCIPHER\fP are imported.
|
||||
+For the supported environments and downloads, see:
|
||||
+\fIhttp://www.ibm.com/security/cryptocards\fP
|
||||
.
|
||||
.SS "Export AES secure keys from the secure key repository"
|
||||
.
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -1522,7 +1522,7 @@ static int command_import(void)
|
||||
|
||||
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
|
||||
g.apqns, g.noapqncheck, g.sector_size,
|
||||
- g.pos_arg, g.volume_type);
|
||||
+ g.pos_arg, g.volume_type, &g.cca);
|
||||
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,679 +0,0 @@
|
||||
Subject: zkey: Add 'convert' command to convert keys from one type to another
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: a86e41a51827b524c5f88db5e24282166df9b3c8
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Add 'convert' command to convert keys from one type to another
|
||||
|
||||
Add a new 'convert' command. It allows to convert a secure key from
|
||||
one key type to another. Currently only keys of type CCA-AESDATA can be
|
||||
converted to CCA-AESCIPHER.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/keystore.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zkey/keystore.h | 4
|
||||
zkey/zkey.1 | 93 ++++++++++++++++++++
|
||||
zkey/zkey.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
4 files changed, 557 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zkey/keystore.c
|
||||
+++ b/zkey/keystore.c
|
||||
@@ -3947,6 +3947,218 @@ int keystore_crypttab(struct keystore *k
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Converts a secure keys in the keystore
|
||||
+ *
|
||||
+ * @param[in] keystore the key store
|
||||
+ * @param[in] name the name of the key to convert
|
||||
+ * @param[in] key_type the type of the key to convert it to
|
||||
+ * @param[in] noapqncheck if true, the specified APQN(s) are not checked for
|
||||
+ * existence and type.
|
||||
+ * @param[in] pkey_fd the file descriptor of /dev/pkey
|
||||
+ * @param[in] cca the CCA library struct
|
||||
+ *
|
||||
+ * @returns 0 for success or a negative errno in case of an error
|
||||
+ */
|
||||
+int keystore_convert_key(struct keystore *keystore, const char *name,
|
||||
+ const char *key_type, bool noapqncheck, bool quiet,
|
||||
+ int pkey_fd, struct cca_lib *cca)
|
||||
+{
|
||||
+ struct key_filenames file_names = { NULL, NULL, NULL };
|
||||
+ u8 output_key[2 * MAX_SECURE_KEY_SIZE];
|
||||
+ struct properties *properties = NULL;
|
||||
+ int rc, min_level, selected = 1;
|
||||
+ unsigned int output_key_size;
|
||||
+ char *cur_key_type = NULL;
|
||||
+ char **apqn_list = NULL;
|
||||
+ size_t secure_key_size;
|
||||
+ u8 *secure_key = NULL;
|
||||
+ char *apqns = NULL;
|
||||
+ char *temp;
|
||||
+ u64 mkvp;
|
||||
+
|
||||
+ util_assert(keystore != NULL, "Internal error: keystore is NULL");
|
||||
+ util_assert(name != NULL, "Internal error: name is NULL");
|
||||
+
|
||||
+ rc = _keystore_get_key_filenames(keystore, name, &file_names);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ rc = _keystore_ensure_keyfiles_exist(&file_names, name);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ properties = properties_new();
|
||||
+ rc = properties_load(properties, file_names.info_filename, 1);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Key '%s' does not exist or is invalid", name);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ cur_key_type = _keystore_get_key_type(properties);
|
||||
+ if (strcasecmp(cur_key_type, key_type) == 0) {
|
||||
+ warnx("The secure key '%s' is already of type %s", name,
|
||||
+ cur_key_type);
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ if (strcasecmp(cur_key_type, KEY_TYPE_CCA_AESDATA) != 0) {
|
||||
+ warnx("Only secure keys of type %s can "
|
||||
+ "be converted. The secure key '%s' is of type %s",
|
||||
+ KEY_TYPE_CCA_AESDATA, name, cur_key_type);
|
||||
+ rc = 0;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ secure_key = read_secure_key(file_names.skey_filename,
|
||||
+ &secure_key_size, keystore->verbose);
|
||||
+ if (secure_key == NULL) {
|
||||
+ rc = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ min_level = get_min_card_level_for_keytype(key_type);
|
||||
+ if (min_level < 0) {
|
||||
+ warnx("Invalid key-type specified: %s", key_type);
|
||||
+ rc = -EINVAL;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ apqns = properties_get(properties, PROP_NAME_APQNS);
|
||||
+ if (apqns != NULL)
|
||||
+ apqn_list = str_list_split(apqns);
|
||||
+
|
||||
+ rc = cross_check_apqns(apqns, 0, min_level, true, keystore->verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ goto out;
|
||||
+ if (rc != 0 && rc != -ENOTSUP && !noapqncheck) {
|
||||
+ warnx("Your master key setup is improper for converting key "
|
||||
+ "'%s'", name);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = validate_secure_key(pkey_fd, secure_key, secure_key_size,
|
||||
+ NULL, NULL, (const char **)apqn_list,
|
||||
+ keystore->verbose);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, keystore->verbose);
|
||||
+ if (rc)
|
||||
+ goto out;
|
||||
+
|
||||
+ rc = select_cca_adapter_by_mkvp(cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP,
|
||||
+ keystore->verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ warnx("No APQN found that is suitable for "
|
||||
+ "converting the secure AES key '%s'", name);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!quiet) {
|
||||
+ util_print_indented("ATTENTION: Converting a secure key is "
|
||||
+ "irreversible, and might have an effect "
|
||||
+ "on the volumes encrypted with it!", 0);
|
||||
+ _keystore_msg_for_volumes("The following volumes are encrypted "
|
||||
+ "with this key:", properties, NULL);
|
||||
+ printf("%s: Convert key '%s [y/N]'? ",
|
||||
+ program_invocation_short_name, name);
|
||||
+ if (!prompt_for_yes(keystore->verbose)) {
|
||||
+ warnx("Operation aborted");
|
||||
+ rc = -ECANCELED;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ memset(output_key, 0, sizeof(output_key));
|
||||
+ output_key_size = sizeof(output_key);
|
||||
+ rc = convert_aes_data_to_cipher_key(cca, secure_key,
|
||||
+ secure_key_size, output_key,
|
||||
+ &output_key_size,
|
||||
+ keystore->verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Converting the secure key '%s' from %s to %s has failed",
|
||||
+ name, KEY_TYPE_CCA_AESDATA, key_type);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = restrict_key_export(cca, output_key, output_key_size,
|
||||
+ keystore->verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Export restricting the converted secure key '%s' has "
|
||||
+ "failed", name);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = properties_set2(properties, PROP_NAME_KEY_TYPE, key_type, true);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Invalid characters in key-type");
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = properties_save(properties, file_names.info_filename, 1);
|
||||
+ if (rc != 0) {
|
||||
+ pr_verbose(keystore,
|
||||
+ "Failed to write key info file '%s': %s",
|
||||
+ file_names.info_filename, strerror(-rc));
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = write_secure_key(file_names.skey_filename, output_key,
|
||||
+ output_key_size, keystore->verbose);
|
||||
+ if (rc != 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ pr_verbose(keystore, "Secure key '%s' was converted successfully",
|
||||
+ name);
|
||||
+
|
||||
+ util_asprintf(&temp, "The following LUKS2 volumes are "
|
||||
+ "encrypted with key '%s'. These volumes still contain "
|
||||
+ "the secure AES volume key of type CCA-AESDATA. To "
|
||||
+ "change the secure AES volume key in the LUKS2 header, "
|
||||
+ "run command 'zkey-cryptsetup setkey <device> "
|
||||
+ "--master-key-file %s':", name,
|
||||
+ file_names.skey_filename);
|
||||
+ _keystore_msg_for_volumes(temp, properties, VOLUME_TYPE_LUKS2);
|
||||
+ free(temp);
|
||||
+ util_asprintf(&temp, "The following plain mode volumes are "
|
||||
+ "encrypted with key '%s'. You must adapt the crypttab "
|
||||
+ "entries for this volumes and change the key size "
|
||||
+ "parameter to 'size=%u' or run command 'zkey crypttab "
|
||||
+ "--volumes <device>' for each volume to re-generate the "
|
||||
+ "crypttab entries:", name, output_key_size * 8, name);
|
||||
+ _keystore_msg_for_volumes(temp, properties, VOLUME_TYPE_PLAIN);
|
||||
+ free(temp);
|
||||
+
|
||||
+out:
|
||||
+ _keystore_free_key_filenames(&file_names);
|
||||
+ if (properties != NULL)
|
||||
+ properties_free(properties);
|
||||
+ if (secure_key != NULL)
|
||||
+ free(secure_key);
|
||||
+ if (apqns != NULL)
|
||||
+ free(apqns);
|
||||
+ if (apqn_list != NULL)
|
||||
+ str_list_free_string_array(apqn_list);
|
||||
+ if (cur_key_type != NULL)
|
||||
+ free(cur_key_type);
|
||||
+
|
||||
+ if (rc != 0)
|
||||
+ pr_verbose(keystore, "Failed to convert key '%s': %s",
|
||||
+ name, strerror(-rc));
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* Frees a keystore object
|
||||
*
|
||||
* @param[in] keystore the key store
|
||||
--- a/zkey/keystore.h
|
||||
+++ b/zkey/keystore.h
|
||||
@@ -81,6 +81,10 @@ int keystore_crypttab(struct keystore *k
|
||||
const char *volume_type, const char *keyfile,
|
||||
size_t keyfile_offset, size_t keyfile_size, size_t tries);
|
||||
|
||||
+int keystore_convert_key(struct keystore *keystore, const char *name,
|
||||
+ const char *key_type, bool noapqncheck, bool quiet,
|
||||
+ int pkey_fd, struct cca_lib *cca);
|
||||
+
|
||||
void keystore_free(struct keystore *keystore);
|
||||
|
||||
|
||||
--- a/zkey/zkey.1
|
||||
+++ b/zkey/zkey.1
|
||||
@@ -62,7 +62,8 @@ in size.
|
||||
The \fBzkey\fP tool can operate in two modes. When argument
|
||||
.I secure\-key\-file
|
||||
is specified then it operates on the secure key contained in the specified file.
|
||||
-This applies to commands \fBgenerate\fP, \fBvalidate\fP, and \fBreencipher\fP.
|
||||
+This applies to commands \fBgenerate\fP, \fBvalidate\fP, \fBreencipher\fP, and
|
||||
+\fBconvert\fP.
|
||||
When the
|
||||
.B \-\-name
|
||||
option is specified then it operates on a secure key contained in the secure
|
||||
@@ -680,6 +681,72 @@ questions, you can specify the
|
||||
option. These options are passed to the generated command(s) and behave in the
|
||||
same way as with \fBcryptsetup\fP.
|
||||
.
|
||||
+.SS "Convert existing AES secure keys from one key type to another type"
|
||||
+.
|
||||
+.B zkey
|
||||
+.BR convert | con
|
||||
+.I secure\-key\-file
|
||||
+.RB \-\-key-type | \-K
|
||||
+.IR type
|
||||
+.RB [ \-\-no\-apqn\-check ]
|
||||
+.RB [ \-\-force | \-F ]
|
||||
+.RB [ \-\-verbose | \-V ]
|
||||
+.
|
||||
+.PP
|
||||
+.B zkey
|
||||
+.BR convert | con
|
||||
+.B \-\-name | \-N
|
||||
+.IR key-name
|
||||
+.RB \-\-key-type | \-K
|
||||
+.IR type
|
||||
+.RB [ \-\-no\-apqn\-check ]
|
||||
+.RB [ \-\-force | \-F ]
|
||||
+.RB [ \-\-verbose | \-V ]
|
||||
+.
|
||||
+.PP
|
||||
+Use the
|
||||
+.B convert
|
||||
+command to convert an existing secure key from one key type to another type.
|
||||
+You can convert secure keys of type CCA-AESDATA to type CCA-AESCIPHER only.
|
||||
+
|
||||
+.B Note:
|
||||
+Secure keys converted to type \fBCCA-AESCIPHER\fP require an IBM cryptographic
|
||||
+adapter in CCA coprocessor mode of version 6 or later, e.g. a CEX6C.
|
||||
+
|
||||
+The secure key can either be contained in a file in the file system, or in a
|
||||
+secure key repository. To convert a secure key contained in a file, specify
|
||||
+the file name with option \fIsecure\-key\-file\fP. To convert a secure key
|
||||
+contained in the secure key repository, specify the name of the key
|
||||
+that is to be converted using the
|
||||
+.B \-\-name
|
||||
+option. You cannot use wildcards. The convert command prompts for
|
||||
+a confirmation, unless you specify the
|
||||
+.B \-\-force
|
||||
+option.
|
||||
+.PP
|
||||
+.B Note:
|
||||
+Converting a secure key is irreversible!
|
||||
+When converting a secure key that is associated with one or multiple volumes,
|
||||
+a message informs you about the associated volumes. When the secure key is
|
||||
+converted, this might have an effect on these volumes.
|
||||
+.P
|
||||
+For volumes with volume type \fBplain\fP, you must adapt the crypttab entries
|
||||
+and change the key size parameter to \fBsize=<new-key-size-in-bits>\fP or run
|
||||
+command \fBzkey crypttab --volumes <device>\fP for each associated volume to
|
||||
+re-generate the crypttab entries.
|
||||
+.P
|
||||
+Associated volumes of type \fLUKS2\fP still contain the secure AES volume key of
|
||||
+the original type. To change the secure AES volume key in the LUKS2 header,
|
||||
+run command \fBzkey-cryptsetup setkey <device> --master-key-file
|
||||
+<converted-key>\fP for each associated volume.
|
||||
+.
|
||||
+.P
|
||||
+.B Note:
|
||||
+The \fBconvert\fP command requires the CCA host library (libcsulcca.so)
|
||||
+to be installed. The required CCA IBM cryptographic adapter firmware version
|
||||
+is 6.3.27 or later. For the supported environments and downloads, see:
|
||||
+\fIhttp://www.ibm.com/security/cryptocards\fP
|
||||
+.
|
||||
.
|
||||
.
|
||||
.
|
||||
@@ -1203,6 +1270,30 @@ cryptsetup command(s).
|
||||
.
|
||||
.
|
||||
.
|
||||
+.SS "Options for the convert command"
|
||||
+.TP
|
||||
+.BR \-N ", " \-\-name\~\fIkey-name\fP
|
||||
+Specifies the name of the secure key in the secure key repository. You cannot
|
||||
+use wildcards.
|
||||
+This option is only used for secure keys contained in the secure key repository.
|
||||
+.TP
|
||||
+.BR \-K ", " \-\-key-type\~\fItype\fP
|
||||
+Specifies the key type to which the secure key shall be converted to.
|
||||
+Possible values are \fBCCA-AESCIPHER\fP. Secure keys of type \fBCCA-AESCIPHER\fP
|
||||
+require an IBM cryptographic adapter in CCA coprocessor mode of version 6 or
|
||||
+later, e.g. a CEX6C.
|
||||
+.TP
|
||||
+.BR \-\-no\-apqn\-check
|
||||
+Do not check if the associated APQNs are available and capable of converting
|
||||
+the secure key to type CCA-AESCIPHER.
|
||||
+This option is only used for secure keys contained in the secure key repository.
|
||||
+.TP
|
||||
+.BR \-F ", " \-\-force\fP
|
||||
+The user is prompted to confirm the convertion of a secure key. Use this option
|
||||
+to convert a secure key without prompting for a confirmation.
|
||||
+.
|
||||
+.
|
||||
+.
|
||||
.SS "General options"
|
||||
.TP
|
||||
.BR \-V ", " \-\-verbose
|
||||
--- a/zkey/zkey.c
|
||||
+++ b/zkey/zkey.c
|
||||
@@ -106,6 +106,7 @@ static struct zkey_globals {
|
||||
#define COMMAND_COPY "copy "
|
||||
#define COMMAND_CRYPTTAB "crypttab"
|
||||
#define COMMAND_CRYPTSETUP "cryptsetup"
|
||||
+#define COMMAND_CONVERT "convert"
|
||||
|
||||
#define ZKEY_COMMAND_MAX_LEN 10
|
||||
|
||||
@@ -767,6 +768,38 @@ static struct util_opt opt_vec[] = {
|
||||
/***********************************************************/
|
||||
{
|
||||
.flags = UTIL_OPT_FLAG_SECTION,
|
||||
+ .desc = "OPTIONS",
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ },
|
||||
+ {
|
||||
+ .option = { "name", required_argument, NULL, 'N'},
|
||||
+ .argument = "NAME",
|
||||
+ .desc = "Name of the secure AES key in the repository that is "
|
||||
+ "to be converted",
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ },
|
||||
+ {
|
||||
+ .option = { "key-type", required_argument, NULL, 'K'},
|
||||
+ .argument = "type",
|
||||
+ .desc = "The type of the key to convert the secure key to. "
|
||||
+ "Possible values are '"KEY_TYPE_CCA_AESCIPHER"'. ",
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ },
|
||||
+ {
|
||||
+ .option = {"no-apqn-check", 0, NULL, OPT_NO_APQN_CHECK},
|
||||
+ .desc = "Do not check if the associated APQN(s) are available",
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ .flags = UTIL_OPT_FLAG_NOSHORT,
|
||||
+ },
|
||||
+ {
|
||||
+ .option = {"force", 0, NULL, 'F'},
|
||||
+ .desc = "Do not prompt for a confirmation when converting a "
|
||||
+ "key",
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ },
|
||||
+ /***********************************************************/
|
||||
+ {
|
||||
+ .flags = UTIL_OPT_FLAG_SECTION,
|
||||
.desc = "COMMON OPTIONS"
|
||||
},
|
||||
{
|
||||
@@ -812,6 +845,7 @@ static int command_rename(void);
|
||||
static int command_copy(void);
|
||||
static int command_crypttab(void);
|
||||
static int command_cryptsetup(void);
|
||||
+static int command_convert(void);
|
||||
|
||||
static struct zkey_command zkey_commands[] = {
|
||||
{
|
||||
@@ -946,6 +980,21 @@ static struct zkey_command zkey_commands
|
||||
.has_options = 1,
|
||||
.need_keystore = 1,
|
||||
},
|
||||
+ {
|
||||
+ .command = COMMAND_CONVERT,
|
||||
+ .abbrev_len = 3,
|
||||
+ .function = command_convert,
|
||||
+ .need_cca_library = 1,
|
||||
+ .need_pkey_device = 1,
|
||||
+ .short_desc = "Convert a secure AES key",
|
||||
+ .long_desc = "Convert an existing secure AES key that is "
|
||||
+ "either contained in SECURE-KEY-FILE or is stored "
|
||||
+ "in the repository from one key type to another "
|
||||
+ "type.",
|
||||
+ .has_options = 1,
|
||||
+ .pos_arg = "[SECURE-KEY-FILE]",
|
||||
+ .pos_arg_optional = 1,
|
||||
+ },
|
||||
{ .command = NULL }
|
||||
};
|
||||
|
||||
@@ -1691,6 +1740,206 @@ static int command_cryptsetup(void)
|
||||
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Command handler for 'convert'.
|
||||
+ *
|
||||
+ * Converts secure keys from one key type to another
|
||||
+ */
|
||||
+static int command_convert_file(void)
|
||||
+{
|
||||
+ u8 output_key[2 * MAX_SECURE_KEY_SIZE];
|
||||
+ unsigned int output_key_size;
|
||||
+ size_t secure_key_size;
|
||||
+ int rc, is_old_mk;
|
||||
+ int selected = 1;
|
||||
+ u8 *secure_key;
|
||||
+ int min_level;
|
||||
+ u64 mkvp;
|
||||
+
|
||||
+ if (g.name != NULL) {
|
||||
+ warnx("Option '--name|-N' is not valid for "
|
||||
+ "re-enciphering a key outside of the repository");
|
||||
+ util_prg_print_parse_error();
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+ if (g.noapqncheck) {
|
||||
+ warnx("Option '--no-apqn-check' is not valid for "
|
||||
+ "converting a key outside of the repository");
|
||||
+ util_prg_print_parse_error();
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ min_level = get_min_card_level_for_keytype(g.key_type);
|
||||
+ if (min_level < 0) {
|
||||
+ warnx("Invalid key-type specified: %s", g.key_type);
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ rc = cross_check_apqns(NULL, 0, min_level, true, g.verbose);
|
||||
+ if (rc == -EINVAL)
|
||||
+ return EXIT_FAILURE;
|
||||
+ if (rc != 0 && rc != -ENOTSUP) {
|
||||
+ warnx("Your master key setup is improper");
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ /* Read the secure key to be re-enciphered */
|
||||
+ secure_key = read_secure_key(g.pos_arg, &secure_key_size, g.verbose);
|
||||
+ if (secure_key == NULL)
|
||||
+ return EXIT_FAILURE;
|
||||
+
|
||||
+ rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL,
|
||||
+ &is_old_mk, NULL, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("The secure key in file '%s' is not valid", g.pos_arg);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = get_master_key_verification_pattern(secure_key, secure_key_size,
|
||||
+ &mkvp, g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Failed to get the master key verification pattern: %s",
|
||||
+ strerror(-rc));
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (strcasecmp(get_key_type(secure_key, secure_key_size),
|
||||
+ g.key_type) == 0) {
|
||||
+ warnx("The secure key in file '%s' is already of type %s",
|
||||
+ g.pos_arg, get_key_type(secure_key, secure_key_size));
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (is_cca_aes_data_key(secure_key, secure_key_size)) {
|
||||
+ if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
|
||||
+ warnx("The secure key in file '%s' can not be "
|
||||
+ "converted into type %s", g.pos_arg, g.key_type);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ } else if (is_cca_aes_cipher_key(secure_key, secure_key_size)) {
|
||||
+ warnx("The secure key in file '%s' is already of type %s",
|
||||
+ g.pos_arg, KEY_TYPE_CCA_AESCIPHER);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ } else {
|
||||
+ warnx("The secure key in file '%s' has an unsupported key type",
|
||||
+ g.pos_arg);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = select_cca_adapter_by_mkvp(&g.cca, mkvp, NULL,
|
||||
+ FLAG_SEL_CCA_MATCH_CUR_MKVP,
|
||||
+ g.verbose);
|
||||
+ if (rc == -ENOTSUP) {
|
||||
+ rc = 0;
|
||||
+ selected = 0;
|
||||
+ }
|
||||
+ if (rc != 0) {
|
||||
+ warnx("No APQN found that is suitable for "
|
||||
+ "converting the secure AES key in file '%s'", g.pos_arg);
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (!g.force) {
|
||||
+ util_print_indented("ATTENTION: Converting a secure key is "
|
||||
+ "irreversible, and might have an effect "
|
||||
+ "on the volumes encrypted with it!", 0);
|
||||
+ printf("%s: Convert key in file '%s' [y/N]? ",
|
||||
+ program_invocation_short_name, g.pos_arg);
|
||||
+ if (!prompt_for_yes(g.verbose)) {
|
||||
+ warnx("Operation aborted");
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ memset(output_key, 0, sizeof(output_key));
|
||||
+ output_key_size = sizeof(output_key);
|
||||
+ rc = convert_aes_data_to_cipher_key(&g.cca, secure_key, secure_key_size,
|
||||
+ output_key, &output_key_size,
|
||||
+ g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Converting the secure key from %s to %s has failed",
|
||||
+ get_key_type(secure_key, secure_key_size), g.key_type);
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ rc = restrict_key_export(&g.cca, output_key, output_key_size,
|
||||
+ g.verbose);
|
||||
+ if (rc != 0) {
|
||||
+ warnx("Export restricting the converted secure key has failed");
|
||||
+ if (!selected)
|
||||
+ print_msg_for_cca_envvars("secure AES key");
|
||||
+ rc = EXIT_FAILURE;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ pr_verbose("Secure key was converted successfully");
|
||||
+
|
||||
+ /* Write the converted secure key */
|
||||
+ rc = write_secure_key(g.outputfile ? g.outputfile : g.pos_arg,
|
||||
+ output_key, output_key_size, g.verbose);
|
||||
+ if (rc != 0)
|
||||
+ rc = EXIT_FAILURE;
|
||||
+out:
|
||||
+ free(secure_key);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Command handler for 'convert in repository'.
|
||||
+ *
|
||||
+ * Converts secure keys from one key type to another
|
||||
+ */
|
||||
+static int command_convert_repository(void)
|
||||
+{
|
||||
+ int rc;
|
||||
+
|
||||
+ if (g.name == NULL) {
|
||||
+ misc_print_required_parm("--name/-N");
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ rc = keystore_convert_key(g.keystore, g.name, g.key_type, g.noapqncheck,
|
||||
+ g.force, g.pkey_fd, &g.cca);
|
||||
+
|
||||
+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Command handler for 'convert'.
|
||||
+ *
|
||||
+ * Converts secure keys from one key type to another
|
||||
+ */
|
||||
+static int command_convert(void)
|
||||
+{
|
||||
+ if (g.key_type == NULL) {
|
||||
+ misc_print_required_parm("--key-type/-K");
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+ if (strcasecmp(g.key_type, KEY_TYPE_CCA_AESCIPHER) != 0) {
|
||||
+ warnx("Secure keys can only be converted into key type %s",
|
||||
+ KEY_TYPE_CCA_AESCIPHER);
|
||||
+ return EXIT_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ if (g.pos_arg != NULL)
|
||||
+ return command_convert_file();
|
||||
+ else
|
||||
+ return command_convert_repository();
|
||||
+
|
||||
+ return EXIT_SUCCESS;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Opens the keystore. The keystore directory is either the
|
||||
* default directory or as specified in an environment variable
|
@ -1,51 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/libc: include 's390.h'
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: b0f82d22f9f60a0a8db1976751aa5a875e7c5f80
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: include 's390.h'
|
||||
|
||||
Include 'boot/s390.h' in 'libc.c' as `PAGE_SIZE` is used there and
|
||||
move the 'libc.h' include directive to the top.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -9,12 +9,14 @@
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
+#include "libc.h"
|
||||
+
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
+#include "boot/s390.h"
|
||||
|
||||
#include "error.h"
|
||||
-#include "libc.h"
|
||||
#include "sclp.h"
|
||||
|
||||
extern char __heap_start[];
|
@ -1,63 +0,0 @@
|
||||
Subject: zkey: Allow 'zkey-cryptsetup setkey' to set different key types
|
||||
From: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
|
||||
Summary: zkey: Add support for CCA AES CIPHER keys
|
||||
Description: With CCA 5 there is a new secure key type, the so called
|
||||
variable length symmetric cipher key token. This token format
|
||||
can hold AES keys with size 128, 192 and 256 bits together
|
||||
with additional attributes cryptographic bound to the key
|
||||
token. The attributes may limit the usage of the key, for
|
||||
example restrict export or usability scope. So this key type
|
||||
is considered to be even more secure than the traditional
|
||||
secure key token. This key token type is also called "CCA
|
||||
AES CIPHER key", where the formerly used key token is called
|
||||
"CCA AES DATA key".
|
||||
The zkey as well as the zkey-cryptsetup tools are enhanced
|
||||
to support AES CIPHER keys. That is, zkey can manage AES DATA
|
||||
keys, as well as AES CIPHER keys. The key type must be specified
|
||||
at key generation time, the default is to generate AED DATA
|
||||
keys.
|
||||
Upstream-ID: bc987c8d18ddeb6fec46113a7fe7588555b592e7
|
||||
Problem-ID: SEC1717
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zkey: Allow 'zkey-cryptsetup setkey' to set different key types
|
||||
|
||||
When a secure key has been converted from type CCA-AESDATA to type
|
||||
CCA-AESCIPHER, the secure key stored in the LUKS2 header of a volume
|
||||
encrypted with that key should also changed.
|
||||
|
||||
Command 'zkey-cryptsetup setkey' allows to set (replace) the volume
|
||||
key in the LUKS2 header. It now accepts keys to be set that have
|
||||
a different size of the original volume keys. CCA-AESCIPHER keys
|
||||
are larger than CCA-AESDATA keys.
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
|
||||
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
---
|
||||
zkey/zkey-cryptsetup.c | 9 +--------
|
||||
1 file changed, 1 insertion(+), 8 deletions(-)
|
||||
|
||||
--- a/zkey/zkey-cryptsetup.c
|
||||
+++ b/zkey/zkey-cryptsetup.c
|
||||
@@ -2169,14 +2169,7 @@ static int command_setkey(void)
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
- if (keysize != newkey_size) {
|
||||
- warnx("The secure key in file '%s' has an invalid size",
|
||||
- g.master_key_file);
|
||||
- rc = -EINVAL;
|
||||
- goto out;
|
||||
- }
|
||||
-
|
||||
- if (memcmp(newkey, key, keysize) == 0) {
|
||||
+ if (keysize == newkey_size && memcmp(newkey, key, keysize) == 0) {
|
||||
warnx("The secure key in file '%s' is equal to the current "
|
||||
"volume key, setkey is ignored", g.master_key_file);
|
||||
rc = 0;
|
@ -1,69 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] include/boot/s390.h: move panic and panic_notify to libc.h
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 2568863f581cff9bf3b1e27c2d2917b5ae3b5177
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
include/boot/s390.h: move panic and panic_notify to libc.h
|
||||
|
||||
... as this code is not s390 specific and not every user of s390.h
|
||||
wants to implement `panic_notify`.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/s390.h | 9 ---------
|
||||
zipl/boot/libc.h | 8 ++++++++
|
||||
2 files changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/include/boot/s390.h
|
||||
+++ b/include/boot/s390.h
|
||||
@@ -201,15 +201,6 @@ struct _lowcore {
|
||||
#define S390_lowcore (*((struct _lowcore *) 0))
|
||||
|
||||
|
||||
-void panic_notify(unsigned long reason);
|
||||
-
|
||||
-#define panic(reason, x...) \
|
||||
-do { \
|
||||
- printf(x); \
|
||||
- panic_notify(reason); \
|
||||
- libc_stop(reason); \
|
||||
-} while (0)
|
||||
-
|
||||
static __always_inline int page_is_valid(unsigned long addr)
|
||||
{
|
||||
unsigned long tmp;
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -61,6 +61,14 @@ void libc_stop(unsigned long);
|
||||
void start(void);
|
||||
void pgm_check_handler(void);
|
||||
void pgm_check_handler_fn(void);
|
||||
+void panic_notify(unsigned long reason);
|
||||
+
|
||||
+#define panic(reason, ...) \
|
||||
+ do { \
|
||||
+ printf(__VA_ARGS__); \
|
||||
+ panic_notify(reason); \
|
||||
+ libc_stop(reason); \
|
||||
+ } while (0)
|
||||
|
||||
static inline int isdigit(int c)
|
||||
{
|
@ -1,73 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] include/boot/s390.h: fixes for -Werror=sign-conversion
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 305235a7bce814f71ec113a612b6117c96894e23
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
include/boot/s390.h: fixes for -Werror=sign-conversion
|
||||
|
||||
Errors fixed:
|
||||
|
||||
../../include/boot/s390.h: In function '__stfle_asm':
|
||||
../../include/boot/s390.h:424:41: error: conversion to 'long unsigned int' from 'int' may change the sign of the result [-Werror=sign-conversion]
|
||||
register unsigned long reg0 asm("0") = size - 1;
|
||||
|
||||
../../include/boot/s390.h: In function 'stfle':
|
||||
../../include/boot/s390.h:453:31: error: conversion to 'long unsigned int' from 'int' may change the sign of the result [-Werror=sign-conversion]
|
||||
nr = MIN((nr + 1) * 8, size * 8UL);
|
||||
|
||||
../../include/boot/s390.h: In function 'diag308':
|
||||
../../include/boot/s390.h:296:9: error: conversion from 'long unsigned int' to 'int' may change value [-Werror=conversion]
|
||||
return _rc;
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
include/boot/s390.h | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/boot/s390.h
|
||||
+++ b/include/boot/s390.h
|
||||
@@ -269,7 +269,7 @@ enum diag308_subcode {
|
||||
DIAG308_STORE = 6,
|
||||
};
|
||||
|
||||
-static __always_inline int diag308(unsigned long subcode, void *addr)
|
||||
+static __always_inline unsigned long diag308(unsigned long subcode, void *addr)
|
||||
{
|
||||
register unsigned long _addr asm("0") = (unsigned long) addr;
|
||||
register unsigned long _rc asm("1") = 0;
|
||||
@@ -403,7 +403,7 @@ static __always_inline int test_facility
|
||||
return __test_facility(nr, &S390_lowcore.stfle_fac_list);
|
||||
}
|
||||
|
||||
-static __always_inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, int size)
|
||||
+static __always_inline unsigned long __stfle_asm(uint64_t *stfle_fac_list, unsigned int size)
|
||||
{
|
||||
register unsigned long reg0 asm("0") = size - 1;
|
||||
|
||||
@@ -420,7 +420,7 @@ static __always_inline unsigned long __s
|
||||
* @stfle_fac_list: array where facility list can be stored
|
||||
* @size: size of passed in array in double words
|
||||
*/
|
||||
-static __always_inline void stfle(uint64_t *stfle_fac_list, int size)
|
||||
+static __always_inline void stfle(uint64_t *stfle_fac_list, unsigned int size)
|
||||
{
|
||||
unsigned long nr;
|
||||
|
@ -1,640 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl: refactor all EBCDIC code into separate files
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: a37170b8bec07a0ffc3270a4c78124e1117f0337
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl: refactor all EBCDIC code into separate files
|
||||
|
||||
This allows the reuse of the code later in sclp.c. While at it, also
|
||||
declare @source parameter of `ebcdic_to_ascii` function as `const` and
|
||||
rename all `ebc_` function name prefixes into `ebcdic_`. Move
|
||||
conversion tables to separate file so it only gets linked into loaders
|
||||
that need it.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/Makefile | 16 ++--
|
||||
zipl/boot/ebcdic.c | 30 ++++++++
|
||||
zipl/boot/ebcdic.h | 45 ++++++++++++
|
||||
zipl/boot/ebcdic_conv.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zipl/boot/ebcdic_conv.h | 21 ++++++
|
||||
zipl/boot/libc.c | 19 -----
|
||||
zipl/boot/libc.h | 25 -------
|
||||
zipl/boot/menu.c | 9 +-
|
||||
zipl/boot/stage3.c | 156 --------------------------------------------
|
||||
9 files changed, 280 insertions(+), 208 deletions(-)
|
||||
|
||||
--- a/zipl/boot/Makefile
|
||||
+++ b/zipl/boot/Makefile
|
||||
@@ -28,22 +28,22 @@ all: data.o data.h tape0.bin stage3.bin
|
||||
|
||||
eckd2dump_sv.exec: \
|
||||
head.o stage2dump.o cio.o eckd2dump.o eckd2dump_sv.o \
|
||||
- libc.o sclp.o entry.o
|
||||
+ libc.o ebcdic.o sclp.o entry.o
|
||||
eckd2dump_mv.exec: \
|
||||
head.o stage2dump.o cio.o eckd2dump.o eckd2dump_mv.o \
|
||||
- libc.o sclp.o entry.o
|
||||
+ libc.o ebcdic.o sclp.o entry.o
|
||||
fba2dump.exec: \
|
||||
head.o stage2dump.o cio.o fba2dump.o \
|
||||
- libc.o sclp.o entry.o
|
||||
+ libc.o ebcdic.o sclp.o entry.o
|
||||
tape2dump.exec: \
|
||||
head.o stage2dump.o cio.o tape2dump.o \
|
||||
- libc.o sclp.o entry.o
|
||||
-eckd2.exec: head.o stage2.o cio.o eckd2.o libc.o menu.o sclp.o \
|
||||
+ libc.o ebcdic.o sclp.o entry.o
|
||||
+eckd2.exec: head.o stage2.o cio.o eckd2.o libc.o ebcdic.o menu.o sclp.o \
|
||||
kdump2.o kdump.o entry.o
|
||||
-fba2.exec: head.o stage2.o cio.o fba2.o libc.o menu.o sclp.o \
|
||||
+fba2.exec: head.o stage2.o cio.o fba2.o libc.o ebcdic.o menu.o sclp.o \
|
||||
kdump2.o kdump.o entry.o
|
||||
-stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \
|
||||
- kdump.o entry.o stage3.lds
|
||||
+stage3.exec: head.o stage3.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o \
|
||||
+ sclp_stage3.o kdump.o entry.o stage3.lds
|
||||
|
||||
%.exec: %.o
|
||||
STAGE=$$( \
|
||||
--- /dev/null
|
||||
+++ b/zipl/boot/ebcdic.c
|
||||
@@ -0,0 +1,30 @@
|
||||
+/*
|
||||
+ * EBCDIC specific functions
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2013, 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.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include "ebcdic.h"
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * Convert ebcdic string to number with given base
|
||||
+ */
|
||||
+unsigned long ebcdic_strtoul(char *nptr, char **endptr, int base)
|
||||
+{
|
||||
+ unsigned long val = 0;
|
||||
+
|
||||
+ while (ebcdic_isdigit(*nptr)) {
|
||||
+ if (val != 0)
|
||||
+ val *= base;
|
||||
+ val += *nptr - 0xf0;
|
||||
+ nptr++;
|
||||
+ }
|
||||
+ if (endptr)
|
||||
+ *endptr = (char *)nptr;
|
||||
+ return val;
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/zipl/boot/ebcdic.h
|
||||
@@ -0,0 +1,45 @@
|
||||
+/*
|
||||
+ * EBCDIC specific functions
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2013, 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 EBCDIC_H
|
||||
+#define EBCDIC_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+unsigned long ebcdic_strtoul(char *, char **, int);
|
||||
+
|
||||
+static __always_inline int ecbdic_isspace(char c)
|
||||
+{
|
||||
+ return (c == 0x40) || (c == 0x05) || (c == 0x15) || (c == 0x25) ||
|
||||
+ (c == 0x0b) || (c == 0x0c) || (c == 0x0d);
|
||||
+}
|
||||
+
|
||||
+static __always_inline int ebcdic_isdigit(char c)
|
||||
+{
|
||||
+ return (c >= 0xf0) && (c <= 0xf9);
|
||||
+}
|
||||
+
|
||||
+static __always_inline int ebcdic_isupper(char c)
|
||||
+{
|
||||
+ return (c >= 0xC1 && c <= 0xC9) || (c >= 0xD1 && c <= 0xD9) ||
|
||||
+ (c >= 0xE2 && c <= 0xE9);
|
||||
+}
|
||||
+
|
||||
+static __always_inline char ebcdic_tolower(char c)
|
||||
+{
|
||||
+ if (ebcdic_isupper(c))
|
||||
+ c -= 0x40;
|
||||
+ return c;
|
||||
+}
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* EBCDIC_H */
|
||||
--- /dev/null
|
||||
+++ b/zipl/boot/ebcdic_conv.c
|
||||
@@ -0,0 +1,167 @@
|
||||
+/*
|
||||
+ * EBCDIC conversion functions
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2013, 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.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include "ebcdic_conv.h"
|
||||
+#include "libc.h"
|
||||
+#include "boot/s390.h"
|
||||
+
|
||||
+
|
||||
+static unsigned char ebcdic_037[256] = {
|
||||
+/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
+/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
+/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
+ -ENP ->LF */
|
||||
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
+/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
+ -IUS */
|
||||
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
+ -INP */
|
||||
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
+/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
+ -SW */
|
||||
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
+/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
+/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
+/* 0x40 SP RSP ä ---- */
|
||||
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
+/* 0x48 . < ( + | */
|
||||
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
+/* 0x50 & ---- */
|
||||
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
+/* 0x58 ß ! $ * ) ; */
|
||||
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
+/* 0x60 - / ---- Ä ---- ---- ---- */
|
||||
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
||||
+/* 0x68 ---- , % _ > ? */
|
||||
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
+/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
||||
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0x78 * ` : # @ ' = " */
|
||||
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
+/* 0x80 * a b c d e f g */
|
||||
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
+/* 0x88 h i ---- ---- ---- */
|
||||
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
+/* 0x90 ° j k l m n o p */
|
||||
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
+/* 0x98 q r ---- ---- */
|
||||
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
+/* 0xA0 ~ s t u v w x */
|
||||
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
+/* 0xA8 y z ---- ---- ---- ---- */
|
||||
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0xB0 ^ ---- § ---- */
|
||||
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
+/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0xC0 { A B C D E F G */
|
||||
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
+/* 0xC8 H I ---- ö ---- */
|
||||
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
+/* 0xD0 } J K L M N O P */
|
||||
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
+/* 0xD8 Q R ---- ü */
|
||||
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
+/* 0xE0 \ S T U V W X */
|
||||
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
+/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
||||
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
||||
+/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
+/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
||||
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
+};
|
||||
+
|
||||
+static unsigned char ebcdic_500[256] = {
|
||||
+/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
+/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
+/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
+ -ENP ->LF */
|
||||
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
+/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
+ -IUS */
|
||||
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
+ -INP */
|
||||
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
+/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
+ -SW */
|
||||
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
+/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
+/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
+/* 0x40 SP RSP ä ---- */
|
||||
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
+/* 0x48 . < ( + | */
|
||||
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
+/* 0x50 & ---- */
|
||||
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
+/* 0x58 ß ! $ * ) ; */
|
||||
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
+/* 0x60 - / ---- Ä ---- ---- ---- */
|
||||
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
||||
+/* 0x68 ---- , % _ > ? */
|
||||
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
+/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
||||
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0x78 * ` : # @ ' = " */
|
||||
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
+/* 0x80 * a b c d e f g */
|
||||
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
+/* 0x88 h i ---- ---- ---- */
|
||||
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
+/* 0x90 ° j k l m n o p */
|
||||
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
+/* 0x98 q r ---- ---- */
|
||||
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
+/* 0xA0 ~ s t u v w x */
|
||||
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
+/* 0xA8 y z ---- ---- ---- ---- */
|
||||
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0xB0 ^ ---- § ---- */
|
||||
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
+/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
+/* 0xC0 { A B C D E F G */
|
||||
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
+/* 0xC8 H I ---- ö ---- */
|
||||
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
+/* 0xD0 } J K L M N O P */
|
||||
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
+/* 0xD8 Q R ---- ü */
|
||||
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
+/* 0xE0 \ S T U V W X */
|
||||
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
+/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
||||
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
||||
+/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
+/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
||||
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
+};
|
||||
+
|
||||
+void ebcdic_to_ascii(unsigned char *target, const unsigned char *source,
|
||||
+ unsigned int l)
|
||||
+{
|
||||
+ unsigned char *ebc;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ ebc = is_zvm() ? ebcdic_037 : ebcdic_500;
|
||||
+ for (i = 0; i < l; i++)
|
||||
+ target[i] = ebc[source[i]];
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/zipl/boot/ebcdic_conv.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * EBCDIC conversion functions
|
||||
+ *
|
||||
+ * Copyright IBM Corp. 2013, 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 EBCDIC_CONV_H
|
||||
+#define EBCDIC_CONV_H
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+void ebcdic_to_ascii(unsigned char *target, const unsigned char *source,
|
||||
+ unsigned int l);
|
||||
+
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* EBCDIC_CONV_H */
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "error.h"
|
||||
#include "sclp.h"
|
||||
+#include "ebcdic.h"
|
||||
|
||||
extern char __heap_start[];
|
||||
extern char __heap_stop[];
|
||||
@@ -129,24 +130,6 @@ int strncmp(const char *s1, const char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Convert ebcdic string to number with given base
|
||||
- */
|
||||
-unsigned long ebcstrtoul(char *nptr, char **endptr, int base)
|
||||
-{
|
||||
- unsigned long val = 0;
|
||||
-
|
||||
- while (ebc_isdigit(*nptr)) {
|
||||
- if (val != 0)
|
||||
- val *= base;
|
||||
- val += *nptr - 0xf0;
|
||||
- nptr++;
|
||||
- }
|
||||
- if (endptr)
|
||||
- *endptr = (char *) nptr;
|
||||
- return val;
|
||||
-}
|
||||
-
|
||||
static int skip_atoi(const char **c)
|
||||
{
|
||||
int i = 0;
|
||||
--- a/zipl/boot/libc.h
|
||||
+++ b/zipl/boot/libc.h
|
||||
@@ -51,7 +51,6 @@ void *memmove(void *, const void *, unsi
|
||||
void *memset(void *, int c, unsigned long);
|
||||
char *strcat(char *, const char *);
|
||||
int strncmp(const char *, const char *, unsigned long);
|
||||
-unsigned long ebcstrtoul(char *, char **, int);
|
||||
int strlen(const char *);
|
||||
char *strcpy(char *, const char *);
|
||||
unsigned long get_zeroed_page(void);
|
||||
@@ -80,28 +79,4 @@ static inline int isspace(char c)
|
||||
return (c == 32) || (c >= 9 && c <= 13);
|
||||
}
|
||||
|
||||
-static inline int ebc_isspace(char c)
|
||||
-{
|
||||
- return (c == 0x40) || (c == 0x05) || (c == 0x15) || (c == 0x25) ||
|
||||
- (c == 0x0b) || (c == 0x0c) || (c == 0x0d);
|
||||
-}
|
||||
-
|
||||
-static inline int ebc_isdigit(char c)
|
||||
-{
|
||||
- return (c >= 0xf0) && (c <= 0xf9);
|
||||
-}
|
||||
-
|
||||
-static inline int ebc_isupper(char c)
|
||||
-{
|
||||
- return (c >= 0xC1 && c <= 0xC9) || (c >= 0xD1 && c <= 0xD9) ||
|
||||
- (c >= 0xE2 && c <= 0xE9);
|
||||
-}
|
||||
-
|
||||
-static inline char ebc_tolower(char c)
|
||||
-{
|
||||
- if (ebc_isupper(c))
|
||||
- c -= 0x40;
|
||||
- return c;
|
||||
-}
|
||||
-
|
||||
#endif /* LIBC_H */
|
||||
--- a/zipl/boot/menu.c
|
||||
+++ b/zipl/boot/menu.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "libc.h"
|
||||
#include "menu.h"
|
||||
#include "sclp.h"
|
||||
+#include "ebcdic.h"
|
||||
|
||||
static const char *msg_econfig = "Error: undefined configuration\n";
|
||||
|
||||
@@ -55,8 +56,8 @@ static int menu_read(void)
|
||||
/* input under zVM needs to be converted to lower case */
|
||||
if (is_zvm())
|
||||
for (i = 0; i < count; i++)
|
||||
- temp_area[i] = ebc_tolower(temp_area[i]);
|
||||
- value = ebcstrtoul((char *)temp_area, &endptr, 10);
|
||||
+ temp_area[i] = ebcdic_tolower(temp_area[i]);
|
||||
+ value = ebcdic_strtoul((char *)temp_area, &endptr, 10);
|
||||
|
||||
if ((endptr != temp_area) && (value < BOOT_MENU_ENTRIES - 1) &&
|
||||
(__stage2_params.config[value] != 0)) {
|
||||
@@ -112,7 +113,7 @@ static int menu_param(unsigned long *val
|
||||
int i;
|
||||
|
||||
if (!sclp_param(loadparm))
|
||||
- *value = ebcstrtoul(loadparm, &endptr, 10);
|
||||
+ *value = ebcdic_strtoul(loadparm, &endptr, 10);
|
||||
|
||||
/* got number, done */
|
||||
if (endptr != loadparm)
|
||||
@@ -121,7 +122,7 @@ static int menu_param(unsigned long *val
|
||||
/* no number, check for keyword */
|
||||
i = 0;
|
||||
/* skip leading whitespaces */
|
||||
- while ((i < PARAM_SIZE) && ebc_isspace(loadparm[i]))
|
||||
+ while ((i < PARAM_SIZE) && ecbdic_isspace(loadparm[i]))
|
||||
i++;
|
||||
|
||||
if (!strncmp(&loadparm[i], "PROMPT", 6)) {
|
||||
--- a/zipl/boot/stage3.c
|
||||
+++ b/zipl/boot/stage3.c
|
||||
@@ -12,9 +12,12 @@
|
||||
#include "libc.h"
|
||||
#include "boot/sigp.h"
|
||||
#include "boot/s390.h"
|
||||
+#include "boot/sigp.h"
|
||||
#include "stage3.h"
|
||||
#include "error.h"
|
||||
#include "zipl.h"
|
||||
+#include "ebcdic.h"
|
||||
+#include "ebcdic_conv.h"
|
||||
|
||||
#define for_each_rb_entry(entry, rb) \
|
||||
for (entry = rb->entries; \
|
||||
@@ -24,159 +27,6 @@
|
||||
static const char *msg_sipl_inval = "Secure boot failure: invalid load address";
|
||||
static const char *msg_sipl_unverified = "Secure boot failure: unverified load address";
|
||||
|
||||
-static unsigned char ebc_037[256] = {
|
||||
-/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
- 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
-/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
- 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
-/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
- -ENP ->LF */
|
||||
- 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
-/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
- -IUS */
|
||||
- 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
- -INP */
|
||||
- 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
-/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
- -SW */
|
||||
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
-/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
- 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
-/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
- 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
-/* 0x40 SP RSP ä ---- */
|
||||
- 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
-/* 0x48 . < ( + | */
|
||||
- 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
-/* 0x50 & ---- */
|
||||
- 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
-/* 0x58 ß ! $ * ) ; */
|
||||
- 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
-/* 0x60 - / ---- Ä ---- ---- ---- */
|
||||
- 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
||||
-/* 0x68 ---- , % _ > ? */
|
||||
- 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
-/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
||||
- 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0x78 * ` : # @ ' = " */
|
||||
- 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
-/* 0x80 * a b c d e f g */
|
||||
- 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
-/* 0x88 h i ---- ---- ---- */
|
||||
- 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
-/* 0x90 ° j k l m n o p */
|
||||
- 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
-/* 0x98 q r ---- ---- */
|
||||
- 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
-/* 0xA0 ~ s t u v w x */
|
||||
- 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
-/* 0xA8 y z ---- ---- ---- ---- */
|
||||
- 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0xB0 ^ ---- § ---- */
|
||||
- 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
-/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
- 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0xC0 { A B C D E F G */
|
||||
- 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
-/* 0xC8 H I ---- ö ---- */
|
||||
- 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
-/* 0xD0 } J K L M N O P */
|
||||
- 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
-/* 0xD8 Q R ---- ü */
|
||||
- 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
-/* 0xE0 \ S T U V W X */
|
||||
- 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
-/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
||||
- 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
||||
-/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
-/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
||||
- 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
-};
|
||||
-
|
||||
-static unsigned char ebc_500[256] = {
|
||||
-/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||
- 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||
-/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||
- 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
-/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
|
||||
- -ENP ->LF */
|
||||
- 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
|
||||
-/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
|
||||
- -IUS */
|
||||
- 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
|
||||
- -INP */
|
||||
- 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
|
||||
-/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
|
||||
- -SW */
|
||||
- 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
|
||||
-/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
|
||||
- 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
|
||||
-/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
|
||||
- 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
|
||||
-/* 0x40 SP RSP ä ---- */
|
||||
- 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
|
||||
-/* 0x48 . < ( + | */
|
||||
- 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
|
||||
-/* 0x50 & ---- */
|
||||
- 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
|
||||
-/* 0x58 ß ! $ * ) ; */
|
||||
- 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
|
||||
-/* 0x60 - / ---- Ä ---- ---- ---- */
|
||||
- 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
|
||||
-/* 0x68 ---- , % _ > ? */
|
||||
- 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
|
||||
-/* 0x70 --- ---- ---- ---- ---- ---- ---- */
|
||||
- 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0x78 * ` : # @ ' = " */
|
||||
- 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
|
||||
-/* 0x80 * a b c d e f g */
|
||||
- 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
-/* 0x88 h i ---- ---- ---- */
|
||||
- 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
|
||||
-/* 0x90 ° j k l m n o p */
|
||||
- 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
|
||||
-/* 0x98 q r ---- ---- */
|
||||
- 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
|
||||
-/* 0xA0 ~ s t u v w x */
|
||||
- 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
|
||||
-/* 0xA8 y z ---- ---- ---- ---- */
|
||||
- 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0xB0 ^ ---- § ---- */
|
||||
- 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
|
||||
-/* 0xB8 ---- [ ] ---- ---- ---- ---- */
|
||||
- 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
|
||||
-/* 0xC0 { A B C D E F G */
|
||||
- 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
-/* 0xC8 H I ---- ö ---- */
|
||||
- 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
|
||||
-/* 0xD0 } J K L M N O P */
|
||||
- 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
|
||||
-/* 0xD8 Q R ---- ü */
|
||||
- 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
|
||||
-/* 0xE0 \ S T U V W X */
|
||||
- 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
|
||||
-/* 0xE8 Y Z ---- Ö ---- ---- ---- */
|
||||
- 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
|
||||
-/* 0xF0 0 1 2 3 4 5 6 7 */
|
||||
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
-/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
|
||||
- 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||
-};
|
||||
-
|
||||
-static void ebcdic_to_ascii(unsigned char *target, unsigned char *source,
|
||||
- unsigned int l)
|
||||
-{
|
||||
- unsigned char *ebc;
|
||||
- unsigned int i;
|
||||
-
|
||||
- ebc = is_zvm() ? ebc_037 : ebc_500;
|
||||
- for (i = 0; i < l; i++)
|
||||
- target[i] = ebc[source[i]];
|
||||
-}
|
||||
-
|
||||
static inline void __noreturn start_kernel(void)
|
||||
{
|
||||
struct psw_t *psw = &S390_lowcore.program_new_psw;
|
@ -1,79 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/sclp: add macros for the control-program masks
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 303a3707e2e59e0ad581876db426a52fffa606b0
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/sclp: add macros for the control-program masks
|
||||
|
||||
Add macros for the control-program masks and use them.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/sclp.c | 16 ++++++++--------
|
||||
zipl/boot/sclp.h | 6 ++++++
|
||||
2 files changed, 14 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/zipl/boot/sclp.c
|
||||
+++ b/zipl/boot/sclp.c
|
||||
@@ -126,20 +126,20 @@ int sclp_setup(int initialise)
|
||||
|
||||
switch (initialise) {
|
||||
case SCLP_INIT:
|
||||
- sccb->receive_mask = 0x80000000;
|
||||
- sccb->send_mask = 0x40000000;
|
||||
+ sccb->receive_mask = SCLP_EVENT_MASK_OPCMD;
|
||||
+ sccb->send_mask = SCLP_EVENT_MASK_MSG;
|
||||
break;
|
||||
case SCLP_DISABLE:
|
||||
- sccb->receive_mask = 0x0;
|
||||
- sccb->send_mask = 0x0;
|
||||
+ sccb->receive_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
+ sccb->send_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
break;
|
||||
case SCLP_HSA_INIT:
|
||||
- sccb->receive_mask = 0x0;
|
||||
- sccb->send_mask = 0x40000010;
|
||||
+ sccb->receive_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
+ sccb->send_mask = SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_SDIAS;
|
||||
break;
|
||||
case SCLP_HSA_INIT_ASYNC:
|
||||
- sccb->receive_mask = 0x00000010;
|
||||
- sccb->send_mask = 0x40000010;
|
||||
+ sccb->receive_mask = SCLP_EVENT_MASK_SDIAS;
|
||||
+ sccb->send_mask = SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_SDIAS;
|
||||
break;
|
||||
}
|
||||
|
||||
--- a/zipl/boot/sclp.h
|
||||
+++ b/zipl/boot/sclp.h
|
||||
@@ -28,6 +28,12 @@
|
||||
#define SCLP_CMD_READ_INFO2 0x00020001
|
||||
#define SCLP_CMD_READ_DATA 0x00770005
|
||||
|
||||
+/* SCLP event masks */
|
||||
+#define SCLP_EVENT_MASK_DISABLE 0x00000000
|
||||
+#define SCLP_EVENT_MASK_SDIAS 0x00000010
|
||||
+#define SCLP_EVENT_MASK_MSG 0x40000000
|
||||
+#define SCLP_EVENT_MASK_OPCMD 0x80000000
|
||||
+
|
||||
#define PSW_EXT_MASK 0x00080000ULL
|
||||
#define PSW_EXT_ADDR 0x80000000ULL
|
||||
#define PSW_WAIT_MASK 0x010a0000ULL
|
@ -1,163 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/sclp: add `sclp_print_ascii`
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: f99560f734e8101a0e8195d73e3350d9211335b8
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/sclp: add `sclp_print_ascii`
|
||||
|
||||
Add `sclp_print_ascii` function that can be used to print output on
|
||||
the SCLP ASCII console. This would increase the size of the
|
||||
loaders (e.g. eckd2.bin and fba2.bin) and therefore might break the
|
||||
compilation. In order to avoid that add a macro 'ENABLE_SCLP_ASCII'
|
||||
which must be defined by the users of the `sclp_print_ascii` function.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/sclp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
zipl/boot/sclp.h | 20 +++++++++++++++++++-
|
||||
2 files changed, 69 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/sclp.c
|
||||
+++ b/zipl/boot/sclp.c
|
||||
@@ -13,6 +13,10 @@
|
||||
#include "error.h"
|
||||
#include "boot/s390.h"
|
||||
#include "sclp.h"
|
||||
+#include "ebcdic.h"
|
||||
+#ifdef ENABLE_SCLP_ASCII
|
||||
+# include "ebcdic_conv.h"
|
||||
+#endif /* ENABLE_SCLP_ASCII */
|
||||
|
||||
/* Perform service call. Return 0 on success, non-zero otherwise. */
|
||||
static int sclp_service_call(unsigned int command, void *sccb)
|
||||
@@ -133,6 +137,10 @@ int sclp_setup(int initialise)
|
||||
sccb->receive_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
sccb->send_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
break;
|
||||
+ case SCLP_LINE_ASCII_INIT:
|
||||
+ sccb->receive_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
+ sccb->send_mask = SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_ASCII;
|
||||
+ break;
|
||||
case SCLP_HSA_INIT:
|
||||
sccb->receive_mask = SCLP_EVENT_MASK_DISABLE;
|
||||
sccb->send_mask = SCLP_EVENT_MASK_MSG | SCLP_EVENT_MASK_SDIAS;
|
||||
@@ -161,6 +169,48 @@ out_free_page:
|
||||
return rc;
|
||||
}
|
||||
|
||||
+#ifdef ENABLE_SCLP_ASCII
|
||||
+/* Content of @buffer must be EBCDIC encoded. The function used for
|
||||
+ * the conversion `ebcdic_to_ascii` differentiates whether the code
|
||||
+ * runs on z/VM or not and then selects the appropriate EBCDIC
|
||||
+ * coding.
|
||||
+ */
|
||||
+int sclp_print_ascii(const char *buffer)
|
||||
+{
|
||||
+ struct write_sccb *sccb = NULL;
|
||||
+ int rc, str_len = strlen(buffer);
|
||||
+ unsigned long data_len = str_len + 1;
|
||||
+
|
||||
+ /* don't overflow the sccb buffer */
|
||||
+ if (data_len > SCCB_MAX_DATA_LEN)
|
||||
+ data_len = SCCB_MAX_DATA_LEN;
|
||||
+
|
||||
+ sccb = (void *)get_zeroed_page();
|
||||
+ sccb->header.length = sizeof(struct write_sccb) - sizeof(struct mdb)
|
||||
+ + data_len;
|
||||
+ sccb->header.function_code = SCLP_FC_NORMAL_WRITE;
|
||||
+ sccb->msg_buf.header.length = sizeof(struct msg_buf) - sizeof(struct mdb)
|
||||
+ + data_len;
|
||||
+ sccb->msg_buf.header.type = SCLP_EVENT_DATA_ASCII;
|
||||
+ sccb->msg_buf.header.flags = 0;
|
||||
+ ebcdic_to_ascii(sccb->msg_buf.data,
|
||||
+ (const unsigned char *)buffer,
|
||||
+ data_len - 1);
|
||||
+ sccb->msg_buf.data[data_len - 1] = '\0';
|
||||
+
|
||||
+ /* SCLP command for write data */
|
||||
+ rc = start_sclp(SCLP_CMD_WRITE_DATA, sccb);
|
||||
+ if (rc || sccb->header.response_code != 0x20) {
|
||||
+ rc = 1;
|
||||
+ goto out_free_page;
|
||||
+ }
|
||||
+ rc = 0;
|
||||
+out_free_page:
|
||||
+ free_page((unsigned long) sccb);
|
||||
+ return rc;
|
||||
+}
|
||||
+#endif /* ENABLE_SCLP_ASCII */
|
||||
+
|
||||
int sclp_print(char *buffer)
|
||||
{
|
||||
struct write_sccb *sccb;
|
||||
--- a/zipl/boot/sclp.h
|
||||
+++ b/zipl/boot/sclp.h
|
||||
@@ -28,9 +28,16 @@
|
||||
#define SCLP_CMD_READ_INFO2 0x00020001
|
||||
#define SCLP_CMD_READ_DATA 0x00770005
|
||||
|
||||
+/* SCLP function codes */
|
||||
+#define SCLP_FC_NORMAL_WRITE 0
|
||||
+
|
||||
+/* SCLP event data types */
|
||||
+#define SCLP_EVENT_DATA_ASCII 0x1a
|
||||
+
|
||||
/* SCLP event masks */
|
||||
#define SCLP_EVENT_MASK_DISABLE 0x00000000
|
||||
#define SCLP_EVENT_MASK_SDIAS 0x00000010
|
||||
+#define SCLP_EVENT_MASK_ASCII 0x00000040
|
||||
#define SCLP_EVENT_MASK_MSG 0x40000000
|
||||
#define SCLP_EVENT_MASK_OPCMD 0x80000000
|
||||
|
||||
@@ -46,6 +53,11 @@
|
||||
#define SCLP_DISABLE 0x1
|
||||
#define SCLP_HSA_INIT 0x2
|
||||
#define SCLP_HSA_INIT_ASYNC 0x3
|
||||
+#define SCLP_LINE_ASCII_INIT 0x4
|
||||
+
|
||||
+#define SCCB_SIZE PAGE_SIZE
|
||||
+#define SCCB_MAX_DATA_LEN (SCCB_SIZE - sizeof(struct sccb_header) \
|
||||
+ - sizeof(struct evbuf_header))
|
||||
|
||||
typedef uint32_t sccb_mask_t;
|
||||
|
||||
@@ -114,7 +126,10 @@ struct mdb {
|
||||
|
||||
struct msg_buf {
|
||||
struct evbuf_header header;
|
||||
- struct mdb mdb;
|
||||
+ union {
|
||||
+ struct mdb mdb;
|
||||
+ uint8_t data[0];
|
||||
+ };
|
||||
} __packed;
|
||||
|
||||
struct write_sccb {
|
||||
@@ -164,6 +179,9 @@ struct read_sccb {
|
||||
int start_sclp(unsigned int, void *);
|
||||
int sclp_setup(int);
|
||||
int sclp_print(char *);
|
||||
+# ifdef ENABLE_SCLP_ASCII
|
||||
+int sclp_print_ascii(const char *);
|
||||
+# endif /* ENABLE_SCLP_ASCII */
|
||||
int sclp_param(char *);
|
||||
int sclp_read(unsigned long, void *, int *);
|
||||
int sclp_read_info(struct read_info_sccb *sccb);
|
@ -1,47 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] zipl/libc: printf: print on linemode and ASCII console
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: e51663bbca8770c1f7986dac47a59193dbf96010
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
zipl/libc: printf: print on linemode and ASCII console
|
||||
|
||||
... if the `ENABLE_SCLP_ASCII` macro is defined.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
zipl/boot/libc.c | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/zipl/boot/libc.c
|
||||
+++ b/zipl/boot/libc.c
|
||||
@@ -406,8 +406,11 @@ void printf(const char *fmt, ...)
|
||||
buf[LINE_LENGTH - 2] = '.';
|
||||
buf[LINE_LENGTH - 3] = '.';
|
||||
}
|
||||
- sclp_print(buf);
|
||||
va_end(va);
|
||||
+ sclp_print(buf);
|
||||
+#ifdef ENABLE_SCLP_ASCII
|
||||
+ sclp_print_ascii(buf);
|
||||
+#endif /* ENABLE_SCLP_ASCII */
|
||||
}
|
||||
|
||||
/*
|
@ -1,134 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] Consolidate `ALIGN, __ALIGN_MASK, ARRAY_SIZE` macros
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 67aef9bbf3b5d18c70e8c4a45734bcb6d6744a8c
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
Consolidate `ALIGN, __ALIGN_MASK, ARRAY_SIZE` macros
|
||||
|
||||
Consolidate `ALIGN, __ALIGN_MASK, ARRAY_SIZE` macros and add them to
|
||||
lib/zt_common.h. While at it, adapt coding style.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
cmsfs-fuse/dasd.c | 1 +
|
||||
cmsfs-fuse/helper.h | 2 --
|
||||
include/lib/zt_common.h | 4 ++++
|
||||
zconf/qeth/misc.h | 2 --
|
||||
zdev/include/misc.h | 2 +-
|
||||
zdump/zg.c | 2 +-
|
||||
zdump/zg.h | 3 ---
|
||||
zipl/include/zipl.h | 4 ----
|
||||
8 files changed, 7 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/cmsfs-fuse/dasd.c
|
||||
+++ b/cmsfs-fuse/dasd.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "cmsfs-fuse.h"
|
||||
#include "edf.h"
|
||||
#include "helper.h"
|
||||
--- a/cmsfs-fuse/helper.h
|
||||
+++ b/cmsfs-fuse/helper.h
|
||||
@@ -49,6 +49,4 @@ extern FILE *logfile;
|
||||
fprintf(stderr, COMP "Warning, " __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
-
|
||||
#endif
|
||||
--- a/include/lib/zt_common.h
|
||||
+++ b/include/lib/zt_common.h
|
||||
@@ -44,6 +44,10 @@
|
||||
# define STATIC_ASSERT(test)
|
||||
#endif
|
||||
|
||||
+#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1)
|
||||
+#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
+
|
||||
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
||||
--- a/zconf/qeth/misc.h
|
||||
+++ b/zconf/qeth/misc.h
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
-
|
||||
char *misc_link_target(const char *fmt, ...);
|
||||
bool misc_str_in_list(const char *str, const char *strings[], int array_size);
|
||||
int misc_argz_add_from_file(char **argz, size_t *argz_len,
|
||||
--- a/zdev/include/misc.h
|
||||
+++ b/zdev/include/misc.h
|
||||
@@ -15,10 +15,10 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+#include "lib/zt_common.h"
|
||||
#include "lib/util_list.h"
|
||||
#include "exit_code.h"
|
||||
|
||||
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#define SCOPE_ACTIVE(x) ((x) & config_active ? 1 : 0)
|
||||
#define SCOPE_PERSISTENT(x) ((x) & config_persistent ? 1 : 0)
|
||||
#define SCOPE_AUTOCONF(x) ((x) & config_autoconf ? 1 : 0)
|
||||
--- a/zdump/zg.c
|
||||
+++ b/zdump/zg.c
|
||||
@@ -432,7 +432,7 @@ char *zg_devnode_create(dev_t dev)
|
||||
char *file_path;
|
||||
unsigned int i;
|
||||
|
||||
- for (i = 0; i < ARRAY_ELEMENT_CNT(dir_vec); i++) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(dir_vec); i++) {
|
||||
if (dir_vec[i] == NULL)
|
||||
continue;
|
||||
file_path = devnode_create_dir(dir_vec[i], dev);
|
||||
--- a/zdump/zg.h
|
||||
+++ b/zdump/zg.h
|
||||
@@ -122,10 +122,7 @@ do { \
|
||||
* Misc
|
||||
*/
|
||||
#define PAGE_SIZE 4096UL
|
||||
-#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
|
||||
-#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
|
||||
-#define ARRAY_ELEMENT_CNT(x) (sizeof(x) / sizeof(x[0]))
|
||||
#define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
|
||||
static inline u32 zg_csum_partial(const void *buf, int len, u32 sum)
|
||||
--- a/zipl/include/zipl.h
|
||||
+++ b/zipl/include/zipl.h
|
||||
@@ -62,10 +62,6 @@ typedef uint64_t address_t;
|
||||
* resulting return code or 0. */
|
||||
#define DRY_RUN_FUNC(x) (dry_run ? 0 : (x))
|
||||
|
||||
-#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
|
||||
-#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
-
|
||||
extern int verbose;
|
||||
extern int interactive;
|
||||
extern int dry_run;
|
@ -1,803 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] genprotimg: boot: initial bootloader support
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 3356d6f4facd748f8f5cf24ffc5056db3e915f2c
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
genprotimg: boot: initial bootloader support
|
||||
|
||||
Add a boot loader for protected virtualization (PV) that can be
|
||||
combined with a kernel/initrd/parmfile to form a single bootable file.
|
||||
This file must be constructed in a way that it can be used (1) for a
|
||||
QEMU direct kernel boot and (2) it can be zipl'ed by the normal,
|
||||
unmodified zipl program.
|
||||
|
||||
This new boot loader consists of two parts:
|
||||
|
||||
1. stage3a boot loader (cleartext), this loader is responsible for
|
||||
the transition into the protected mode by doing diag308 subcode 8
|
||||
and 10 calls.
|
||||
|
||||
2. stage3b boot loader (encrypted), this loader is very similar to the
|
||||
normal zipl stage3 boot loader. It will be loaded by the Ultravisor
|
||||
after the successful transition into protected mode. Like the zipl
|
||||
stage3 boot loader it moves the kernel and patches in the values
|
||||
for initrd and parmline.
|
||||
|
||||
The requirements for (1) and (2) result in the following constraints:
|
||||
|
||||
1. It must be possible to place stage3a and stage3b at a location >=
|
||||
0x10000 because the zipl stage3 loader zeroes out everything at
|
||||
addresses lower than 0x10000 of the image.
|
||||
|
||||
2. As the stage3 loader of zipl assumes that the passed kernel image
|
||||
looks like a normal kernel image, the zipl stage3 loader modifies the
|
||||
content at the memory area 0x10400 - 0x10800, therefore we leave this
|
||||
area unused in our stage3a loader.
|
||||
|
||||
3. The default entry address used by the zipl stage3 loader is 0x10000
|
||||
so we add a simple branch to 0x11000 at 0x10000 so the zipl stage3
|
||||
loader can modify the area 0x10400 - 0x10800 without affecting the
|
||||
stage3a loader.
|
||||
|
||||
The stage3b loader is linked at address 0x9000, therefore it will not
|
||||
work at another address. The relocation support for the stage3b
|
||||
loader, so that it can be placed at addresses != 0x9000, is added in
|
||||
the next patch. This loader with relocation support has the name
|
||||
'stage3b_reloc'.
|
||||
|
||||
The memory layout of the single bootable file looks like:
|
||||
|
||||
+-----------------------+-----------+------------------------+
|
||||
|Start |End |Use |
|
||||
+=======================+===========+========================+
|
||||
|0 |0x7 |Short PSW, starting |
|
||||
| | |instruction at 0x11000 |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|0x10000 |0x10012 |Branch to 0x11000 |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|0x10013 |0x10fff |Left intentionally |
|
||||
| | |unused |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|0x11000 |0x12fff |Stage3a |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|0x13000 |0x13fff |IPIB used as argument |
|
||||
| | |for the diag308 call |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|0x14000 |0x1[45]fff |UV header used for the |
|
||||
| | |diag308 call (size can |
|
||||
| | |be either 1 or 2 pages) |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|NEXT_PAGE_ALIGNED_ADDR | |Encrypted Kernel |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|NEXT_PAGE_ALIGNED_ADDR | |Encrypted Cmdline |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|NEXT_PAGE_ALIGNED_ADDR | |Encrypted Initrd |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|NEXT_PAGE_ALIGNED_ADDR | |Encrypted Stage3b_reloc |
|
||||
+-----------------------+-----------+------------------------+
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
genprotimg/boot/.gitignore | 3
|
||||
genprotimg/boot/Makefile | 83 +++++++++++++++++++++++++++
|
||||
genprotimg/boot/common_memory_layout.h | 25 ++++++++
|
||||
genprotimg/boot/head.S | 29 +++++++++
|
||||
genprotimg/boot/stage3a.c | 62 ++++++++++++++++++++
|
||||
genprotimg/boot/stage3a.h | 34 +++++++++++
|
||||
genprotimg/boot/stage3a.lds | 101 +++++++++++++++++++++++++++++++++
|
||||
genprotimg/boot/stage3a_init.S | 26 ++++++++
|
||||
genprotimg/boot/stage3b.c | 77 +++++++++++++++++++++++++
|
||||
genprotimg/boot/stage3b.h | 38 ++++++++++++
|
||||
genprotimg/boot/stage3b.lds | 87 ++++++++++++++++++++++++++++
|
||||
include/boot/ipl.h | 25 ++++++++
|
||||
include/boot/s390.h | 22 +++++--
|
||||
zipl/boot/error.h | 6 +
|
||||
14 files changed, 613 insertions(+), 5 deletions(-)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/.gitignore
|
||||
@@ -0,0 +1,3 @@
|
||||
+*.elf
|
||||
+*.bin
|
||||
+*.d
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/Makefile
|
||||
@@ -0,0 +1,83 @@
|
||||
+# Common definitions
|
||||
+include ../../common.mak
|
||||
+
|
||||
+ZIPL_DIR := $(rootdir)/zipl
|
||||
+ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot
|
||||
+
|
||||
+INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include
|
||||
+INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS))
|
||||
+
|
||||
+ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
|
||||
+ $(INCLUDE_PARMS) \
|
||||
+ -DENABLE_SCLP_ASCII=1 \
|
||||
+ -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||
+ -fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
|
||||
+ -fno-delete-null-pointer-checks \
|
||||
+ -fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||
+ -mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||
+ -Wall -Wformat-security -Wextra -Werror
|
||||
+
|
||||
+FILES := stage3a.bin stage3b.bin
|
||||
+
|
||||
+ZIPL_SRCS_C := libc.c ebcdic.c ebcdic_conv.c sclp.c
|
||||
+ZIPL_SRCS_ASM := entry.S
|
||||
+
|
||||
+ZIPL_OBJS_C := $(ZIPL_SRCS_C:%.c=%.o)
|
||||
+ZIPL_OBJS_ASM := $(ZIPL_SRCS_ASM:%.S=%.o)
|
||||
+ZIPL_OBJS := $(ZIPL_OBJS_C) $(ZIPL_OBJS_ASM)
|
||||
+
|
||||
+
|
||||
+all: $(FILES)
|
||||
+
|
||||
+# Prevent make from using some default rules...
|
||||
+%: %.S
|
||||
+
|
||||
+%.o: %.S Makefile
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
+
|
||||
+%.o: %.c Makefile
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
+
|
||||
+
|
||||
+# Special rules for zipl object files
|
||||
+$(ZIPL_OBJS_C): %.o : $(ZIPL_BOOT_DIR)/%.c
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
+
|
||||
+$(ZIPL_OBJS_ASM): %.o : $(ZIPL_BOOT_DIR)/%.S
|
||||
+ $(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
+
|
||||
+dependencies_zipl_c := $(ZIPL_SRCS_C:%.c=.%.o.d)
|
||||
+
|
||||
+$(dependencies_zipl_c): .%.o.d : $(ZIPL_BOOT_DIR)/%.c
|
||||
+ $(CC_SILENT) -MM $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< > $@
|
||||
+
|
||||
+ifneq ($(MAKECMDGOALS),clean)
|
||||
+-include $(dependencies_zipl_c)
|
||||
+endif
|
||||
+
|
||||
+
|
||||
+stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
||||
+stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
||||
+
|
||||
+%.elf: %.o
|
||||
+ case $* in \
|
||||
+ stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||
+ stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||
+ esac; \
|
||||
+ $(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||
+ @chmod a-x $@
|
||||
+
|
||||
+%.bin: %.elf
|
||||
+ $(OBJCOPY) -O binary \
|
||||
+ --only-section=.text* \
|
||||
+ --only-section=.ex_table* \
|
||||
+ --only-section=.fixup* \
|
||||
+ --only-section=.data* \
|
||||
+ --only-section=.rodata* \
|
||||
+ $< $@
|
||||
+ @chmod a-x $@
|
||||
+
|
||||
+clean:
|
||||
+ rm -f *.o *.elf *.bin *.map .*.d
|
||||
+
|
||||
+.PHONY: all clean
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/common_memory_layout.h
|
||||
@@ -0,0 +1,25 @@
|
||||
+/*
|
||||
+ * Common memory layout for stage3a and stage3b bootloader.
|
||||
+ *
|
||||
+ * 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 COMMON_MEMORY_LAYOUT_H
|
||||
+#define COMMON_MEMORY_LAYOUT_H
|
||||
+
|
||||
+#include "boot/loaders_layout.h"
|
||||
+
|
||||
+#define STACK_ADDRESS STAGE3_STACK_ADDRESS
|
||||
+#define STACK_SIZE STAGE3_STACK_SIZE
|
||||
+
|
||||
+#define HEAP_ADDRESS STAGE3_HEAP_ADDRESS
|
||||
+#define HEAP_SIZE STAGE3_HEAP_SIZE
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* COMMON_MEMORY_LAYOUT_H */
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/head.S
|
||||
@@ -0,0 +1,29 @@
|
||||
+/*
|
||||
+ * Entry code for stage 3a boot loader
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+
|
||||
+#include "common_memory_layout.h"
|
||||
+
|
||||
+#include "boot/s390.h"
|
||||
+#include "boot/sigp.h"
|
||||
+
|
||||
+.section .text.start
|
||||
+.globl _start
|
||||
+_start:
|
||||
+ /* Might be called after a diag308 so better set
|
||||
+ * architecture and addressing mode
|
||||
+ */
|
||||
+ lhi %r1, 1
|
||||
+ sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
+ sam64
|
||||
+
|
||||
+ /* Initialize stack */
|
||||
+ lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||
+ brasl %r14, initialize
|
||||
+.previous
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3a.c
|
||||
@@ -0,0 +1,62 @@
|
||||
+/*
|
||||
+ * Main program for stage3a bootloader
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include "libc.h"
|
||||
+#include "stage3a.h"
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+#include "boot/s390.h"
|
||||
+#include "boot/ipl.h"
|
||||
+#include "sclp.h"
|
||||
+#include "error.h"
|
||||
+
|
||||
+
|
||||
+static volatile struct stage3a_args __section(".loader_parms") loader_parms;
|
||||
+
|
||||
+void __noreturn start(void)
|
||||
+{
|
||||
+ int rc;
|
||||
+ volatile struct stage3a_args *args = &loader_parms;
|
||||
+ /* calculate the IPIB memory address */
|
||||
+ struct ipl_parameter_block *ipib = (void *)((uint64_t)args + args->ipib_offs);
|
||||
+
|
||||
+ /* Calculate the PV header memory address and set it and its
|
||||
+ * size in the IPIB. This allows the PV header to be position
|
||||
+ * independent.
|
||||
+ */
|
||||
+ ipib->pv.pv_hdr_addr = (uint64_t)args + args->hdr_offs;
|
||||
+ ipib->pv.pv_hdr_size = args->hdr_size;
|
||||
+
|
||||
+ /* set up ASCII and line-mode */
|
||||
+ sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
+
|
||||
+ /* test if Secure Execution Unpack facility is available */
|
||||
+ stfle(S390_lowcore.stfle_fac_list,
|
||||
+ ARRAY_SIZE(S390_lowcore.stfle_fac_list));
|
||||
+ rc = test_facility(UNPACK_FACILITY);
|
||||
+ if (rc == 0)
|
||||
+ panic(ENOPV, "Secure unpack facility is not available\n");
|
||||
+
|
||||
+ rc = diag308(DIAG308_SET_PV, ipib);
|
||||
+ if (rc != DIAG308_RC_OK)
|
||||
+ panic(EPV, "Protected boot setup has failed: 0x%x\n", rc);
|
||||
+
|
||||
+ rc = diag308(DIAG308_UNPACK_PV, 0x0);
|
||||
+ if (rc != DIAG308_RC_OK) {
|
||||
+ sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
+ panic(EPV, "Protected boot has failed: 0x%x\n", rc);
|
||||
+ }
|
||||
+
|
||||
+ while (1)
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+void panic_notify(unsigned long UNUSED(rc))
|
||||
+{
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3a.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+/*
|
||||
+ * Main program for stage3a bootloader.
|
||||
+ *
|
||||
+ * 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 STAGE3A_H
|
||||
+#define STAGE3A_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+#include "boot/loaders_layout.h"
|
||||
+
|
||||
+#define STAGE3A_INIT_ENTRY IMAGE_ENTRY
|
||||
+#define STAGE3A_ENTRY (STAGE3A_INIT_ENTRY + _AC(0x1000, UL))
|
||||
+#define STAGE3A_LOAD_ADDRESS IMAGE_LOAD_ADDRESS
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+/* Must not have any padding */
|
||||
+struct stage3a_args {
|
||||
+ uint64_t hdr_offs;
|
||||
+ uint64_t hdr_size;
|
||||
+ uint64_t ipib_offs;
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct stage3a_args) == 3 * 8)
|
||||
+
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* STAGE3A_H */
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3a.lds
|
||||
@@ -0,0 +1,101 @@
|
||||
+/*
|
||||
+ * Memory layout for stage 3a
|
||||
+ * ==========================
|
||||
+ *
|
||||
+ * General memory layout
|
||||
+ * ---------------------
|
||||
+ *
|
||||
+ * 0x00000 - 0x01fff Lowcore
|
||||
+ * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
+ * 0x0f000 - 0x0ffff Stack
|
||||
+ * 0x10000 - 0x10012 Jump to the "actual" stage3a code
|
||||
+ * 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the
|
||||
+ * actual data: IPIB and UV header)
|
||||
+ */
|
||||
+
|
||||
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
+OUTPUT_ARCH(s390:64-bit)
|
||||
+
|
||||
+ENTRY(_init)
|
||||
+
|
||||
+__heap_size__ = 0x4000;
|
||||
+__stack_size__ = 0x1000;
|
||||
+
|
||||
+SECTIONS
|
||||
+{
|
||||
+ . = 0x0;
|
||||
+
|
||||
+ . = 0x2000;
|
||||
+ __heap_start = .;
|
||||
+ .heap : {
|
||||
+ . = . + __heap_size__;
|
||||
+ ASSERT(__heap_stop - __heap_start == __heap_size__,
|
||||
+ "Heap section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __heap_stop = .;
|
||||
+
|
||||
+ . = 0xf000;
|
||||
+ __stack_start = .;
|
||||
+ .stack : {
|
||||
+ . = . + __stack_size__;
|
||||
+ ASSERT(__stack_end - __stack_start == __stack_size__,
|
||||
+ "Stack section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __stack_end = .;
|
||||
+
|
||||
+ . = 0x10000;
|
||||
+ __text_init_start = .;
|
||||
+ .text : {
|
||||
+ stage3a_init.o(.text.init)
|
||||
+ __text_init_stop = ABSOLUTE(.);
|
||||
+ /* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||
+ * otherwise the text data could be overwritten by the original zipl stage3
|
||||
+ * boot loader */
|
||||
+ ASSERT(__text_init_stop - __text_init_start < 0x400,
|
||||
+ "Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'");
|
||||
+ . = 0x1000;
|
||||
+ head.o(.text.start)
|
||||
+ *(.text)
|
||||
+ }
|
||||
+
|
||||
+ .ex_table ALIGN(16) : {
|
||||
+ __ex_table_start = .;
|
||||
+ *(.ex_table)
|
||||
+ __ex_table_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .bss ALIGN(16) : {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss)
|
||||
+ __bss_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .rodata ALIGN(16) : {
|
||||
+ *(.rodata)
|
||||
+ *(.rodata.*)
|
||||
+ }
|
||||
+
|
||||
+ .data ALIGN(16) : {
|
||||
+ *(.data)
|
||||
+ . = ALIGN(16);
|
||||
+ /* The IPIB offset and the UV header offset and size will be
|
||||
+ * saved in 'loader_parms' */
|
||||
+ __loader_parms_start = .;
|
||||
+ KEEP(*(.loader_parms));
|
||||
+ __loader_parms_stop = .;
|
||||
+ ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8,
|
||||
+ "Data size must be equal to 'sizeof(struct stage3a_args)'");
|
||||
+ ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+
|
||||
+ /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
+ * put at 0x0 */
|
||||
+ .notes : {
|
||||
+ *(.note.*)
|
||||
+ }
|
||||
+
|
||||
+ /* Sections to be discarded */
|
||||
+ /DISCARD/ : {
|
||||
+ *(.eh_frame)
|
||||
+ }
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3a_init.S
|
||||
@@ -0,0 +1,26 @@
|
||||
+/*
|
||||
+ * Entry code for stage 3a boot loader
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include "stage3a.h"
|
||||
+#include "boot/sigp.h"
|
||||
+
|
||||
+.section .text.init
|
||||
+.globl _init
|
||||
+_init:
|
||||
+ /* set architecture and switch to 64bit */
|
||||
+ lhi %r1, 1
|
||||
+ sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
+ sam64
|
||||
+ /* The original stage3 boot loader will try to store the
|
||||
+ * kernel command line and the address and size of the
|
||||
+ * ramdisk. Simply ignore this by starting at 0x11000.
|
||||
+ */
|
||||
+ lgfi %r1, STAGE3A_ENTRY
|
||||
+ br %r1
|
||||
+.previous
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3b.c
|
||||
@@ -0,0 +1,77 @@
|
||||
+/*
|
||||
+ * Main program for stage3b bootloader
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include "libc.h"
|
||||
+#include "stage3b.h"
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+#include "boot/s390.h"
|
||||
+#include "boot/linux_layout.h"
|
||||
+#include "boot/loaders_layout.h"
|
||||
+#include "sclp.h"
|
||||
+#include "error.h"
|
||||
+
|
||||
+
|
||||
+static volatile struct stage3b_args __section(".loader_parms") loader_parms;
|
||||
+
|
||||
+static inline void __noreturn load_psw(struct psw_t psw)
|
||||
+{
|
||||
+ asm volatile("lpswe %0" : : "Q"(psw) : "cc");
|
||||
+
|
||||
+ while (1)
|
||||
+ ;
|
||||
+}
|
||||
+
|
||||
+void __noreturn start(void)
|
||||
+{
|
||||
+ volatile struct stage3b_args *args = &loader_parms;
|
||||
+ volatile struct memblob *kernel = &args->kernel;
|
||||
+ volatile struct memblob *cmdline = &args->cmdline;
|
||||
+ volatile struct memblob *initrd = &args->initrd;
|
||||
+ volatile struct psw_t psw = args->psw;
|
||||
+
|
||||
+ /* set up ASCII and line-mode */
|
||||
+ sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
+
|
||||
+ if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||
+ panic(EINTERNAL, "Invalid kernel\n");
|
||||
+
|
||||
+ if (cmdline->size > COMMAND_LINE_SIZE)
|
||||
+ panic(EINTERNAL, "Command line is too large\n");
|
||||
+
|
||||
+ /* move the kernel and cut the kernel header */
|
||||
+ memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||
+ (void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||
+ kernel->size - IMAGE_LOAD_ADDRESS);
|
||||
+
|
||||
+ /* move the kernel cmdline */
|
||||
+ memmove((void *)COMMAND_LINE,
|
||||
+ (void *)cmdline->src,
|
||||
+ cmdline->size);
|
||||
+ /* the initrd does not need to be moved */
|
||||
+
|
||||
+ if (initrd->size != 0) {
|
||||
+ /* copy initrd start address and size into new kernel space */
|
||||
+ *(unsigned long long *)INITRD_START = initrd->src;
|
||||
+ *(unsigned long long *)INITRD_SIZE = initrd->size;
|
||||
+ }
|
||||
+
|
||||
+ /* disable ASCII and line-mode */
|
||||
+ sclp_setup(SCLP_DISABLE);
|
||||
+
|
||||
+ /* use lpswe instead of diag308 as a I/O subsystem reset is not
|
||||
+ * needed as this was already done by the diag308 subcode 10 call
|
||||
+ * in stage3a
|
||||
+ */
|
||||
+ load_psw(psw);
|
||||
+}
|
||||
+
|
||||
+void panic_notify(unsigned long UNUSED(rc))
|
||||
+{
|
||||
+}
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3b.h
|
||||
@@ -0,0 +1,38 @@
|
||||
+/*
|
||||
+ * Main program for stage3b bootloader
|
||||
+ *
|
||||
+ * 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 STAGE3B_H
|
||||
+#define STAGE3B_H
|
||||
+
|
||||
+#include "lib/zt_common.h"
|
||||
+
|
||||
+
|
||||
+#ifndef __ASSEMBLER__
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+#include "boot/s390.h"
|
||||
+
|
||||
+/* Must not have any padding included */
|
||||
+struct memblob {
|
||||
+ uint64_t src;
|
||||
+ uint64_t size;
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct memblob) == 2 * 8)
|
||||
+
|
||||
+/* Must not have any padding included */
|
||||
+struct stage3b_args {
|
||||
+ struct memblob kernel;
|
||||
+ struct memblob cmdline;
|
||||
+ struct memblob initrd;
|
||||
+ struct psw_t psw;
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct stage3b_args) == 3 * sizeof(struct memblob) + 16)
|
||||
+#endif /* __ASSEMBLER__ */
|
||||
+#endif /* STAGE3B_H */
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3b.lds
|
||||
@@ -0,0 +1,87 @@
|
||||
+/*
|
||||
+ * Memory layout for stage 3b
|
||||
+ * ==========================
|
||||
+ *
|
||||
+ * General memory layout
|
||||
+ * ---------------------
|
||||
+ *
|
||||
+ * 0x00000 - 0x01fff Lowcore
|
||||
+ * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
+ * 0x0a000 - 0x0efff Stage3b code
|
||||
+ * 0x0f000 - 0x0ffff Stack
|
||||
+ */
|
||||
+
|
||||
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
+OUTPUT_ARCH(s390:64-bit)
|
||||
+
|
||||
+ENTRY(_start)
|
||||
+
|
||||
+__heap_size__ = 0x4000;
|
||||
+__stack_size__ = 0x1000;
|
||||
+
|
||||
+SECTIONS
|
||||
+{
|
||||
+ . = 0x0;
|
||||
+
|
||||
+ . = 0x2000;
|
||||
+ __heap_start = .;
|
||||
+ .heap : {
|
||||
+ . = . + __heap_size__;
|
||||
+ ASSERT(__heap_stop - __heap_start == __heap_size__,
|
||||
+ "Heap section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __heap_stop = .;
|
||||
+
|
||||
+ . = 0xa000;
|
||||
+ .text : {
|
||||
+ head.o(.text.start)
|
||||
+ *(.text)
|
||||
+ }
|
||||
+
|
||||
+ .ex_table ALIGN(16) : {
|
||||
+ __ex_table_start = .;
|
||||
+ *(.ex_table)
|
||||
+ __ex_table_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .bss ALIGN(16) : {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss)
|
||||
+ __bss_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .rodata ALIGN(16) : {
|
||||
+ *(.rodata)
|
||||
+ *(.rodata.*)
|
||||
+ }
|
||||
+
|
||||
+ .data ALIGN(16) : {
|
||||
+ *(.data)
|
||||
+ . = ALIGN(16);
|
||||
+ __loader_parms_start = .;
|
||||
+ KEEP(*(.loader_parms));
|
||||
+ __loader_parms_end = .;
|
||||
+ ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16,
|
||||
+ "Data size must be equal to 'sizeof(struct stage3b_args)'");
|
||||
+ }
|
||||
+
|
||||
+ . = 0xf000;
|
||||
+ __stack_start = .;
|
||||
+ .stack : {
|
||||
+ . = . + __stack_size__;
|
||||
+ ASSERT(__stack_end - __stack_start == __stack_size__,
|
||||
+ "Stack section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __stack_end = .;
|
||||
+
|
||||
+ /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
+ * put at 0x0 */
|
||||
+ .notes : {
|
||||
+ *(.note.*)
|
||||
+ }
|
||||
+
|
||||
+ /* Sections to be discarded */
|
||||
+ /DISCARD/ : {
|
||||
+ *(.eh_frame)
|
||||
+ }
|
||||
+}
|
||||
--- a/include/boot/ipl.h
|
||||
+++ b/include/boot/ipl.h
|
||||
@@ -89,6 +89,30 @@ struct ipl_pb0_ccw {
|
||||
uint8_t reserved5[8];
|
||||
} __packed;
|
||||
|
||||
+/* Structure must not have any padding */
|
||||
+struct ipl_pb0_pv_comp {
|
||||
+ uint64_t tweak_pref;
|
||||
+ uint64_t addr;
|
||||
+ uint64_t len;
|
||||
+};
|
||||
+STATIC_ASSERT(sizeof(struct ipl_pb0_pv_comp) == 3 * 8)
|
||||
+
|
||||
+/* IPL Parameter Block 0 for PV */
|
||||
+struct ipl_pb0_pv {
|
||||
+ uint32_t len;
|
||||
+ uint8_t pbt;
|
||||
+ uint8_t reserved1[3];
|
||||
+ uint8_t loadparm[8];
|
||||
+ uint8_t reserved2[84];
|
||||
+ uint8_t reserved3[3];
|
||||
+ uint8_t version;
|
||||
+ uint8_t reserved4[4];
|
||||
+ uint32_t num_comp;
|
||||
+ uint64_t pv_hdr_addr;
|
||||
+ uint64_t pv_hdr_size;
|
||||
+ struct ipl_pb0_pv_comp components[];
|
||||
+} __packed;
|
||||
+
|
||||
struct ipl_parameter_block {
|
||||
struct ipl_pl_hdr hdr;
|
||||
union {
|
||||
@@ -96,6 +120,7 @@ struct ipl_parameter_block {
|
||||
struct ipl_pb0_common common;
|
||||
struct ipl_pb0_fcp fcp;
|
||||
struct ipl_pb0_ccw ccw;
|
||||
+ struct ipl_pb0_pv pv;
|
||||
char raw[PAGE_SIZE - sizeof(struct ipl_pl_hdr)];
|
||||
};
|
||||
} __packed __aligned(PAGE_SIZE);
|
||||
--- a/include/boot/s390.h
|
||||
+++ b/include/boot/s390.h
|
||||
@@ -18,6 +18,12 @@
|
||||
|
||||
#define PAGE_SIZE _AC(4096, UL)
|
||||
|
||||
+/* Minimum size of a stack frame in bytes */
|
||||
+#define STACK_FRAME_OVERHEAD _AC(160, U)
|
||||
+
|
||||
+/* Facilities */
|
||||
+#define UNPACK_FACILITY _AC(161, U)
|
||||
+
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
@@ -262,11 +268,17 @@ static __always_inline void __ctl_set_bi
|
||||
* DIAG 308 support
|
||||
*/
|
||||
enum diag308_subcode {
|
||||
- DIAG308_REL_HSA = 2,
|
||||
- DIAG308_IPL = 3,
|
||||
- DIAG308_DUMP = 4,
|
||||
- DIAG308_SET = 5,
|
||||
- DIAG308_STORE = 6,
|
||||
+ DIAG308_REL_HSA = 2,
|
||||
+ DIAG308_IPL = 3,
|
||||
+ DIAG308_DUMP = 4,
|
||||
+ DIAG308_SET = 5,
|
||||
+ DIAG308_STORE = 6,
|
||||
+ DIAG308_SET_PV = 8,
|
||||
+ DIAG308_UNPACK_PV = 10,
|
||||
+};
|
||||
+
|
||||
+enum diag308_rc {
|
||||
+ DIAG308_RC_OK = 0x0001,
|
||||
};
|
||||
|
||||
static __always_inline unsigned long diag308(unsigned long subcode, void *addr)
|
||||
--- a/zipl/boot/error.h
|
||||
+++ b/zipl/boot/error.h
|
||||
@@ -71,4 +71,10 @@
|
||||
#define ENOTIME 0x00004605 /* The zipl time stamps do not match */
|
||||
#define ENOMSS 0x00004606 /* Could not enable MSS */
|
||||
|
||||
+/*
|
||||
+ * PV error codes
|
||||
+ */
|
||||
+#define ENOPV 0x00004607 /* No support for PV */
|
||||
+#define EPV 0x00004608 /* PV error */
|
||||
+
|
||||
#endif /* ERROR_H */
|
@ -1,479 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] genprotimg: boot: use C pre-processor for linker script generation
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: 2d600570df98a1d26a6f3947ae8c39bcde00b464
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
genprotimg: boot: use C pre-processor for linker script generation
|
||||
|
||||
Use C pre-processor for linker script generation. This allows the
|
||||
usage of constants in our "linker scripts" `*.lds.S` (actually, these
|
||||
are assembler files, so we can make us of the C pre-processor and its
|
||||
capabilities).
|
||||
|
||||
Suggested-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
genprotimg/boot/.gitignore | 1
|
||||
genprotimg/boot/Makefile | 13 ++++-
|
||||
genprotimg/boot/stage3a.lds | 101 -----------------------------------------
|
||||
genprotimg/boot/stage3a.lds.S | 103 ++++++++++++++++++++++++++++++++++++++++++
|
||||
genprotimg/boot/stage3b.h | 4 +
|
||||
genprotimg/boot/stage3b.lds | 87 -----------------------------------
|
||||
genprotimg/boot/stage3b.lds.S | 87 +++++++++++++++++++++++++++++++++++
|
||||
7 files changed, 207 insertions(+), 189 deletions(-)
|
||||
|
||||
--- a/genprotimg/boot/.gitignore
|
||||
+++ b/genprotimg/boot/.gitignore
|
||||
@@ -1,3 +1,4 @@
|
||||
*.elf
|
||||
+*.lds
|
||||
*.bin
|
||||
*.d
|
||||
--- a/genprotimg/boot/Makefile
|
||||
+++ b/genprotimg/boot/Makefile
|
||||
@@ -39,6 +39,17 @@ all: $(FILES)
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
|
||||
+# Dependencies for the .lds generation
|
||||
+sources_lds_S = $(wildcard *.lds.S)
|
||||
+dependencies_lds_S = $(sources_lds_s:%.lds.S=.%.lds.d)
|
||||
+# Include all ".lds.d" dependency files for all make targets except for "clean"
|
||||
+ifneq ($(MAKECMDGOALS),clean)
|
||||
+-include $(dependencies_lds_S)
|
||||
+endif
|
||||
+
|
||||
+%.lds: %.lds.S Makefile
|
||||
+ $(CPP) -Wp,-MD,.$@.d,-MT,$@ $(INCLUDE_PARMS) -P -C -o $@ $<
|
||||
+
|
||||
# Special rules for zipl object files
|
||||
$(ZIPL_OBJS_C): %.o : $(ZIPL_BOOT_DIR)/%.c
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
@@ -78,6 +89,6 @@ stage3b.elf: head.o stage3b.o stage3b.ld
|
||||
@chmod a-x $@
|
||||
|
||||
clean:
|
||||
- rm -f *.o *.elf *.bin *.map .*.d
|
||||
+ rm -f *.o *.elf *.bin *.map .*.d *.lds
|
||||
|
||||
.PHONY: all clean
|
||||
--- a/genprotimg/boot/stage3a.lds
|
||||
+++ /dev/null
|
||||
@@ -1,101 +0,0 @@
|
||||
-/*
|
||||
- * Memory layout for stage 3a
|
||||
- * ==========================
|
||||
- *
|
||||
- * General memory layout
|
||||
- * ---------------------
|
||||
- *
|
||||
- * 0x00000 - 0x01fff Lowcore
|
||||
- * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
- * 0x0f000 - 0x0ffff Stack
|
||||
- * 0x10000 - 0x10012 Jump to the "actual" stage3a code
|
||||
- * 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the
|
||||
- * actual data: IPIB and UV header)
|
||||
- */
|
||||
-
|
||||
-OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
-OUTPUT_ARCH(s390:64-bit)
|
||||
-
|
||||
-ENTRY(_init)
|
||||
-
|
||||
-__heap_size__ = 0x4000;
|
||||
-__stack_size__ = 0x1000;
|
||||
-
|
||||
-SECTIONS
|
||||
-{
|
||||
- . = 0x0;
|
||||
-
|
||||
- . = 0x2000;
|
||||
- __heap_start = .;
|
||||
- .heap : {
|
||||
- . = . + __heap_size__;
|
||||
- ASSERT(__heap_stop - __heap_start == __heap_size__,
|
||||
- "Heap section doesn't conform to the described memory layout");
|
||||
- }
|
||||
- __heap_stop = .;
|
||||
-
|
||||
- . = 0xf000;
|
||||
- __stack_start = .;
|
||||
- .stack : {
|
||||
- . = . + __stack_size__;
|
||||
- ASSERT(__stack_end - __stack_start == __stack_size__,
|
||||
- "Stack section doesn't conform to the described memory layout");
|
||||
- }
|
||||
- __stack_end = .;
|
||||
-
|
||||
- . = 0x10000;
|
||||
- __text_init_start = .;
|
||||
- .text : {
|
||||
- stage3a_init.o(.text.init)
|
||||
- __text_init_stop = ABSOLUTE(.);
|
||||
- /* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||
- * otherwise the text data could be overwritten by the original zipl stage3
|
||||
- * boot loader */
|
||||
- ASSERT(__text_init_stop - __text_init_start < 0x400,
|
||||
- "Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'");
|
||||
- . = 0x1000;
|
||||
- head.o(.text.start)
|
||||
- *(.text)
|
||||
- }
|
||||
-
|
||||
- .ex_table ALIGN(16) : {
|
||||
- __ex_table_start = .;
|
||||
- *(.ex_table)
|
||||
- __ex_table_stop = .;
|
||||
- }
|
||||
-
|
||||
- .bss ALIGN(16) : {
|
||||
- __bss_start = .;
|
||||
- *(.bss)
|
||||
- __bss_stop = .;
|
||||
- }
|
||||
-
|
||||
- .rodata ALIGN(16) : {
|
||||
- *(.rodata)
|
||||
- *(.rodata.*)
|
||||
- }
|
||||
-
|
||||
- .data ALIGN(16) : {
|
||||
- *(.data)
|
||||
- . = ALIGN(16);
|
||||
- /* The IPIB offset and the UV header offset and size will be
|
||||
- * saved in 'loader_parms' */
|
||||
- __loader_parms_start = .;
|
||||
- KEEP(*(.loader_parms));
|
||||
- __loader_parms_stop = .;
|
||||
- ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8,
|
||||
- "Data size must be equal to 'sizeof(struct stage3a_args)'");
|
||||
- ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||
- }
|
||||
-
|
||||
- /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
- * put at 0x0 */
|
||||
- .notes : {
|
||||
- *(.note.*)
|
||||
- }
|
||||
-
|
||||
- /* Sections to be discarded */
|
||||
- /DISCARD/ : {
|
||||
- *(.eh_frame)
|
||||
- }
|
||||
-}
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3a.lds.S
|
||||
@@ -0,0 +1,103 @@
|
||||
+/*
|
||||
+ * Memory layout for stage 3a
|
||||
+ * ==========================
|
||||
+ *
|
||||
+ * General memory layout
|
||||
+ * ---------------------
|
||||
+ *
|
||||
+ * 0x00000 - 0x01fff Lowcore
|
||||
+ * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
+ * 0x0f000 - 0x0ffff Stack
|
||||
+ * 0x10000 - 0x10012 Jump to the "actual" stage3a code
|
||||
+ * 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the
|
||||
+ * actual data: IPIB and UV header)
|
||||
+ */
|
||||
+
|
||||
+#include "stage3a.h"
|
||||
+#include "common_memory_layout.h"
|
||||
+
|
||||
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
+OUTPUT_ARCH(s390:64-bit)
|
||||
+
|
||||
+ENTRY(_init)
|
||||
+
|
||||
+SECTIONS
|
||||
+{
|
||||
+ . = 0x0;
|
||||
+
|
||||
+ . = HEAP_ADDRESS;
|
||||
+ __heap_start = .;
|
||||
+ .heap : {
|
||||
+ . = . + HEAP_SIZE;
|
||||
+ ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||
+ "Heap section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __heap_stop = .;
|
||||
+
|
||||
+ . = STACK_ADDRESS;
|
||||
+ __stack_start = .;
|
||||
+ .stack : {
|
||||
+ . = . + STACK_SIZE;
|
||||
+ ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||
+ "Stack section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __stack_end = .;
|
||||
+
|
||||
+ . = STAGE3A_INIT_ENTRY;
|
||||
+ __text_init_start = .;
|
||||
+ .text : {
|
||||
+ stage3a_init.o(.text.init)
|
||||
+ __text_init_stop = ABSOLUTE(.);
|
||||
+ /* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||
+ * otherwise the text data could be overwritten by the original zipl stage3
|
||||
+ * boot loader */
|
||||
+ ASSERT(__text_init_stop - __text_init_start < PARMAREA - IMAGE_ENTRY,
|
||||
+ "Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'");
|
||||
+ . = 0x1000;
|
||||
+ ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
||||
+ "Text section doesn't conform to the described memory layout");
|
||||
+ head.o(.text.start)
|
||||
+ *(.text)
|
||||
+ }
|
||||
+
|
||||
+ .ex_table ALIGN(16) : {
|
||||
+ __ex_table_start = .;
|
||||
+ *(.ex_table)
|
||||
+ __ex_table_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .bss ALIGN(16) : {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss)
|
||||
+ __bss_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .rodata ALIGN(16) : {
|
||||
+ *(.rodata)
|
||||
+ *(.rodata.*)
|
||||
+ }
|
||||
+
|
||||
+ .data ALIGN(16) : {
|
||||
+ *(.data)
|
||||
+ . = ALIGN(16);
|
||||
+ /* The IPIB offset and the UV header offset and size will be
|
||||
+ * saved in 'loader_parms' */
|
||||
+ __loader_parms_start = .;
|
||||
+ KEEP(*(.loader_parms));
|
||||
+ __loader_parms_stop = .;
|
||||
+ ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8,
|
||||
+ "Data size must be equal to 'sizeof(struct stage3a_args)'");
|
||||
+ ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+
|
||||
+ /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
+ * put at 0x0 */
|
||||
+ .notes : {
|
||||
+ *(.note.*)
|
||||
+ }
|
||||
+
|
||||
+ /* Sections to be discarded */
|
||||
+ /DISCARD/ : {
|
||||
+ *(.eh_frame)
|
||||
+ }
|
||||
+}
|
||||
--- a/genprotimg/boot/stage3b.h
|
||||
+++ b/genprotimg/boot/stage3b.h
|
||||
@@ -11,6 +11,10 @@
|
||||
#define STAGE3B_H
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
+#include "boot/loaders_layout.h"
|
||||
+
|
||||
+#define STAGE3B_ENTRY STAGE3_ENTRY
|
||||
+#define STAGE3B_LOAD_ADDRESS STAGE3B_ENTRY
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
--- a/genprotimg/boot/stage3b.lds
|
||||
+++ /dev/null
|
||||
@@ -1,87 +0,0 @@
|
||||
-/*
|
||||
- * Memory layout for stage 3b
|
||||
- * ==========================
|
||||
- *
|
||||
- * General memory layout
|
||||
- * ---------------------
|
||||
- *
|
||||
- * 0x00000 - 0x01fff Lowcore
|
||||
- * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
- * 0x0a000 - 0x0efff Stage3b code
|
||||
- * 0x0f000 - 0x0ffff Stack
|
||||
- */
|
||||
-
|
||||
-OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
-OUTPUT_ARCH(s390:64-bit)
|
||||
-
|
||||
-ENTRY(_start)
|
||||
-
|
||||
-__heap_size__ = 0x4000;
|
||||
-__stack_size__ = 0x1000;
|
||||
-
|
||||
-SECTIONS
|
||||
-{
|
||||
- . = 0x0;
|
||||
-
|
||||
- . = 0x2000;
|
||||
- __heap_start = .;
|
||||
- .heap : {
|
||||
- . = . + __heap_size__;
|
||||
- ASSERT(__heap_stop - __heap_start == __heap_size__,
|
||||
- "Heap section doesn't conform to the described memory layout");
|
||||
- }
|
||||
- __heap_stop = .;
|
||||
-
|
||||
- . = 0xa000;
|
||||
- .text : {
|
||||
- head.o(.text.start)
|
||||
- *(.text)
|
||||
- }
|
||||
-
|
||||
- .ex_table ALIGN(16) : {
|
||||
- __ex_table_start = .;
|
||||
- *(.ex_table)
|
||||
- __ex_table_stop = .;
|
||||
- }
|
||||
-
|
||||
- .bss ALIGN(16) : {
|
||||
- __bss_start = .;
|
||||
- *(.bss)
|
||||
- __bss_stop = .;
|
||||
- }
|
||||
-
|
||||
- .rodata ALIGN(16) : {
|
||||
- *(.rodata)
|
||||
- *(.rodata.*)
|
||||
- }
|
||||
-
|
||||
- .data ALIGN(16) : {
|
||||
- *(.data)
|
||||
- . = ALIGN(16);
|
||||
- __loader_parms_start = .;
|
||||
- KEEP(*(.loader_parms));
|
||||
- __loader_parms_end = .;
|
||||
- ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16,
|
||||
- "Data size must be equal to 'sizeof(struct stage3b_args)'");
|
||||
- }
|
||||
-
|
||||
- . = 0xf000;
|
||||
- __stack_start = .;
|
||||
- .stack : {
|
||||
- . = . + __stack_size__;
|
||||
- ASSERT(__stack_end - __stack_start == __stack_size__,
|
||||
- "Stack section doesn't conform to the described memory layout");
|
||||
- }
|
||||
- __stack_end = .;
|
||||
-
|
||||
- /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
- * put at 0x0 */
|
||||
- .notes : {
|
||||
- *(.note.*)
|
||||
- }
|
||||
-
|
||||
- /* Sections to be discarded */
|
||||
- /DISCARD/ : {
|
||||
- *(.eh_frame)
|
||||
- }
|
||||
-}
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3b.lds.S
|
||||
@@ -0,0 +1,87 @@
|
||||
+/*
|
||||
+ * Memory layout for stage 3b
|
||||
+ * ==========================
|
||||
+ *
|
||||
+ * General memory layout
|
||||
+ * ---------------------
|
||||
+ *
|
||||
+ * 0x00000 - 0x01fff Lowcore
|
||||
+ * 0x02000 - 0x05fff Memory allocation (heap)
|
||||
+ * 0x0a000 - 0x0efff Stage3b code
|
||||
+ * 0x0f000 - 0x0ffff Stack
|
||||
+ */
|
||||
+
|
||||
+#include "stage3b.h"
|
||||
+#include "common_memory_layout.h"
|
||||
+
|
||||
+OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
+OUTPUT_ARCH(s390:64-bit)
|
||||
+
|
||||
+ENTRY(_start)
|
||||
+
|
||||
+SECTIONS
|
||||
+{
|
||||
+ . = 0x0;
|
||||
+
|
||||
+ . = HEAP_ADDRESS;
|
||||
+ __heap_start = .;
|
||||
+ .heap : {
|
||||
+ . = . + HEAP_SIZE;
|
||||
+ ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||
+ "Heap section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __heap_stop = .;
|
||||
+
|
||||
+ . = STAGE3B_ENTRY;
|
||||
+ .text : {
|
||||
+ head.o(.text.start)
|
||||
+ *(.text)
|
||||
+ }
|
||||
+
|
||||
+ .ex_table ALIGN(16) : {
|
||||
+ __ex_table_start = .;
|
||||
+ *(.ex_table)
|
||||
+ __ex_table_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .bss ALIGN(16) : {
|
||||
+ __bss_start = .;
|
||||
+ *(.bss)
|
||||
+ __bss_stop = .;
|
||||
+ }
|
||||
+
|
||||
+ .rodata ALIGN(16) : {
|
||||
+ *(.rodata)
|
||||
+ *(.rodata.*)
|
||||
+ }
|
||||
+
|
||||
+ .data ALIGN(16) : {
|
||||
+ *(.data)
|
||||
+ . = ALIGN(16);
|
||||
+ __loader_parms_start = .;
|
||||
+ KEEP(*(.loader_parms));
|
||||
+ __loader_parms_end = .;
|
||||
+ ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16,
|
||||
+ "Data size must be equal to 'sizeof(struct stage3b_args)'");
|
||||
+ }
|
||||
+
|
||||
+ . = STACK_ADDRESS;
|
||||
+ __stack_start = .;
|
||||
+ .stack : {
|
||||
+ . = . + STACK_SIZE;
|
||||
+ ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||
+ "Stack section doesn't conform to the described memory layout");
|
||||
+ }
|
||||
+ __stack_end = .;
|
||||
+
|
||||
+ /* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
+ * put at 0x0 */
|
||||
+ .notes : {
|
||||
+ *(.note.*)
|
||||
+ }
|
||||
+
|
||||
+ /* Sections to be discarded */
|
||||
+ /DISCARD/ : {
|
||||
+ *(.eh_frame)
|
||||
+ }
|
||||
+}
|
@ -1,120 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] genprotimg: add relocator for stage3b
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: d2f8f972cff7aacbef8e72577af70dbf59ba3ead
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
genprotimg: add relocator for stage3b
|
||||
|
||||
Add support for the placement of the stage3b loader at other addresses
|
||||
than 0xa000. For this add a position independent relocator that first
|
||||
copies the original stage3b code to the memory location 0xa000 and
|
||||
then starts it.
|
||||
|
||||
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
genprotimg/boot/Makefile | 5 +++
|
||||
genprotimg/boot/stage3b_reloc.S | 53 ++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 57 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/genprotimg/boot/Makefile
|
||||
+++ b/genprotimg/boot/Makefile
|
||||
@@ -17,7 +17,7 @@ ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
|
||||
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||
-Wall -Wformat-security -Wextra -Werror
|
||||
|
||||
-FILES := stage3a.bin stage3b.bin
|
||||
+FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
|
||||
|
||||
ZIPL_SRCS_C := libc.c ebcdic.c ebcdic_conv.c sclp.c
|
||||
ZIPL_SRCS_ASM := entry.S
|
||||
@@ -66,14 +66,17 @@ ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(dependencies_zipl_c)
|
||||
endif
|
||||
|
||||
+stage3b_reloc.o: stage3b.bin
|
||||
|
||||
stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
||||
stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
||||
+stage3b_reloc.elf:
|
||||
|
||||
%.elf: %.o
|
||||
case $* in \
|
||||
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||
+ stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||
esac; \
|
||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||
@chmod a-x $@
|
||||
--- /dev/null
|
||||
+++ b/genprotimg/boot/stage3b_reloc.S
|
||||
@@ -0,0 +1,53 @@
|
||||
+/*
|
||||
+ * Relocator code for stage 3b boot loader
|
||||
+ *
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include "stage3b.h"
|
||||
+#include "boot/sigp.h"
|
||||
+
|
||||
+.macro MEMCPY dst,src,len
|
||||
+ lgr %r0, \dst
|
||||
+ lgr %r1, \len
|
||||
+ lgr %r2, \src
|
||||
+ lgr %r3, \len
|
||||
+
|
||||
+20: mvcle %r0, %r2, 0
|
||||
+ jo 20b
|
||||
+.endm
|
||||
+
|
||||
+.org 0x0
|
||||
+.section .text.start
|
||||
+.globl stage3b_reloc_start
|
||||
+stage3b_reloc_start:
|
||||
+ /* Might be called after a diag308 so better set
|
||||
+ * architecture and addressing mode
|
||||
+ */
|
||||
+ lhi %r1, 1
|
||||
+ sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
+ sam64
|
||||
+
|
||||
+.copy_stage3b:
|
||||
+ /* Location of stage3b in memory */
|
||||
+ larl %r8, stage3b_start
|
||||
+
|
||||
+ /* Destination for stage3b */
|
||||
+ lgfi %r9, STAGE3B_LOAD_ADDRESS
|
||||
+
|
||||
+ /* Size of stage3b */
|
||||
+ lghi %r11, stage3b_end - stage3b_start
|
||||
+
|
||||
+ /* Copy the stage3b loader to address STAGE3B_LOAD_ADDRESS */
|
||||
+ MEMCPY %r9, %r8, %r11
|
||||
+
|
||||
+ /* Branch to STAGE3B_ENTRY */
|
||||
+ lgfi %r9, STAGE3B_ENTRY
|
||||
+ br %r9
|
||||
+stage3b_start:
|
||||
+ .incbin "stage3b.bin"
|
||||
+stage3b_end:
|
||||
+.previous
|
@ -1,38 +0,0 @@
|
||||
Subject: [PATCH] [FEAT VS1804] README.md: remove useless empty line
|
||||
From: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
|
||||
Summary: genprotimg: Introduce new tool for the creation of PV images
|
||||
Description: genprotimg takes a kernel, host-key documents, optionally an
|
||||
initrd, optionally a file with the kernel command line, and it
|
||||
generates a single, loadable image file. The image consists of a
|
||||
concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, and cmdline, and the
|
||||
integrity-protected PV header, containing metadata necessary for
|
||||
running the guest in PV mode. It's possible to use this image file
|
||||
as a kernel for zIPL or for a direct kernel boot using QEMU.
|
||||
Upstream-ID: b06af6026f08d67339a109ba7457373ab82d3248
|
||||
Problem-ID: VS1804
|
||||
|
||||
Upstream-Description:
|
||||
|
||||
README.md: remove useless empty line
|
||||
|
||||
Remove useless empty line.
|
||||
|
||||
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
||||
|
||||
|
||||
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
|
||||
---
|
||||
README.md | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -1,4 +1,3 @@
|
||||
-
|
||||
s390-tools
|
||||
==========
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user