diff --git a/cputype b/cputype index 2fbdecc..50abf92 100644 --- a/cputype +++ b/cputype @@ -2,7 +2,7 @@ # # cputype # -# Copyright (c) 2014-2017 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2014-2017, 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # Based on the IBM machine model, returns a (hopefully) human understandable # string that identifies the processor. @@ -59,6 +59,8 @@ case "${machine}" in 2964) echo "${machine} = z13 IBM z13" ;; 2965) echo "${machine} = z13s IBM z13s (single frame)" ;; 3906) echo "${machine} = z14 IBM z14" ;; + 3907) echo "${machine} = z14 ZR1 IBM z14 ZR1" ;; + 8561) echo "${machine} = z15 IBM z15" ;; *) echo "An unknown machine type was reported: ${machine}" >&2 echo "Please file a bug report with this output:" >&2 /bin/cat /proc/cpuinfo >&2 diff --git a/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch b/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch index cca095d..6dd0d83 100644 --- a/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch +++ b/dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch @@ -23,16 +23,16 @@ diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index e1877ac..f03cbad 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c -@@ -588,7 +616,7 @@ +@@ -580,7 +580,7 @@ */ static void check_disk(dasdfmt_info_t *info, char *devname) { -- int ro, errno_save; -+ int ro, errno_save, i = 0; +- int err; ++ int err, index = 0 ; + bool ro; - if (ioctl(filedes, BLKROGET, &ro) != 0) { - errno_save = errno; -@@ -602,9 +630,27 @@ + err = dasd_is_ro(devname, &ro); +@@ -593,9 +593,27 @@ if (ro) ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n"); @@ -47,9 +47,9 @@ index e1877ac..f03cbad 100644 + * And confusing the hell out ouf anyone else. + * Bah. + */ -+ for ( i = 0 ; i < 6 ; i++ ) { ++ for ( index = 0 ; index < 6 ; index++ ) { + if (info->dasd_info.open_count > 1) { -+ get_device_info(info); ++ dasd_get_info(dev_filename, &info->dasd_info); + sleep(1); + } + else break; diff --git a/read_values.c b/read_values.c index ca4fadc..db2519b 100644 --- a/read_values.c +++ b/read_values.c @@ -1,6 +1,6 @@ /********************************************************************************/ /* */ -/* Copyright (C) 2014-2015, SUSE LLC */ +/* Copyright (C) 2014-2015, 2019 SUSE LLC */ /* */ /* All rights reserved. @@ -63,6 +63,10 @@ struct machinetype { { "2827", "2827 = z12-EC IBM zEnterprise EC12" }, { "2828", "2828 = z12-BC IBM zEnterprise BC12" }, { "2964", "2964 = z13 IBM z13" }, + { "2965", "2965 = z13s IBM z13s (single frame)" }, + { "3906", "3906 = z14 IBM z14" }, + { "3907", "3907 = z14 ZR1 IBM z14 ZR1" }, + { "8561", "8561 = z15 IBM z15" }, }; int debug = 0; diff --git a/s390-tools-2.1.0.tar.gz b/s390-tools-2.1.0.tar.gz deleted file mode 100644 index aada5a0..0000000 --- a/s390-tools-2.1.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b5ce3fa0de074dfe7d16c74771fcb5092c4a6f575168bf4e13f88275a6370122 -size 1046910 diff --git a/s390-tools-2.11.0.tar.gz b/s390-tools-2.11.0.tar.gz new file mode 100644 index 0000000..60048ed --- /dev/null +++ b/s390-tools-2.11.0.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fd1883e12f9da16be6b081508108abd3ce8cd80168efe4cd339ba33837f8f4aa +size 1164539 diff --git a/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch b/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch index 60237ca..efc8d40 100644 --- a/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch +++ b/s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch @@ -19,19 +19,17 @@ diff --git a/fdasd/fdasd.c b/fdasd/fdasd.c index 4503d3e..f04dc3d 100644 --- a/fdasd/fdasd.c +++ b/fdasd/fdasd.c -@@ -1247,9 +1247,12 @@ - } +@@ -1229,10 +1229,12 @@ + */ + static void fdasd_reread_partition_table(fdasd_anchor_t *anc) + { ++ int rc = 0 ; + if (!anc->silent) + printf("rereading partition table...\n"); - if (ioctl(fd, BLKRRPART, NULL) != 0) { -- close(fd); -- fdasd_error(anc, unable_to_ioctl, "Error while rereading " -- "partition table.\nPlease reboot!"); -+ if (errno == EINVAL && !anc->force_virtual) { -+ close(fd); -+ fdasd_error(anc, unable_to_ioctl, -+ "Error while rereading " -+ "partition table.\nPlease reboot!"); -+ } +- if (dasd_reread_partition_table(options.device, 1) != 0) { ++ rc = dasd_reread_partition_table(options.device, 1); ++ if (rc == EINVAL && !anc->force_virtual) { + fdasd_error(anc, unable_to_ioctl, "Error while rereading " + "partition table.\nPlease reboot!"); } - close(fd); - } diff --git a/s390-tools-sles15-1-lstape-fix-output-with-SCSI-lin_tape-and-multiple-pa.patch b/s390-tools-sles15-1-lstape-fix-output-with-SCSI-lin_tape-and-multiple-pa.patch deleted file mode 100644 index 94f7e95..0000000 --- a/s390-tools-sles15-1-lstape-fix-output-with-SCSI-lin_tape-and-multiple-pa.patch +++ /dev/null @@ -1,181 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape | 11 ++++------- - zconf/lstape.8 | 7 ++----- - 2 files changed, 6 insertions(+), 12 deletions(-) - ---- a/zconf/lstape -+++ b/zconf/lstape -@@ -2,7 +2,7 @@ - # - # lstape - Tool to show information about tape devices - # --# Copyright IBM Corp. 2003, 2017 -+# Copyright IBM Corp. 2003, 2018 - # - # s390-tools is free software; you can redistribute it and/or modify - # it under the terms of the MIT license. See LICENSE for details. -@@ -55,7 +55,7 @@ function PrintVersion() - { - cat <<-EOD - $CMD: version %S390_TOOLS_VERSION% -- Copyright IBM Corp. 2003, 2017 -+ Copyright IBM Corp. 2003, 2018 - EOD - } - -@@ -292,16 +292,13 @@ function SysfsCreateListSCSI() - TAPE_DEV=$CHG_IDX - fi - elif [ -r /proc/scsi/$DEV_NAME ]; then -- if [ "$TAPE_SERIAL" != "NO/INQ" ]; then - IBM_IDX=$( -- awk '$3 == "'$TAPE_SERIAL'"{ -- print $1 -- }' /proc/scsi/$DEV_NAME -+ grep -wF "$SCSI_ID" /proc/scsi/$DEV_NAME | -+ cut -d ' ' -f 1 - ) - if [ "$IBM_IDX" != "" ]; then - TAPE_DEV=$DEV_NAME$IBM_IDX - fi -- fi - fi - - printf "$SCSIFORMAT" \ ---- a/zconf/lstape.8 -+++ b/zconf/lstape.8 -@@ -1,8 +1,8 @@ --.\" Copyright 2017 IBM Corp. -+.\" Copyright 2017, 2018 IBM Corp. - .\" s390-tools is free software; you can redistribute it and/or modify - .\" it under the terms of the MIT license. See LICENSE for details. - .\" --.TH LSTAPE 8 "Jul 2007" "s390-tools" -+.TH LSTAPE 8 "Jun 2018" "s390-tools" - - .SH NAME - lstape \- list tape devices. -@@ -34,9 +34,6 @@ lstape command tries to find out which o - and changer driver the device names start with "st" or "sch", while for the - IBM tape driver this would be "IBMtape" or "IBMchanger". If "N/A" is shown, - the correct driver could not be obtained. --This happens for example if there is no sg_inq command installed which is --required to read the drive's serial number which in turn is used to find out --the device number of the IBM tape driver. - - The serial number of a SCSI tape can be displayed with the --verbose option. If - there is no sg_inq command available "NO/INQ" is shown as the tape's serial. diff --git a/s390-tools-sles15-2-lstape-fix-to-prefer-sysfs-to-find-lin_tape-device-n.patch b/s390-tools-sles15-2-lstape-fix-to-prefer-sysfs-to-find-lin_tape-device-n.patch deleted file mode 100644 index 0f24a1b..0000000 --- a/s390-tools-sles15-2-lstape-fix-to-prefer-sysfs-to-find-lin_tape-device-n.patch +++ /dev/null @@ -1,144 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape | 17 +++++++++++++++++ - 1 file changed, 17 insertions(+) - ---- a/zconf/lstape -+++ b/zconf/lstape -@@ -291,6 +291,23 @@ function SysfsCreateListSCSI() - if [ "$CHG_IDX" != "" ]; then - TAPE_DEV=$CHG_IDX - fi -+ elif [ "$(echo "$SCSI_LIST"|grep lin_tape)" != "" ]; then -+ # bash glob sorts so IBMtape0 comes before IBMtape0n -+ local IBM_PATH=$( -+ ls -1d $SCSI_DEV/lin_tape/$DEV_NAME[0-9]* | -+ head -n 1) -+ if [ -d "$IBM_PATH" ]; then -+ IBM_IDX=${IBM_PATH##*/} -+ else -+ # deprecated sysfs layout -+ IBM_IDX=$( -+ echo "$SCSI_LIST" | -+ awk -F: '/lin_tape\:'"$DEV_NAME"'[0-9]+$/{print $NF}' -+ ) -+ fi -+ if [ "$IBM_IDX" != "" ]; then -+ TAPE_DEV=$IBM_IDX -+ fi - elif [ -r /proc/scsi/$DEV_NAME ]; then - IBM_IDX=$( - grep -wF "$SCSI_ID" /proc/scsi/$DEV_NAME | diff --git a/s390-tools-sles15-3-lstape-fix-output-without-SCSI-generic-sg.patch b/s390-tools-sles15-3-lstape-fix-output-without-SCSI-generic-sg.patch deleted file mode 100644 index c609666..0000000 --- a/s390-tools-sles15-3-lstape-fix-output-without-SCSI-generic-sg.patch +++ /dev/null @@ -1,167 +0,0 @@ -Subject: [PATCH] [BZ 170633] lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape | 12 ++++++++++-- - zconf/lstape.8 | 8 +++++++- - 2 files changed, 17 insertions(+), 3 deletions(-) - ---- a/zconf/lstape -+++ b/zconf/lstape -@@ -48,6 +48,9 @@ function PrintUsage() { - : -v|--version - : Display the version of the tools package and - : the lstape command. -+ : -+ :$(basename $0) without the --ccw-only option causes extra SAN traffic -+ :for each SCSI tape or changer device by invoking the sg_inq command. - EOD - } - -@@ -249,11 +252,16 @@ function SysfsCreateListSCSI() - if [ -h $SG_DEV ]; then - # deprecated sysfs layout - SG_DEV=$(echo $SG_DEV | awk -F: '{print $NF}') -- else -+ elif [ -d $SCSI_DEV/scsi_generic ]; then - SG_DEV=$(basename $SG_DEV/*) -+ else -+ SG_DEV="" - fi - -- if [ "$SG_INQ" != "" ]; then -+ if [ -z "$SG_DEV" ]; then -+ SG_DEV="N/A" -+ TAPE_SERIAL="NO/SG" -+ elif [ "$SG_INQ" != "" ]; then - TAPE_SERIAL=$( - sg_inq /dev/$SG_DEV | - awk '/serial/{print $NF}' ---- a/zconf/lstape.8 -+++ b/zconf/lstape.8 -@@ -36,7 +36,13 @@ IBM tape driver this would be "IBMtape" - the correct driver could not be obtained. - - The serial number of a SCSI tape can be displayed with the --verbose option. If --there is no sg_inq command available "NO/INQ" is shown as the tape's serial. -+there is no sg_inq command available "NO/INQ" is shown as the serial number -+of the tape. -+If no SCSI generic (sg) kernel support is available, "NO/SG" is shown -+as the serial number of the tape and "N/A" for the "Generic" column. -+ -+The lstape command without the --ccw-only option causes extra SAN traffic -+for each SCSI tape or changer device by invoking the sg_inq command. - - .SH OPTIONS - .TP 8 diff --git a/s390-tools-sles15-4-lsluns-fix-to-prevent-error-messages-if-there-are-no.patch b/s390-tools-sles15-4-lsluns-fix-to-prevent-error-messages-if-there-are-no.patch deleted file mode 100644 index a4f7a1d..0000000 --- a/s390-tools-sles15-4-lsluns-fix-to-prevent-error-messages-if-there-are-no.patch +++ /dev/null @@ -1,177 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lsluns | 14 +++++++++----- - zconf/lsluns.8 | 5 ++--- - 2 files changed, 11 insertions(+), 8 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -2,7 +2,7 @@ - # - # lsluns - list LUNs discovered in the FC SAN, or show encryption state of attached LUNs - # --# Copyright IBM Corp. 2008, 2017 -+# Copyright IBM Corp. 2008, 2018 - # - # s390-tools is free software; you can redistribute it and/or modify - # it under the terms of the MIT license. See LICENSE for details. -@@ -152,6 +152,11 @@ sub get_lun_hash - my %lun_hash; - - foreach my $device () { -+ # skip non-zfcp SCSI devices and avoid file access error messages -+ next unless -r "$device/device/fcp_lun"; -+ next unless -r "$device/device/wwpn"; -+ next unless -r "$device/device/hba_id"; -+ - my $l = `cat $device/device/fcp_lun`; - my $p = `cat $device/device/wwpn`; - my $a = `cat $device/device/hba_id`; -@@ -170,9 +175,8 @@ sub get_lun_hash - sub lsluns_usage { - print <] ... [-p ] ... [-h] [-v] - -@@ -220,7 +224,7 @@ EOD - - sub lsluns_version { - print "$PROGRAM_NAME: version %S390_TOOLS_VERSION%\n"; -- print "Copyright IBM Corp. 2008, 2017\n"; -+ print "Copyright IBM Corp. 2008, 2018\n"; - } - - sub lsluns_invalid_usage { ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -28,9 +28,8 @@ zfcp-attached LUNs - - .SH DESCRIPTION - .PP --This tool is designed for environments where all SCSI devices are attached --through the zfcp device driver. Expect error messages in mixed environments --such as with iSCSI. -+This tool is designed for environments with SCSI devices attached -+through the zfcp device driver. - - .B lsluns - lists all logical unit numbers (LUNs) discovered in the diff --git a/s390-tools-sles15-5-lstape-fix-to-prevent-error-messages-if-there-are-no.patch b/s390-tools-sles15-5-lstape-fix-to-prevent-error-messages-if-there-are-no.patch deleted file mode 100644 index ec7dadc..0000000 --- a/s390-tools-sles15-5-lstape-fix-to-prevent-error-messages-if-there-are-no.patch +++ /dev/null @@ -1,136 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - ---- a/zconf/lstape -+++ b/zconf/lstape -@@ -335,9 +335,13 @@ function SysfsCreateListSCSI() - $STATE - - if $VERBOSE; then -+ HBA_ID="N/A" -+ [ -r $SCSI_DEV/hba_id ] && HBA_ID=$(cat $SCSI_DEV/hba_id) -+ WWPN="N/A" -+ [ -r $SCSI_DEV/wwpn ] && WWPN=$(cat $SCSI_DEV/wwpn) - printf "$SCSIVFORMAT" \ -- $(cat $SCSI_DEV/hba_id) \ -- $(cat $SCSI_DEV/wwpn) \ -+ "$HBA_ID" \ -+ "$WWPN" \ - $TAPE_SERIAL - fi - done diff --git a/s390-tools-sles15-6-lstape-fix-description-of-type-and-devbusid-filter-f.patch b/s390-tools-sles15-6-lstape-fix-description-of-type-and-devbusid-filter-f.patch deleted file mode 100644 index 6e10577..0000000 --- a/s390-tools-sles15-6-lstape-fix-description-of-type-and-devbusid-filter-f.patch +++ /dev/null @@ -1,147 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape.8 | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - ---- a/zconf/lstape.8 -+++ b/zconf/lstape.8 -@@ -20,6 +20,8 @@ lstape \- list tape devices. - .br - .RB [ -t - .IR [, ] "" ...] -+.br -+.RI [ ...] - - .SH DESCRIPTION - The lstape command lists all available tape devices on the current host. For -@@ -78,12 +80,14 @@ on the output of SCSI devices. - - .TP - .BR -t | --type " \fI\fR" --Limit output to given device types (currently only applies to channel attached -+Limit output to given device types, for example 3490 -+(currently only applies to channel-attached - tape devices). - - .TP --\fB\fR = --Device type of devices that should be displayed (e.g. 3490). -+.I -+Limits the output to information about the specified tape device or -+devices only. For CCW-attached devices only. - - .SH EXAMPLES - \fBlstape\fR diff --git a/s390-tools-sles15-7-lstape-fix-SCSI-output-description-in-man-page.patch b/s390-tools-sles15-7-lstape-fix-SCSI-output-description-in-man-page.patch deleted file mode 100644 index 7315e1a..0000000 --- a/s390-tools-sles15-7-lstape-fix-SCSI-output-description-in-man-page.patch +++ /dev/null @@ -1,206 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape.8 | 68 +++++++++++++++++++++++++++++++++++++++++++++------------ - 1 file changed, 54 insertions(+), 14 deletions(-) - ---- a/zconf/lstape.8 -+++ b/zconf/lstape.8 -@@ -29,20 +29,6 @@ channel attached tape devices this outpu - /proc/tapedevices (which is obsolete) but also includes offline devices. By - default all tape devices are displayed. - --Since SCSI tape devices are accessed differently to channel attached tape --devices they are only visible if they are known to the SCSI layer. There --are at least two possible drivers that can claim a SCSI tape device and the --lstape command tries to find out which one this is. For the generic tape --and changer driver the device names start with "st" or "sch", while for the --IBM tape driver this would be "IBMtape" or "IBMchanger". If "N/A" is shown, --the correct driver could not be obtained. -- --The serial number of a SCSI tape can be displayed with the --verbose option. If --there is no sg_inq command available "NO/INQ" is shown as the serial number --of the tape. --If no SCSI generic (sg) kernel support is available, "NO/SG" is shown --as the serial number of the tape and "N/A" for the "Generic" column. -- - The lstape command without the --ccw-only option causes extra SAN traffic - for each SCSI tape or changer device by invoking the sg_inq command. - -@@ -89,6 +75,55 @@ tape devices). - Limits the output to information about the specified tape device or - devices only. For CCW-attached devices only. - -+.SH OUTPUT FIELDS FOR SCSI TAPE/CHANGER DEVICES -+.TP -+.B Generic -+SCSI generic device file for the tape drive, for example /dev/sg0. -+"N/A" if the SCSI generic (sg) kernel functionality is not available. -+.TP -+.B Device -+Main character device node file for accessing the tape drive or medium changer. -+SCSI tape devices are only visible if they are known to the SCSI layer. There -+are at least two possible drivers that can claim a SCSI tape device. The -+lstape command tries to determine the device driver. For the generic tape -+and changer driver the device names start with "st" or "sch", while for the -+IBM tape driver this would be "IBMtape" or "IBMchanger". If "N/A" is shown, -+the device driver could not be determined. -+.TP -+.B Target -+Linux SCSI device name in H:C:T:L format. -+.TP -+.B Vendor -+The vendor field from the SCSI device. -+.TP -+.B Model -+The model field from the SCSI device. -+.TP -+.B Type -+"tapedrv" for a tape drive or "changer" for a medium changer. -+.TP -+.B State -+The state of the SCSI device object in the kernel. -+Any state other than "running" can indicate problems. -+ -+.PP -+ -+For SCSI devices, the --verbose option additionally displays: -+.TP -+.B HBA -+The device bus-ID of the FCP device -+through which the tape drive is attached. -+"N/A" if device is not attached through zfcp. -+.TP -+.B WWPN -+The WWPN (worldwide port name) of the tape drive in the SAN. -+"N/A" if device is not attached through zfcp. -+.TP -+.B Serial -+The serial number. -+"NO/INQ" if there is no sg_inq command available. -+"NO/SG" if no SCSI generic (sg) kernel support is available. -+ - .SH EXAMPLES - \fBlstape\fR - .RS -@@ -99,3 +134,8 @@ List all tape devices that are available - .RS - Show all 3490 CCW devices that are online. - .RE -+ -+\fBlstape --scsi-only --verbose\fR -+.RS -+Show all SCSI tape or changer devices with maximum information. -+.RE diff --git a/s390-tools-sles15-8-lstape-fix-SCSI-HBA-CCW-device-bus-ID-e.g.-for-virti.patch b/s390-tools-sles15-8-lstape-fix-SCSI-HBA-CCW-device-bus-ID-e.g.-for-virti.patch deleted file mode 100644 index b948d8e..0000000 --- a/s390-tools-sles15-8-lstape-fix-SCSI-HBA-CCW-device-bus-ID-e.g.-for-virti.patch +++ /dev/null @@ -1,173 +0,0 @@ -Subject: lstape, lsluns: handle non-zfcp; lin_tape multiple paths -From: Steffen Maier - -Description: lstape, lsluns: handle non-zfcp; lin_tape multiple paths - -Symptom: lstape shows unexpected additional Device suffix numbers in - excess output columns for each additional path of the same - tape/changer driven by the IBM lin_tape device driver - (independent of actual path failover enablement in lin_tape). - It also shows a wrong number of found devices in the header - (without --scsi-only). - - lstape prints error about "Unexpected extra argument:" and the - usage for "sg_inq" along with wrong tabular output. - - lsluns prints ENOENT error text for "cat" on SCSI device sysfs - attributes hba_id, wwpn, and fcp_lun. - - lstape with --verbose option prints ENOENT error text for - "cat" on SCSI device sysfs attributes hba_id and wwpn. - - lstape man page: Description of --type and filter - for channel tapes is incomplete. SCSI output description is - incomplete. - - lstape shows "N/A" instead of the HBA device bus-ID with - virtio-scsi-ccw. - -Problem: s390-tools-1.8.0 before the first upstream commit b627b8d8e1ab - ("Initial s390-tools-2.0.0 import") introduced SCSI - tape/changer output for lstape. It used the SCSI device serial - number as lookup key to find a match in IBM lin_tape device - driver proc-fs output for a given SCSI device name. Multiple - paths to the same tape/changer have the same serial number. - Multiple matches cause excess arguments to printf. Explaining - the resulting output, the bash man page says: "The format is - reused as necessary to consume all of the arguments." This - also causes a wrong number of found devices. - - The default bash settings have nullglob disabled so if - $SCSI_DEV/scsi_generic* aka - /sys/bus/scsi/devices/*:*:*:*/scsi_generic* does not match - anything, it leaves the glob pattern unmodified and - SG_DEV=$(basename $SG_DEV/*) results in the literal "*". If - $SG_INQ exists, it invoked sg_inq with more than the one - allowed positional argument for a SCSI generic device node - "sg_inq /dev/*". Causing error messages and the usage of - sg_inq to land in $TAPE_SERIAL. - - lsluns iterates SCSI generic devices and unconditionally - reads zfcp-specific SCSI device sysfs attributes hba_id, wwpn, - and fcp_lun. - - lstape --verbose unconditionally reads zfcp-specific SCSI - device sysfs attributes hba_id and wwpn. - - filter missing from synopsis. example - at wrong place with filter. filter - option description is a duplicate of filter - option description. SCSI output description misses fields. - - Lstape only used the zfcp-specific sysfs attribute hba_id. - -Solution: Prefer sysfs to find lin_tape device name for SCSI device. - Fallback: The lin_tape proc-fs output format has changed over - the years. The HBA device driver string can contain whitespace - (e.g. "Virtio SCSI HBA") and breaks the field numbers with - tokenized parsing. Grep for the SCSI device name as word (to - skip names with same substring, such as 0:0:1:1 also matching - 0:0:1:10) and cut the first field 'Number' (lin_tape device - name suffix). If there is no SCSI column at all [lin_tape - before v2.2.0] (and no SCSI LLDD or other column with a name - accidentally matching an existing SCSI device name), we get no - match and better bail out with the initialized "N/A" for the - lstape column "Device". - - To not have to rely on the nullglob setting, explicitly check - for the existence of $SCSI_DEV/scsi_generic before evaluating - SG_DEV=$(basename $SG_DEV/*). Also handle availability of - sg_inq but absence of scsi_generic individually to provide the - user with a hint if only sg is missing. - - Simply skip non-zfcp SCSI devices, such as iSCSI or - virtio-scsi-ccw, to not erroneously access absent attributes. - - Assume "N/A" for HBA and WWPN of non-zfcp SCSI devices, such - as iSCSI or virtio-scsi-ccw, to not erroneously access absent - zfcp-specific sysfs attributes. - - Add filter to synopsis. Move example - to option. Replace filter option - description. Move existing SCSI output description to a new - subsection and add description of missing fields. - - Also search sysfs for an ancestor with subsystem ccw. - -Reproduction: Attach more than one path to the same SCSI tape or changer and - load the IBM lin_tape device driver. - - Unload sg kernel module. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - Attach non-zfcp SCSI devices such as iSCSI or virtio-scsi-ccw. - - man lstape - - Attach SCSI tape or changer with virtio-scsi-ccw to a KVM - guest and run "lstape --verbose". - -Upstream-ID: - -Problem-ID: 170633 - -Signed-off-by: Steffen Maier ---- - zconf/lstape | 25 +++++++++++++++++++++++-- - zconf/lstape.8 | 3 ++- - 2 files changed, 25 insertions(+), 3 deletions(-) - ---- a/zconf/lstape -+++ b/zconf/lstape -@@ -223,6 +223,24 @@ function SysfsCreateListCCW() { - ' | sort - } - -+# handle SCSI device not necessarily zfcp-attached, e.g. virtio-scsi-ccw -+function SCSISearchCCWBusid() -+{ -+ local SCSI_DEV=$1 -+ local SDEVCAN=$(readlink -e $SCSI_DEV) -+ while [ -n "$SDEVCAN" ]; do -+ # ascend to parent: strip last path part -+ SDEVCAN=${SDEVCAN%/*} -+ [ -h $SDEVCAN/subsystem ] || continue -+ local SUBSYSTEM=$(readlink -e $SDEVCAN/subsystem) -+ if [ "${SUBSYSTEM##*/}" = "ccw" ]; then -+ echo ${SDEVCAN##*/} -+ return -+ fi -+ done -+ echo "N/A" -+} -+ - function SysfsCreateListSCSI() - { - for SCSI_DEV in $1/bus/scsi/devices/*:*:*:*; do -@@ -335,8 +353,11 @@ function SysfsCreateListSCSI() - $STATE - - if $VERBOSE; then -- HBA_ID="N/A" -- [ -r $SCSI_DEV/hba_id ] && HBA_ID=$(cat $SCSI_DEV/hba_id) -+ if [ -r $SCSI_DEV/hba_id ]; then -+ HBA_ID=$(cat $SCSI_DEV/hba_id) -+ else -+ HBA_ID=$(SCSISearchCCWBusid $SCSI_DEV) -+ fi - WWPN="N/A" - [ -r $SCSI_DEV/wwpn ] && WWPN=$(cat $SCSI_DEV/wwpn) - printf "$SCSIVFORMAT" \ ---- a/zconf/lstape.8 -+++ b/zconf/lstape.8 -@@ -112,8 +112,9 @@ For SCSI devices, the --verbose option a - .TP - .B HBA - The device bus-ID of the FCP device -+or of the virtio-scsi-ccw virtual HBA - through which the tape drive is attached. --"N/A" if device is not attached through zfcp. -+"N/A" if the device does not have a sysfs ancestor with subsystem ccw. - .TP - .B WWPN - The WWPN (worldwide port name) of the tape drive in the SAN. diff --git a/s390-tools-sles15-Allow-multiple-device-arguments.patch b/s390-tools-sles15-Allow-multiple-device-arguments.patch index 4f566e3..82442ab 100644 --- a/s390-tools-sles15-Allow-multiple-device-arguments.patch +++ b/s390-tools-sles15-Allow-multiple-device-arguments.patch @@ -37,7 +37,7 @@ diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index b79cff0..607fd1c 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c -@@ -21,6 +21,7 @@ +@@ -23,6 +23,7 @@ #include "dasdfmt.h" @@ -45,7 +45,7 @@ index b79cff0..607fd1c 100644 #define BUSIDSIZE 8 #define SEC_PER_DAY (60 * 60 * 24) #define SEC_PER_HOUR (60 * 60) -@@ -456,44 +457,40 @@ static void program_interrupt_signal(int sig) +@@ -463,44 +464,40 @@ static void program_interrupt_signal(int sig) /* * check given device name for blanks and some special characters */ @@ -107,37 +107,198 @@ index b79cff0..607fd1c 100644 } } -@@ -1457,24 +1454,86 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname, +@@ -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 } -+void do_dasdfmt(char *dev_filename, dasdfmt_info_t *info, -+ volume_label_t *orig_vlabel) + 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; ++ 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)); + -+ get_device_info(info); + memcpy(&vlabel, orig_vlabel, sizeof(vlabel)); + /* Either let the user specify the blksize or get it from the kernel */ -+ if (!info->blksize_specified) { ++ if (!info.blksize_specified) { + if (!(mode == FULL || -+ info->dasd_info.format == DASD_FORMAT_NONE) -+ || info->check) -+ get_blocksize(&format_params.blksize); ++ 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) { ++ if (info.keep_volser) { ++ if (info.labelspec) { + ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options " + "are mutually exclusive\n", prog_name); + } @@ -148,7 +309,7 @@ index b79cff0..607fd1c 100644 + } + + if (dasdfmt_get_volser(dev_filename, -+ &info->dasd_info, old_volser) == 0) ++ &info.dasd_info, old_volser) == 0) + vtoc_volume_label_set_volser(&vlabel, old_volser); + else + ERRMSG_EXIT(EXIT_FAILURE, @@ -156,24 +317,20 @@ index b79cff0..607fd1c 100644 + prog_name, dev_filename); + } + -+ check_disk(info, 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); ++ set_geo(&info, &cylinders, &heads); ++ set_label(&info, &vlabel, &format_params, cylinders); + -+ if (info->check) -+ check_disk_format(info, cylinders, heads, &format_params); ++ if (info.check) ++ check_disk_format(&info, cylinders, heads, &format_params); + else -+ do_format_dasd(info, dev_filename, &vlabel, ++ do_format_dasd(&info, dev_filename, &vlabel, + &format_params, cylinders, heads); + -+ if (close(filedes) != 0) -+ ERRMSG("%s: error during close: %s\ncontinuing...\n", -+ prog_name, strerror(errno)); -+ +} + int main(int argc, char *argv[]) @@ -184,7 +341,6 @@ index b79cff0..607fd1c 100644 volume_label_t vlabel; - char old_volser[7]; -- char dev_filename[PATH_MAX]; - char str[ERR_LENGTH]; + char *dev_filename[MAX_DEVICES]; char buf[7]; @@ -199,35 +355,30 @@ index b79cff0..607fd1c 100644 /* Establish a handler for interrupt signals. */ signal(SIGTERM, program_interrupt_signal); -@@ -1634,61 +1693,21 @@ int main(int argc, char *argv[]) +@@ -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); - -- 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)); +- 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); - -- get_device_info(&info); -+ while (optind < argc) { -+ if (optind >= argc) -+ ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n", -+ prog_name); - - /* 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(&format_params.blksize); +- get_blocksize(dev_filename, &format_params.blksize); - else - format_params = ask_user_for_blksize(format_params); -+ get_device_name(dev_filename, numdev, argv[optind]); -+ optind++; -+ numdev++; - } - +- } +- - if (info.keep_volser) { - if (info.labelspec) { - ERRMSG_EXIT(EXIT_MISUSE, "%s: The -k and -l options " @@ -246,8 +397,19 @@ index b79cff0..607fd1c 100644 - 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) @@ -261,16 +423,12 @@ index b79cff0..607fd1c 100644 - else - do_format_dasd(&info, dev_filename, &vlabel, - &format_params, cylinders, heads); -- -- if (close(filedes) != 0) -- ERRMSG("%s: error during close: %s\ncontinuing...\n", -- prog_name, strerror(errno)); + 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); ++ do_dasdfmt(dev_filename[i], info, &vlabel, format_params); return 0; } -- diff --git a/s390-tools-sles15-Drop-device_id-parameter.patch b/s390-tools-sles15-Drop-device_id-parameter.patch deleted file mode 100644 index ac46afb..0000000 --- a/s390-tools-sles15-Drop-device_id-parameter.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 320946c0e9b2a80c3569d8f736621c99392fc413 Mon Sep 17 00:00:00 2001 -From: Hannes Reinecke -Date: Thu, 5 Oct 2017 10:11:57 +0200 -Subject: [PATCH] dasdfmt: drop 'device_id' parameter - -Drop device_id parameter from dasdfmt_info() and pass in 'optind' -directly. - -Signed-off-by: Hannes Reinecke ---- - dasdfmt/dasdfmt.c | 15 +++++++-------- - dasdfmt/dasdfmt.h | 1 - - 2 files changed, 7 insertions(+), 9 deletions(-) - -diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c -index 3da7902..b79cff0 100644 ---- a/dasdfmt/dasdfmt.c -+++ b/dasdfmt/dasdfmt.c -@@ -456,24 +456,24 @@ static void program_interrupt_signal(int sig) - /* - * check given device name for blanks and some special characters - */ --static void get_device_name(dasdfmt_info_t *info, char *devname, int argc, -- char *argv[]) -+static void get_device_name(char *devname, -+ int optind, int argc, char *argv[]) - { - struct util_proc_dev_entry dev_entry; - struct stat dev_stat; - -- if (info->device_id + 1 < argc) -+ if (optind + 1 < argc) - ERRMSG_EXIT(EXIT_MISUSE, - "%s: More than one device specified!\n", prog_name); - -- if (info->device_id >= argc) -+ if (optind >= argc) - ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n", - prog_name); - -- if (strlen(argv[info->device_id]) >= PATH_MAX) -+ if (strlen(argv[optind]) >= PATH_MAX) - ERRMSG_EXIT(EXIT_MISUSE, "%s: device name too long!\n", - prog_name); -- strcpy(devname, argv[info->device_id]); -+ strcpy(devname, argv[optind]); - - if (stat(devname, &dev_stat) != 0) - ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for " -@@ -1604,7 +1604,6 @@ int main(int argc, char *argv[]) - break; - case -1: - /* End of options string - start of devices list */ -- info.device_id = optind; - break; - default: - ERRMSG_EXIT(EXIT_MISUSE, "Try '%s --help' for more" -@@ -1635,7 +1634,7 @@ int main(int argc, char *argv[]) - if (info.print_hashmarks) - PARSE_PARAM_INTO(info.hashstep, hashstep_str, 10, "hashstep"); - -- get_device_name(&info, dev_filename, argc, argv); -+ get_device_name(dev_filename, optind, argc, argv); - - filedes = open(dev_filename, O_RDWR); - if (filedes == -1) -diff --git a/dasdfmt/dasdfmt.h b/dasdfmt/dasdfmt.h -index 9ce3b92..a5581f1 100644 ---- a/dasdfmt/dasdfmt.h -+++ b/dasdfmt/dasdfmt.h -@@ -303,7 +303,6 @@ typedef struct dasdfmt_info { - int cdl_format; - int blksize_specified; - int reqsize_specified; -- int device_id; - int keep_volser; - int force_host; - int layout_specified; --- -1.7.12.4 - diff --git a/s390-tools-sles15-Fix-truncation-warning.patch b/s390-tools-sles15-Fix-truncation-warning.patch deleted file mode 100644 index fff721d..0000000 --- a/s390-tools-sles15-Fix-truncation-warning.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 1261105fe238ad306db29a9d47bb1a293bddf9aa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jan=20H=C3=B6ppner?= -Date: Mon, 16 Oct 2017 15:46:07 +0200 -Subject: [PATCH] dasdinfo: Fix truncation warning -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Commit 3c80f7e025db ("dasdinfo: fix buffer overflow warning") changed a -sprintf call to snprintf to avoid a buffer overflow warning. However, -GCC 7 now warns about a potential truncation with snprintf: - -dasdinfo.c: In function 'main': -dasdinfo.c:577:18: warning: '%s' directive output may be truncated -writing up to 255 bytes into a region of size 69 [-Wformat-truncation=] - "/sys/block/%s/device/uid", dir_entry->d_name); - ^~ -dasdinfo.c:576:4: note: 'snprintf' output between 23 and 278 bytes into -a destination of size 80 - snprintf(*uidfile, RD_BUFFER_SIZE, - ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - "/sys/block/%s/device/uid", dir_entry->d_name); - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We could get around this by increasing the buffer. Though, the current -buffer size is already plenty and we know better anyway. -Avoid the warning by simply checking the return value of snprintf and -display an error in case data was truncated nonetheless. - -Fixes: 3c80f7e025db ("dasdinfo: fix buffer overflow warning") -Signed-off-by: Jan Höppner -Signed-off-by: Michael Holzheu ---- - dasdinfo/dasdinfo.c | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/dasdinfo/dasdinfo.c b/dasdinfo/dasdinfo.c -index c8bda3b..f881f03 100644 ---- a/dasdinfo/dasdinfo.c -+++ b/dasdinfo/dasdinfo.c -@@ -545,6 +545,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode) - char *readbuf; - DIR *directory = NULL; - struct dirent *dir_entry = NULL; -+ int rc = 0; - - if (stat(devnode, &stat_buffer) != 0) { - printf("Error: could not stat %s\n", devnode); -@@ -573,8 +574,15 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode) - - if (strncmp(stat_dev, readbuf, - MAX(strlen(stat_dev), strlen(readbuf)-1)) == 0) { -- snprintf(*uidfile, RD_BUFFER_SIZE, -- "/sys/block/%s/device/uid", dir_entry->d_name); -+ rc = snprintf(*uidfile, RD_BUFFER_SIZE, -+ "/sys/block/%s/device/uid", -+ dir_entry->d_name); -+ if (rc >= RD_BUFFER_SIZE) { -+ fprintf(stderr, -+ "Error: Device name was truncated\n"); -+ return -1; -+ } -+ - break; - } - } --- -1.7.12.4 - diff --git a/s390-tools-sles15-Fixup-dasdfmt_get_volser.patch b/s390-tools-sles15-Fixup-dasdfmt_get_volser.patch deleted file mode 100644 index cf177a0..0000000 --- a/s390-tools-sles15-Fixup-dasdfmt_get_volser.patch +++ /dev/null @@ -1,67 +0,0 @@ -From f3adc9ca7928a8250f31b242335686ad9879ce10 Mon Sep 17 00:00:00 2001 -From: Hannes Reinecke -Date: Thu, 5 Oct 2017 09:42:42 +0200 -Subject: [PATCH] dasdfmt: Fixup dasdfmt_get_volser() - -dasdfmt_get_volser() opens its own private filedescriptor -despite the global filedes already being opened. -And we should be passing in only the bits of the info structure -that we actually need. - -Signed-off-by: Hannes Reinecke ---- - dasdfmt/dasdfmt.c | 24 ++++++++---------------- - 1 file changed, 8 insertions(+), 16 deletions(-) - -diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c -index 6043872..4cf423d 100644 ---- a/dasdfmt/dasdfmt.c -+++ b/dasdfmt/dasdfmt.c -@@ -970,28 +970,19 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, volume_label_t *vlabel, - /* - * get volser - */ --static int dasdfmt_get_volser(dasdfmt_info_t *info, char *volser) -+static int dasdfmt_get_volser(char *devname, dasd_information2_t *dasd_info, -+ char *volser) - { - unsigned int blksize; -- int f; - volume_label_t vlabel; - -- f = open(info->devname, O_RDONLY); -- if (f == -1) -- ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", -- prog_name, info->devname, strerror(errno)); -- - get_blocksize(&blksize); - -- if (close(f) != 0) -- ERRMSG("%s: error during close: %s\ncontinuing...\n", -- prog_name, strerror(errno)); -- -- if ((strncmp(info->dasd_info.type, "ECKD", 4) == 0) && -- (!info->dasd_info.FBA_layout)) { -+ if ((strncmp(dasd_info->type, "ECKD", 4) == 0) && -+ !dasd_info->FBA_layout) { - /* OS/390 and zOS compatible disk layout */ -- vtoc_read_volume_label(info->devname, -- info->dasd_info.label_block * blksize, -+ vtoc_read_volume_label(devname, -+ dasd_info->label_block * blksize, - &vlabel); - vtoc_volume_label_get_volser(&vlabel, volser); - return 0; -@@ -1684,7 +1675,8 @@ int main(int argc, char *argv[]) - exit(1); - } - -- if (dasdfmt_get_volser(&info, old_volser) == 0) -+ if (dasdfmt_get_volser(info.devname, -+ &info.dasd_info, old_volser) == 0) - vtoc_volume_label_set_volser(&vlabel, old_volser); - else - ERRMSG_EXIT(EXIT_FAILURE, --- -1.7.12.4 - diff --git a/s390-tools-sles15-Fixup-device-name-handling.patch b/s390-tools-sles15-Fixup-device-name-handling.patch deleted file mode 100644 index 4151aed..0000000 --- a/s390-tools-sles15-Fixup-device-name-handling.patch +++ /dev/null @@ -1,233 +0,0 @@ -From a4101cc9bf1d18b698ead344e6be6fe311fda41d Mon Sep 17 00:00:00 2001 -From: Hannes Reinecke -Date: Thu, 5 Oct 2017 09:59:41 +0200 -Subject: [PATCH] dasdfmt: Fixup device name handling - -get_device_name() contains a chunk of unreachable code, as the -'name' argument is never filled with any value. -So turn things around to have get_device_name() always fill the -'name' argument with the real device name, and remove the -devname entry from the dasdfmt_info_t structure. - -Signed-off-by: Hannes Reinecke ---- - dasdfmt/dasdfmt.c | 70 ++++++++++++++++++++++++------------------------------- - dasdfmt/dasdfmt.h | 1 - - 2 files changed, 30 insertions(+), 41 deletions(-) - -diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c -index 4cf423d..3da7902 100644 ---- a/dasdfmt/dasdfmt.c -+++ b/dasdfmt/dasdfmt.c -@@ -456,7 +456,7 @@ static void program_interrupt_signal(int sig) - /* - * check given device name for blanks and some special characters - */ --static void get_device_name(dasdfmt_info_t *info, char *name, int argc, -+static void get_device_name(dasdfmt_info_t *info, char *devname, int argc, - char *argv[]) - { - struct util_proc_dev_entry dev_entry; -@@ -470,32 +470,20 @@ static void get_device_name(dasdfmt_info_t *info, char *name, int argc, - ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n", - prog_name); - -- if (info->device_id < argc) { -- strcpy(info->devname, argv[info->device_id]); -- } else { -- if ((strchr(name, ' ') != NULL) || (strchr(name, '#') != NULL) || -- (strchr(name, '[') != NULL) || (strchr(name, ']') != NULL) || -- (strchr(name, '!') != NULL) || (strchr(name, '>') != NULL) || -- (strchr(name, '(') != NULL) || (strchr(name, '<') != NULL) || -- (strchr(name, ')') != NULL) || (strchr(name, ':') != NULL) || -- (strchr(name, '&') != NULL) || (strchr(name, ';') != NULL)) -- ERRMSG_EXIT(EXIT_MISUSE, "%s: Your filename contains " -- "blanks or special characters!\n", -- prog_name); -- -- strncpy(info->devname, name, PATH_MAX - 1); -- info->devname[PATH_MAX - 1] = '\0'; -- } -+ if (strlen(argv[info->device_id]) >= PATH_MAX) -+ ERRMSG_EXIT(EXIT_MISUSE, "%s: device name too long!\n", -+ prog_name); -+ strcpy(devname, argv[info->device_id]); - -- if (stat(info->devname, &dev_stat) != 0) -+ if (stat(devname, &dev_stat) != 0) - ERRMSG_EXIT(EXIT_MISUSE, "%s: Could not get information for " -- "device node %s: %s\n", prog_name, info->devname, -+ "device node %s: %s\n", prog_name, devname, - strerror(errno)); - - if (minor(dev_stat.st_rdev) & PARTN_MASK) { - ERRMSG_EXIT(EXIT_MISUSE, "%s: Unable to format partition %s. " - "Please specify a device.\n", prog_name, -- info->devname); -+ devname); - } - - if (util_proc_dev_get_entry(dev_stat.st_rdev, 1, &dev_entry) == 0) { -@@ -505,7 +493,7 @@ static void get_device_name(dasdfmt_info_t *info, char *name, int argc, - prog_name, dev_entry.name); - } else { - printf("%s WARNING: Unable to get driver name for device node %s", -- prog_name, info->devname); -+ prog_name, devname); - } - } - -@@ -586,7 +574,7 @@ static void check_layout(dasdfmt_info_t *info, unsigned int intensity) - /* - * check for disk type and set some variables (e.g. usage count) - */ --static void check_disk(dasdfmt_info_t *info) -+static void check_disk(dasdfmt_info_t *info, char *devname) - { - int ro, errno_save; - -@@ -609,13 +597,13 @@ static void check_disk(dasdfmt_info_t *info) - if (strncmp(info->dasd_info.type, "ECKD", 4) != 0) { - ERRMSG_EXIT(EXIT_FAILURE, - "%s: Unsupported disk type\n%s is not an " -- "ECKD disk!\n", prog_name, info->devname); -+ "ECKD disk!\n", prog_name, devname); - } - -- if (dasd_sys_raw_track_access(info->devname)) { -+ if (dasd_sys_raw_track_access(devname)) { - ERRMSG_EXIT(EXIT_FAILURE, - "%s: Device '%s' is in raw-track access mode\n", -- prog_name, info->devname); -+ prog_name, devname); - } - } - -@@ -935,7 +923,8 @@ static format_data_t ask_user_for_blksize(format_data_t params) - /* - * print all information needed to format the device - */ --static void dasdfmt_print_info(dasdfmt_info_t *info, volume_label_t *vlabel, -+static void dasdfmt_print_info(dasdfmt_info_t *info, char *devname, -+ volume_label_t *vlabel, - unsigned int cylinders, unsigned int heads, - format_data_t *p) - { -@@ -945,7 +934,7 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, volume_label_t *vlabel, - cylinders, heads, (cylinders * heads)); - - printf("\nI am going to format the device "); -- printf("%s in the following way:\n", info->devname); -+ printf("%s in the following way:\n", devname); - printf(" Device number of device : 0x%x\n", info->dasd_info.devno); - printf(" Labelling device : %s\n", - (info->writenolabel) ? "no" : "yes"); -@@ -1376,7 +1365,8 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders, - disk_disabled = 0; - } - --static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel, -+static void do_format_dasd(dasdfmt_info_t *info, char *devname, -+ volume_label_t *vlabel, - format_data_t *p, unsigned int cylinders, - unsigned int heads) - { -@@ -1399,19 +1389,19 @@ static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel, - } - - if ((info->verbosity > 0) || !info->withoutprompt || info->testmode) -- dasdfmt_print_info(info, vlabel, cylinders, heads, p); -+ dasdfmt_print_info(info, devname, vlabel, cylinders, heads, p); - -- count = u2s_get_host_access_count(info->devname); -+ count = u2s_get_host_access_count(devname); - if (info->force_host) { - if (count > 1) { - ERRMSG_EXIT(EXIT_FAILURE, - "\n%s: Disk %s is online on OS instances in %d different LPARs.\n" - "Note: Your installation might include z/VM systems that are configured to\n" - "automatically vary on disks, regardless of whether they are subsequently used.\n\n", -- prog_name, info->devname, count); -+ prog_name, devname, count); - } else if (count < 0) { - ERRMSG("\nHosts access information not available for disk %s.\n\n", -- info->devname); -+ devname); - return; - } - } else if (count > 1) -@@ -1420,7 +1410,7 @@ static void do_format_dasd(dasdfmt_info_t *info, volume_label_t *vlabel, - "Ensure that the disk is not being used by a system outside your LPAR.\n" - "Note: Your installation might include z/VM systems that are configured to\n" - "automatically vary on disks, regardless of whether they are subsequently used.\n", -- info->devname, count); -+ devname, count); - - if (!info->testmode) { - if (!info->withoutprompt) { -@@ -1471,7 +1461,6 @@ int main(int argc, char *argv[]) - { - dasdfmt_info_t info = { - .dasd_info = {0}, -- {0} - }; - volume_label_t vlabel; - char old_volser[7]; -@@ -1648,10 +1637,10 @@ int main(int argc, char *argv[]) - - get_device_name(&info, dev_filename, argc, argv); - -- filedes = open(info.devname, O_RDWR); -+ filedes = open(dev_filename, O_RDWR); - if (filedes == -1) - ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n", -- prog_name, info.devname, strerror(errno)); -+ prog_name, dev_filename, strerror(errno)); - - get_device_info(&info); - -@@ -1675,16 +1664,16 @@ int main(int argc, char *argv[]) - exit(1); - } - -- if (dasdfmt_get_volser(info.devname, -+ 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, info.devname); -+ prog_name, dev_filename); - } - -- check_disk(&info); -+ check_disk(&info, dev_filename); - - if (check_param(str, ERR_LENGTH, &format_params) < 0) - ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str); -@@ -1695,7 +1684,8 @@ int main(int argc, char *argv[]) - if (info.check) - check_disk_format(&info, cylinders, heads, &format_params); - else -- do_format_dasd(&info, &vlabel, &format_params, cylinders, heads); -+ do_format_dasd(&info, dev_filename, &vlabel, -+ &format_params, cylinders, heads); - - if (close(filedes) != 0) - ERRMSG("%s: error during close: %s\ncontinuing...\n", -diff --git a/dasdfmt/dasdfmt.h b/dasdfmt/dasdfmt.h -index 7c6f0bd..9ce3b92 100644 ---- a/dasdfmt/dasdfmt.h -+++ b/dasdfmt/dasdfmt.h -@@ -291,7 +291,6 @@ typedef struct bootstrap2 { - - typedef struct dasdfmt_info { - dasd_information2_t dasd_info; -- char devname[PATH_MAX]; - int verbosity; - int testmode; - int withoutprompt; --- -1.7.12.4 - diff --git a/s390-tools-sles15-Format-devices-in-parallel.patch b/s390-tools-sles15-Format-devices-in-parallel.patch index 76a2e86..9d773dd 100644 --- a/s390-tools-sles15-Format-devices-in-parallel.patch +++ b/s390-tools-sles15-Format-devices-in-parallel.patch @@ -34,7 +34,7 @@ index e7fc501..07c674b 100644 Print one line for each formatted cylinder showing the number of the cylinder and percentage of formatting process. Intended to be used by higher level interfaces. -@@ -153,6 +153,18 @@ Specify blocksize to be used. \fIblksize\fR must be a positive integer +@@ -159,6 +159,18 @@ Specify blocksize to be used. \fIblksize\fR must be a positive integer and always be a power of two. The recommended blocksize is 4096 bytes. .TP @@ -57,15 +57,15 @@ diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index 607fd1c..6dd28fa 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c -@@ -11,6 +11,7 @@ +@@ -12,6 +12,7 @@ #include #include #include +#include + #include "lib/dasd_base.h" #include "lib/dasd_sys.h" - #include "lib/util_opt.h" -@@ -68,6 +69,11 @@ static struct util_opt opt_vec[] = { +@@ -71,6 +72,11 @@ static struct util_opt opt_vec[] = { .desc = "Perform complete format check on device", .flags = UTIL_OPT_FLAG_NOSHORT, }, @@ -77,7 +77,7 @@ index 607fd1c..6dd28fa 100644 UTIL_OPT_SECTION("FORMAT OPTIONS"), { .option = { "blocksize", required_argument, NULL, 'b' }, -@@ -120,7 +126,7 @@ static struct util_opt opt_vec[] = { +@@ -128,7 +134,7 @@ static struct util_opt opt_vec[] = { .desc = "Show a progressbar", }, { @@ -86,7 +86,7 @@ index 607fd1c..6dd28fa 100644 .desc = "Show progress in percent", }, UTIL_OPT_SECTION("MISC"), -@@ -254,7 +260,7 @@ static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders, +@@ -262,7 +268,7 @@ static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders, if (info->print_hashmarks && (cyl / info->hashstep - hashcount) != 0) { @@ -95,7 +95,7 @@ index 607fd1c..6dd28fa 100644 fflush(stdout); hashcount++; } -@@ -1533,7 +1539,8 @@ int main(int argc, char *argv[]) +@@ -1587,7 +1593,8 @@ int main(int argc, char *argv[]) char *reqsize_param_str = NULL; char *hashstep_str = NULL; @@ -105,7 +105,7 @@ index 607fd1c..6dd28fa 100644 /* Establish a handler for interrupt signals. */ signal(SIGTERM, program_interrupt_signal); -@@ -1600,7 +1607,7 @@ int main(int argc, char *argv[]) +@@ -1652,7 +1659,7 @@ int main(int argc, char *argv[]) info.print_hashmarks = 1; } break; @@ -114,9 +114,9 @@ index 607fd1c..6dd28fa 100644 if (!(info.print_hashmarks || info.print_progressbar)) info.print_percentage = 1; break; -@@ -1658,6 +1665,9 @@ int main(int argc, char *argv[]) - "more information.\n", - prog_name, optarg); +@@ -1714,6 +1721,9 @@ int main(int argc, char *argv[]) + case OPT_NODISCARD: + info.no_discard = 1; break; + case 'P': + max_parallel = atoi(optarg); @@ -124,7 +124,7 @@ index 607fd1c..6dd28fa 100644 case OPT_CHECK: info.check = 1; break; -@@ -1673,6 +1683,9 @@ +@@ -1729,6 +1739,9 @@ break; /* exit loop if finished */ } @@ -134,12 +134,12 @@ index 607fd1c..6dd28fa 100644 CHECK_SPEC_MAX_ONCE(info.blksize_specified, "blocksize"); CHECK_SPEC_MAX_ONCE(info.labelspec, "label"); CHECK_SPEC_MAX_ONCE(info.writenolabel, "omit-label-writing flag"); -@@ -1707,7 +1717,33 @@ int main(int argc, char *argv[]) +@@ -1766,7 +1779,33 @@ int main(int argc, char *argv[]) ERRMSG_EXIT(EXIT_MISUSE, "%s: No device specified!\n", prog_name); - + - for (i = 0; i < numdev; i++) -- do_dasdfmt(dev_filename[i], &info, &vlabel); +- do_dasdfmt(dev_filename[i], info, &vlabel, format_params); - return 0; + for (i = 0; i < numdev; i++) { + int chpid; @@ -152,7 +152,7 @@ index 607fd1c..6dd28fa 100644 + prog_name, strerror(errno)); + if (!chpid) { + info.procnum = i; -+ do_dasdfmt(dev_filename[i], &info, &vlabel); ++ do_dasdfmt(dev_filename[i], info, &vlabel, format_params); + exit(0); + } else { + running++; @@ -175,10 +175,10 @@ diff --git a/dasdfmt/dasdfmt.h b/dasdfmt/dasdfmt.h index a5581f1..fb6fc34 100644 --- a/dasdfmt/dasdfmt.h +++ b/dasdfmt/dasdfmt.h -@@ -307,6 +307,7 @@ typedef struct dasdfmt_info { - int force_host; - int layout_specified; - int check; +@@ -95,6 +95,7 @@ typedef struct dasdfmt_info { + int mode_specified; + int ese; + int no_discard; + int procnum; } dasdfmt_info_t; diff --git a/s390-tools-sles15-Implement-Y-yast_mode.patch b/s390-tools-sles15-Implement-Y-yast_mode.patch index 145101a..436b148 100644 --- a/s390-tools-sles15-Implement-Y-yast_mode.patch +++ b/s390-tools-sles15-Implement-Y-yast_mode.patch @@ -41,7 +41,7 @@ diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index 6dd28fa..5b6023a 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c -@@ -129,6 +129,10 @@ static struct util_opt opt_vec[] = { +@@ -137,6 +137,10 @@ static struct util_opt opt_vec[] = { .option = { "percentage", no_argument, NULL, 'Q' }, .desc = "Show progress in percent", }, @@ -52,7 +52,7 @@ index 6dd28fa..5b6023a 100644 UTIL_OPT_SECTION("MISC"), { .option = { "check_host_count", no_argument, NULL, 'C' }, -@@ -351,7 +355,8 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata, +@@ -343,7 +347,8 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata, unsigned int kl = 0; int blksize = cdata->expect.blksize; @@ -62,7 +62,7 @@ index 6dd28fa..5b6023a 100644 printf("\n"); /* -@@ -758,9 +763,9 @@ static void check_hashmarks(dasdfmt_info_t *info) +@@ -749,9 +754,9 @@ static void check_hashmarks(dasdfmt_info_t *info) "using the default.\n"); info->hashstep = 10; } @@ -75,7 +75,16 @@ index 6dd28fa..5b6023a 100644 } } -@@ -1445,16 +1450,18 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname, +@@ -985,7 +990,7 @@ static int dasdfmt_get_volser(char *devn + /* + * do all the labeling (volume label and initial VTOC) + */ +-static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel, ++static void dasdfmt_write_labels(dasdfmt_info_t *info, char *dev_filename, volume_label_t *vlabel, + unsigned int cylinders, unsigned int heads) + { + int label_position; +@@ -1483,17 +1488,19 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname, break; } @@ -84,31 +93,32 @@ index 6dd28fa..5b6023a 100644 + 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... "); + if (!info->yast_mode) + printf("Rereading the partition table... "); - if (reread_partition_table()) { + err = dasd_reread_partition_table(devname, 5); + if (err != 0) { ERRMSG("%s: error during rereading the partition " - "table: %s.\n", prog_name, strerror(errno)); + "table: %s.\n", prog_name, strerror(err)); - } else { + } else if (!info->yast_mode) { printf("ok\n"); } } -@@ -1511,6 +1518,8 @@ void do_dasdfmt(char *dev_filename, dasdfmt_info_t *info, +@@ -1569,6 +1576,8 @@ void do_dasdfmt(char *dev_filename, dasdfmt_info_t *info, ERRMSG_EXIT(EXIT_MISUSE, "%s: %s\n", prog_name, str); - set_geo(info, &cylinders, &heads); -+ if (info->yast_mode) + set_geo(&info, &cylinders, &heads); ++ if (info.yast_mode) + printf("%d\n", cylinders); - set_label(info, &vlabel, &format_params, cylinders); + set_label(&info, &vlabel, &format_params, cylinders); - if (info->check) -@@ -1665,6 +1674,10 @@ int main(int argc, char *argv[]) - "more information.\n", - prog_name, optarg); + if (info.check) +@@ -1721,6 +1730,10 @@ int main(int argc, char *argv[]) + case OPT_NODISCARD: + info.no_discard = 1; break; + case 'Y': + /* YaST mode */ @@ -121,9 +131,9 @@ diff --git a/dasdfmt/dasdfmt.h b/dasdfmt/dasdfmt.h index fb6fc34..fe0cc7f 100644 --- a/dasdfmt/dasdfmt.h +++ b/dasdfmt/dasdfmt.h -@@ -308,6 +308,7 @@ typedef struct dasdfmt_info { - int layout_specified; - int check; +@@ -96,6 +96,7 @@ typedef struct dasdfmt_info { + int ese; + int no_discard; int procnum; + int yast_mode; } dasdfmt_info_t; diff --git a/s390-tools-sles15-Implement-f-for-backwards-compability.patch b/s390-tools-sles15-Implement-f-for-backwards-compability.patch index 17f4e5a..7a50f3c 100644 --- a/s390-tools-sles15-Implement-f-for-backwards-compability.patch +++ b/s390-tools-sles15-Implement-f-for-backwards-compability.patch @@ -41,7 +41,7 @@ diff --git a/dasdfmt/dasdfmt.c b/dasdfmt/dasdfmt.c index 5b6023a..cdd80df 100644 --- a/dasdfmt/dasdfmt.c +++ b/dasdfmt/dasdfmt.c -@@ -74,6 +74,10 @@ static struct util_opt opt_vec[] = { +@@ -77,6 +77,10 @@ static struct util_opt opt_vec[] = { .desc = "Format devices in parallel", .flags = UTIL_OPT_FLAG_NOLONG, }, @@ -52,7 +52,7 @@ index 5b6023a..cdd80df 100644 UTIL_OPT_SECTION("FORMAT OPTIONS"), { .option = { "blocksize", required_argument, NULL, 'b' }, -@@ -1597,6 +1601,10 @@ int main(int argc, char *argv[]) +@@ -1649,6 +1653,10 @@ int main(int argc, char *argv[]) } info.layout_specified = 1; break; diff --git a/s390-tools-sles15-cpi-add-unit-install-section.patch b/s390-tools-sles15-cpi-add-unit-install-section.patch deleted file mode 100644 index a2f9bb6..0000000 --- a/s390-tools-sles15-cpi-add-unit-install-section.patch +++ /dev/null @@ -1,27 +0,0 @@ -Subject: [PATCH] [BZ 160944] cpi: add missing Install section to service unit -From: Hendrik Brueckner - -Description: cpi: add missing Install section to service unit -Symptom: Enabling the cpi service unit fails because it - does not include information about where to install - it. -Problem: An install section is missing. -Solution: Add an install section. -Reproduction: Issue systemctl enable cpi. -Upstream-ID: - -Problem-ID: 160944 - -Signed-off-by: Hendrik Brueckner ---- - systemd/cpi.service.in | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/systemd/cpi.service.in -+++ b/systemd/cpi.service.in -@@ -38,3 +38,6 @@ EnvironmentFile=/etc/sysconfig/cpi - # - # Sending data to the HMC/SE - ExecStart=@toolslib_path@/cpictl -e -+ -+[Install] -+WantedBy=multi-user.target diff --git a/s390-tools-sles15-cpuplugd-Improve-systemctl-start-error-handling.patch b/s390-tools-sles15-cpuplugd-Improve-systemctl-start-error-handling.patch deleted file mode 100644 index b65b276..0000000 --- a/s390-tools-sles15-cpuplugd-Improve-systemctl-start-error-handling.patch +++ /dev/null @@ -1,202 +0,0 @@ -Subject: [PATCH] [BZ 161563] cpuplugd: Improve systemctl start error handling -From: Gerald Schaefer - -Description: cpuplugd, mon_tools: Improve systemctl start error handling -Symptom: "systemctl start cpuplugd/mon_procd/mon_fsstatd" does not - report any errors in case the startup fails. -Problem: For type=simple, systemd forks/execs the process and if that - is successful, it immediately returns. There is no way to - find out if the initial startup fails. -Solution: Use type=fork and run the process in the background. In this - case systemd waits until the initial process returns. - In addition, use PIDFile and ensure that the pid file is - already available when the initial process returns. To - achieve this, use startup synchronization via pipe. -Reproduction: Add invalid values to the config files and start the daemons - with "systemctl start cpuplugd/mon_procd/mon_fsstatd". -Upstream-ID: 82c8148983fc09e9bfa5bf852b2d39571f8475a0 -Problem-ID: 161563 - -Upstream-Description: - - cpuplugd: Improve systemctl start error handling - - Currently "systemctl start cpuplugd" does not report any errors in - case the startup fails. - - Example: - - # mv /etc/cpuplugd.conf /etc/cpuplugd.conf.xxx - # systemctl start cpuplugd - - The reason is that for type=simple systemd forks/execs cpuplugd and if - that is successful immediately returns. There is no way to find out - if the initial startup fails. - - Fix this by using type=fork and running cpuplugd in the background. In - this case systemd waits until the initial process returns. - - In addition use PIDFile and ensure that the pid file is already available - when the initial cpuplugd process returns. To achieve this, replace the - daemon() function by our own implementation that introduces startup - synchronization via pipe. Without that systemd would print the following - warning: - - systemd[1]: cpuplugd.service: PID file /var/run/cpuplugd.pid not readable - (yet?) after start: No such file or directory - - With this patch, an early startup error like in the example above, is now - reported correctly in "systemctl start": - - # systemctl start cpuplugd - Job for cpuplugd.service failed because the control process exited... - See "systemctl status cpuplugd.service" and "journalctl -xe" for ... - # journalctl -ex | grep cpuplugd - Nov 16 15:52:27 ... cpuplugd[5096]: Opening configuration file failed: - No such file or directory - - Signed-off-by: Michael Holzheu - Acked-by: Gerald Schaefer - - -Signed-off-by: Gerald Schaefer ---- - cpuplugd/cpuplugd.h | 2 - - cpuplugd/daemon.c | 60 ++++++++++++++++++++++++++++++++++++++++++-- - cpuplugd/main.c | 4 -- - systemd/cpuplugd.service.in | 5 ++- - 4 files changed, 63 insertions(+), 8 deletions(-) - ---- a/cpuplugd/cpuplugd.h -+++ b/cpuplugd/cpuplugd.h -@@ -197,10 +197,10 @@ int is_online(int cpuid); - long get_cmmpages_size(); - void parse_options(int argc, char **argv); - void check_if_started_twice(); --void store_pid(void); - void handle_signals(void); - void handle_sighup(void); - void reload_daemon(void); -+int daemonize(void); - int check_cmmfiles(void); - void check_config(); - void set_cmm_pages(long size); ---- a/cpuplugd/daemon.c -+++ b/cpuplugd/daemon.c -@@ -9,6 +9,10 @@ - * it under the terms of the MIT license. See LICENSE for details. - */ - -+#include -+#include -+#include -+ - #include "cpuplugd.h" - - const char *name = NAME; -@@ -49,7 +53,7 @@ void print_version() - /* - * Store daemon's pid so it can be stopped - */ --void store_pid(void) -+static int store_pid(void) - { - FILE *filp; - -@@ -57,10 +61,62 @@ void store_pid(void) - if (!filp) { - cpuplugd_error("cannot open pid file %s: %s\n", pid_file, - strerror(errno)); -- exit(1); -+ return -1; - } - fprintf(filp, "%d\n", getpid()); - fclose(filp); -+ return 0; -+} -+ -+/* -+ * Run daemon in background and write pid file -+ */ -+int daemonize(void) -+{ -+ int fd, pipe_fds[2], startup_rc = 1; -+ pid_t pid; -+ -+ if (pipe(pipe_fds) == -1) { -+ cpuplugd_error("cannot create pipe\n"); -+ return -1; -+ } -+ pid = fork(); -+ if (pid < 0) -+ goto close_pipe; -+ if (pid != 0) { -+ /* Wait for startup return code from daemon */ -+ if (read(pipe_fds[0], &startup_rc, sizeof(startup_rc)) == -1) -+ cpuplugd_error("cannot read from pipe\n"); -+ /* On success daemon has written pid file at this point */ -+ exit(startup_rc); -+ } -+ /* Create new session */ -+ if (setsid() < 0) -+ goto notify_parent; -+ /* Redirect stdin/out/err to /dev/null */ -+ fd = open("/dev/null", O_RDWR, 0); -+ if (fd == -1) -+ goto notify_parent; -+ if (dup2(fd, STDIN_FILENO) < 0) -+ goto notify_parent; -+ if (dup2(fd, STDOUT_FILENO) < 0) -+ goto notify_parent; -+ if (dup2(fd, STDERR_FILENO) < 0) -+ goto notify_parent; -+ /* Create pid file */ -+ if (store_pid() < 0) -+ goto notify_parent; -+ startup_rc = 0; -+notify_parent: -+ /* Inform waiting parent about startup return code */ -+ if (write(pipe_fds[1], &startup_rc, sizeof(startup_rc)) == -1) { -+ cpuplugd_error("cannot write to pipe\n"); -+ startup_rc = 1; -+ } -+close_pipe: -+ close(pipe_fds[0]); -+ close(pipe_fds[1]); -+ return startup_rc ? -1 : 0; - } - - /* ---- a/cpuplugd/main.c -+++ b/cpuplugd/main.c -@@ -418,13 +418,11 @@ int main(int argc, char *argv[]) - check_config(); - - if (!foreground) { -- rc = daemon(1, 0); -+ rc = daemonize(); - if (rc < 0) - cpuplugd_exit("Detach from terminal failed: %s\n", - strerror(errno)); - } -- /* Store daemon pid */ -- store_pid(); - /* Unlock lock file */ - flock(fd, LOCK_UN); - close(fd); ---- a/systemd/cpuplugd.service.in -+++ b/systemd/cpuplugd.service.in -@@ -13,10 +13,11 @@ Documentation=man:cpuplugd(8) man:cpuplu - After=remote-fs.target - - [Service] --ExecStart=@usrsbin_path@/cpuplugd -f -c /etc/cpuplugd.conf -+ExecStart=@usrsbin_path@/cpuplugd -c /etc/cpuplugd.conf - ExecReload=/bin/kill -HUP $MAINPID - KillMode=process --Type=simple -+Type=forking -+PIDFile=/var/run/cpuplugd.pid - - [Install] - WantedBy=multi-user.target diff --git a/s390-tools-sles15-dbginfo-add-data-for-ps-cpprot.patch b/s390-tools-sles15-dbginfo-add-data-for-ps-cpprot.patch deleted file mode 100644 index 5cb14b2..0000000 --- a/s390-tools-sles15-dbginfo-add-data-for-ps-cpprot.patch +++ /dev/null @@ -1,69 +0,0 @@ -Subject: [PATCH] [BZ 168517] dbginfo.sh: Extend data collection -From: Sa Liu - -Description: dbginfo.sh: Extend data collection -Symptom: This update covers various symptoms on dbginfo.sh data - collection: - - There is no data collected for docker. - - ps command does not show threads infomation. - - There is no run queue statistics and scheduler data. - - z/VM commands do not show multithread, protect - settings and SSI status. -Problem: Following problems exist: - - No analysis is possible for docker data. - - Missing thread information. - - Missing run queue statistics and scheduler data. - - Missing z/VM information. -Solution: - Extend the data collection to collect docker data - - Change ps command to show threads informaton - - Add commands to display run queue statistics and - scheduler data. - - Add z/VM commands to show multithread, protect settings - and SSI status. -Reproduction: Run this script and verify the output -Upstream-ID: - -Problem-ID: 168517 - -Signed-off-by: Sa Liu ---- - scripts/dbginfo.sh | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - ---- a/scripts/dbginfo.sh -+++ b/scripts/dbginfo.sh -@@ -375,7 +375,8 @@ CMDS="uname -a\ - :runlevel\ - :iptables -L\ - :ulimit -a\ -- :ps -eo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\ -+ :ps -emo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\ -+ :ps -eHo pid,tid,nlwp,policy,user,tname,ni,pri,psr,sgi_p,stat,wchan,start_time,time,pcpu,pmem,vsize,size,rss,share,command\ - :ps axX\ - :dmesg -s 1048576\ - :last\ -@@ -470,6 +471,8 @@ VM_CMDS="q userid\ - :q privclass\ - :q cplevel\ - :q cpservice\ -+ :q cpprot user\ -+ :q specex\ - :q ssi\ - :q cpus\ - :q srm\ -@@ -508,6 +511,7 @@ VM_CMDS="q userid\ - :q cache\ - :q nic\ - :q pav\ -+ :q proc\ - :q proc topology\ - :q mt\ - :q qioass\ -@@ -831,7 +835,7 @@ post_processing() { - local tmp_file - local file_name - -- pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Postprocessing" -+ pr_syslog_stdout "${COLLECTION_COUNT} of ${COLLECTION_COUNT}: Postprocessing" - - find "${WORKPATH}etc/libvirt/qemu/" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do - file_mtime_epoche=$(stat --format=%Y "${file_name}") diff --git a/s390-tools-sles15-hmcdrvfs-fix-parsing-of-link-count.patch b/s390-tools-sles15-hmcdrvfs-fix-parsing-of-link-count.patch deleted file mode 100644 index fa5d1c7..0000000 --- a/s390-tools-sles15-hmcdrvfs-fix-parsing-of-link-count.patch +++ /dev/null @@ -1,41 +0,0 @@ -Subject: [PATCH] [BZ 164881] hmcdrvfs: fix parsing of link count >= 1000 -From: Gerald Schaefer - -Description: hmcdrvfs: fix parsing of link count >= 1000 -Symptom: hmcdrvfs will ignore files with a link count >= 1000 -Problem: The parsing code relies on having spaces between the different - fields in its input data. When a file has a link count >= 1000, - there will be no space, and the "link count" field will be - placed directly after the previous "mode" field. This will - confuse the parser, and all such files will not be accesible. -Solution: The "mode" field will never contain digits, so the parser can - recognize the "link count" field by the presence of a digit. -Reproduction: Use a medium containing files with link count >= 1000 in - hmcdrvfs, and try to access/list them. -Upstream-ID: - -Problem-ID: 164881 - -Signed-off-by: Gerald Schaefer ---- - hmcdrvfs/hmcdrvfs.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - ---- a/hmcdrvfs/hmcdrvfs.c -+++ b/hmcdrvfs/hmcdrvfs.c -@@ -821,10 +821,13 @@ static char *hmcdrv_parse_line(char *lin - if ((*line != '\0') && (*line != '\n')) { - field = hmcdrv_parse_ntoken(field, line, &attr); - -- while ((*line != '\0') && -- (*line != '\n') && -- !isspace(*line)) -+ while ((*line != '\0') && (*line != '\n')) { -+ if (isspace(*line)) -+ break; -+ if (field == 1 && isdigit(*line)) -+ break; - ++line; /* search end of field */ -+ } - } - } /* while */ - diff --git a/s390-tools-sles15-iucvterm-include-ctype-for-toupper.patch b/s390-tools-sles15-iucvterm-include-ctype-for-toupper.patch deleted file mode 100644 index c229f2b..0000000 --- a/s390-tools-sles15-iucvterm-include-ctype-for-toupper.patch +++ /dev/null @@ -1,26 +0,0 @@ -From e179b7a9acdd63caacf352b37e128b5326f151cd Mon Sep 17 00:00:00 2001 -From: Hendrik Brueckner -Date: Wed, 18 Oct 2017 11:35:58 +0200 -Subject: [PATCH] iucvterm: include ctype for toupper() - -Signed-off-by: Hendrik Brueckner -Signed-off-by: Michael Holzheu ---- - iucvterm/src/getopt.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/iucvterm/src/getopt.c b/iucvterm/src/getopt.c -index 503f6dd..b79b6a9 100644 ---- a/iucvterm/src/getopt.c -+++ b/iucvterm/src/getopt.c -@@ -8,6 +8,7 @@ - * 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 - #include - #include - #include --- -1.7.12.4 - diff --git a/s390-tools-sles15-lsluns-clarify-discovery-use-case-relation-to-NPIV-a.patch b/s390-tools-sles15-lsluns-clarify-discovery-use-case-relation-to-NPIV-a.patch deleted file mode 100644 index 300a26a..0000000 --- a/s390-tools-sles15-lsluns-clarify-discovery-use-case-relation-to-NPIV-a.patch +++ /dev/null @@ -1,110 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: clarify discovery use case, relation to NPIV and to zfcp auto LUN scan -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: 0daa7ba0b558ff22fa1c1e014e754cbd08366c00 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: clarify discovery use case, relation to NPIV and to zfcp auto LUN scan - - Signed-off-by: Steffen Maier - Reviewed-by: Jens Remus - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 3 +++ - zconf/lsluns.8 | 18 ++++++++++++++++++ - 2 files changed, 21 insertions(+) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -174,6 +174,9 @@ $PROGRAM_NAME [-c ] ... [-p ] ... [-p ] ... [-h] [-v] - ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -46,6 +46,24 @@ encryption, use other tools such as - or - .BR "lsscsi \-tv" . - -+.SS Details on lsluns without -a option -+ -+.TP -+Prerequisite -+Discovering LUNs only makes sense for NPIV-enabled FCP devices -+without zfcp automatic LUN scan. zfcp automatic LUN scan is available -+as of kernel version 2.6.37, if not disabled with zfcp.allow_lun_scan=0. -+ -+With available and enabled zfcp automatic LUN scan, -+the kernel already performs LUN discovery. -+ -+.TP -+Temporary LUN Attachment -+If not attached already, lsluns temporarily attaches LUN 0 -+(or if this fails the WLUN 0xc101000000000000) during runtime. -+Do not terminate lsluns with a signal. Signals interfere -+with the removal of temporarily attached LUNs. -+ - .SH OPTIONS - .TP - .BR \-a ", " \-\-active diff --git a/s390-tools-sles15-lsluns-complement-alternative-tools-with-lszdev.patch b/s390-tools-sles15-lsluns-complement-alternative-tools-with-lszdev.patch deleted file mode 100644 index 6965302..0000000 --- a/s390-tools-sles15-lsluns-complement-alternative-tools-with-lszdev.patch +++ /dev/null @@ -1,104 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: complement alternative tools with lszdev -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: e5f9279295780bd297f58cc23319878fadbc80f1 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: complement alternative tools with lszdev - - Signed-off-by: Steffen Maier - Reviewed-by: Benjamin Block - Reviewed-by: Jens Remus - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 3 ++- - zconf/lsluns.8 | 7 +++++-- - 2 files changed, 7 insertions(+), 3 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -192,7 +192,8 @@ $PROGRAM_NAME -a [-c ] ... [-p - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: c993ad89c544dd162005a9a1e582b51667c46b66 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: do not print confusing messages when a filter matches nothing - - lsluns printed potentially confusing messages when a filter or combination - of filters matched nothing: - - No valid combination found for adapter '0.0.1906'. Removing from - resource list. - No valid combination found for port '0x50050763071845e3'. Removing from - resource list. - ... - - To the user it is potentially unclear which 'combination' is actually being - referred to, as only one part of the combination is mentioned, and what the - ominous 'resource list' is. The later information is merely useful for a - developer to debug the script. - - Such a message was written for every user supplied filter that did not - contribute anything to the resulting subset that is being listed, although - the filter actually might match something when used standalone. - - Additionally those messages were printed to stdout instead of stderr. As - there is no debug or verbose switch and the information level of those - messages is low, we may simply discard them. - - Reported-by: Steffen Maier - Signed-off-by: Jens Remus - Reviewed-by: Steffen Maier - Reviewed-by: Benjamin Block - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 15 --------------- - 1 file changed, 15 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -215,7 +215,6 @@ sub get_env_list - my $p_ref_list = shift(); - my @res ; - my %res_hash; -- my @t_arr; - - @res = ; - return () if (!@res); -@@ -226,20 +225,6 @@ sub get_env_list - next if (@$p_ref_list && "@$p_ref_list" !~ /$p/); - push @{ $res_hash{$a} }, $p; - } -- foreach my $a (sort @$a_ref_list) { -- if ("@{[keys %res_hash]}" !~ /$a/) { -- print "\tNo valid combination found for adapter '$a'. ", -- "Removing from resource list.\n"; -- } -- } -- -- push @t_arr, map { @{$res_hash{$_}} } keys %res_hash; -- foreach my $p (@$p_ref_list) { -- if ("@t_arr" !~ /$p/) { -- print "\tNo valid combination found for port '$p'. ", -- "Removing from resource list.\n"; -- } -- } - - if (!%res_hash) { - print "$PROGRAM_NAME: Adapter and/or port filter(s) did not match anything\n"; diff --git a/s390-tools-sles15-lsluns-do-not-scan-all-if-filters-match-nothing.patch b/s390-tools-sles15-lsluns-do-not-scan-all-if-filters-match-nothing.patch deleted file mode 100644 index 7823c5e..0000000 --- a/s390-tools-sles15-lsluns-do-not-scan-all-if-filters-match-nothing.patch +++ /dev/null @@ -1,111 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: do not scan (all) if filters match nothing -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: 398f9ceac8c20705f573671bde4bc482967f5c13 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: do not scan (all) if filters match nothing - - Fix the following undesired behavior of lsluns to scan all resources if the - user provided filters did not match anything: - - No valid combination found for adapter '5080'. Removing from resource - list. - No valid parameters left, using all available resources in system. - Scanning for LUNs on adapter 0.0.5080 - ... - - Scanning can be resource consumptive. So if a user already wants to filter, - possibly to reduce resource consumption, he does not want to happen to scan - everything and thus consume the worst case of resources. - - Instead print a message to inform the user why nothing was scanned. - - Reported-by: Steffen Maier - Signed-off-by: Jens Remus - Reviewed-by: Steffen Maier - Reviewed-by: Benjamin Block - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 8 +------- - 1 file changed, 1 insertion(+), 7 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -219,7 +219,6 @@ sub get_env_list - - @res = ; - return () if (!@res); --reload: - foreach my $entry (@res) { - my $a = ${[split('/', $entry)]}[-2]; - my $p = ${[split('/', $entry)]}[-1]; -@@ -243,12 +242,7 @@ reload: - } - - if (!%res_hash) { -- print "\nNo valid parameters left, ", -- "using all available resources in system.\n\n"; -- @$a_ref_list = (); -- @$p_ref_list = (); -- @t_arr = (); -- goto reload; -+ print "$PROGRAM_NAME: Adapter and/or port filter(s) did not match anything\n"; - } - return %res_hash; - } diff --git a/s390-tools-sles15-lsluns-document-restriction-to-zfcp-only-systems.patch b/s390-tools-sles15-lsluns-document-restriction-to-zfcp-only-systems.patch deleted file mode 100644 index 10db92b..0000000 --- a/s390-tools-sles15-lsluns-document-restriction-to-zfcp-only-systems.patch +++ /dev/null @@ -1,108 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: document restriction to zfcp-only systems -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: 55f0b001d15b3984967e7f87d6118232078e3fe5 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: document restriction to zfcp-only systems - - Signed-off-by: Steffen Maier - Reviewed-by: Jens Remus - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 4 ++++ - zconf/lsluns.8 | 8 ++++++-- - 2 files changed, 10 insertions(+), 2 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -170,6 +170,10 @@ sub get_lun_hash - sub lsluns_usage { - print <] ... [-p ] ... [-h] [-v] - - List LUNs discovered in the Fibre Channel (FC) Storage Area Network (SAN). ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -4,8 +4,8 @@ - .\" - .TH LSLUNS 8 "2017-02-17" "s390-tools" - .SH NAME --lsluns \- list LUNs discovered in the FC SAN, or show encryption state of --attached LUNs -+lsluns \- list LUNs discovered in the FC SAN through zfcp, or show encryption state of -+zfcp-attached LUNs - - .SH SYNOPSIS - .B lsluns -@@ -28,6 +28,10 @@ attached LUNs - - .SH DESCRIPTION - .PP -+This tool is designed for environments where all SCSI devices are attached -+through the zfcp device driver. Expect error messages in mixed environments -+such as with iSCSI. -+ - .B lsluns - lists all logical unit numbers (LUNs) discovered in the - Fibre Channel (FC) Storage Area Network (SAN). diff --git a/s390-tools-sles15-lsluns-enhance-usage-statement-and-man-page.patch b/s390-tools-sles15-lsluns-enhance-usage-statement-and-man-page.patch deleted file mode 100644 index aa1b14e..0000000 --- a/s390-tools-sles15-lsluns-enhance-usage-statement-and-man-page.patch +++ /dev/null @@ -1,283 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: enhance usage statement and man page -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: e748fff3479f8f4ae7e8262b4913f6d08ff78f66 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: enhance usage statement and man page - - The wording in the lsluns usage statement and man page was misleading - in several aspects: - - * lsluns does not list all LUNs, just those discovered in the FC SAN - * lsluns -a should only be used to display the LUN encryption status - - Fix filter option arguments. Clarify filter option usage. Refer to - lszfcp and lsscsi. - - Reported-by: Steffen Maier - Signed-off-by: Jens Remus - Reviewed-by: Steffen Maier - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 45 +++++++++++++++------------ - zconf/lsluns.8 | 93 +++++++++++++++++++++++++++++++++++++++------------------ - 2 files changed, 91 insertions(+), 47 deletions(-) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -1,6 +1,6 @@ - #!/usr/bin/perl - # --# lsluns - Tool to list all available LUNs -+# lsluns - list LUNs discovered in the FC SAN, or show encryption state of attached LUNs - # - # Copyright IBM Corp. 2008, 2017 - # -@@ -169,32 +169,39 @@ sub get_lun_hash - - sub lsluns_usage { - print <] -+Usage: -+$PROGRAM_NAME [-c ] ... [-p ] ... [-h] [-v] - -- lsluns provides information for LUNs. -+ List LUNs discovered in the Fibre Channel (FC) Storage Area Network (SAN). -+ This causes extra SAN traffic for each target port WWPN. - -- The default is to list all LUNs that are available via the attached ports. -- The display can be limited by specifying an adapter or a port. -+$PROGRAM_NAME -a [-c ] ... [-p ] ... [-h] [-v] -+ -+ Show encryption state of the attached LUNs. -+ This causes extra SAN traffic for each attached LUN. -+ -+For all other uses, such as listing attached LUNs or properties other than -+encryption, use other tools such as "lszfcp -D" or "lsscsi -tv". -+ -+Limit the listing by specifying one or more adapters (FCP device -+bus-IDs) or target port WWPNs or both. - - Options: -- -a, --active -- Shows all activated LUNs. -- In addition LUN encryption information is provided. -- e.g. "lsluns -a" -- -- -c, --ccw -- Shows LUNs for a specific ccw device. -- e.g. "lsluns -c 0.0.3922" -- -- -p, --port -- Shows LUNs for a specific port. -- e.g. "lsluns -p 0x5005123456789000" -+ -c , --ccw -+ Filter LUNs by adapter with the specified FCP device bus-ID. Can be -+ specified multiple times. -+ For example: "$PROGRAM_NAME -c 0.0.3922" -+ -+ -p , --port -+ Filter LUNs by target port with the specified WWPN. Can be specified -+ multiple times. -+ For example: "$PROGRAM_NAME -p 0x5005123456789000" - - -h, --help -- Print help message and exit. -+ Print help message and exit. - - -v, --version -- Display version info and exit. -+ Display version information and exit. - EOD - exit 0; - } ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -2,61 +2,93 @@ - .\" s390-tools is free software; you can redistribute it and/or modify - .\" it under the terms of the MIT license. See LICENSE for details. - .\" --.TH LSLUNS 8 "June 2008" "s390-tools" -+.TH LSLUNS 8 "2017-02-17" "s390-tools" - .SH NAME --lsluns \- list available LUNs -+lsluns \- list LUNs discovered in the FC SAN, or show encryption state of -+attached LUNs - - .SH SYNOPSIS - .B lsluns -+.RB [\| \-c -+.IR busid \|]\ .\|.\|. -+.RB [\| \-p -+.IR wwpn \|]\ .\|.\|. -+.\" --active -+.br -+.B lsluns \-a -+.RB [\| \-c -+.IR busid \|]\ .\|.\|. -+.RB [\| \-p -+.IR wwpn \|]\ .\|.\|. -+.\" --help and --version -+.br -+.B lsluns - .RB [\| \-h \|] - .RB [\| \-v \|] --.RB [\| \-c --.IR adapter\ id:0.0.XXXX \|]\ .\|.\|. --.RB [ \-p --.IR port\ number:0xXXXXXXXXXXXXXXXX \|]\ .\|.\|. - - .SH DESCRIPTION - .PP - .B lsluns --does a listing of all available LUNs. -- --The default is to list all LUNs that are found. The listing can be --limited by specifying an adapter or a port. -+lists all logical unit numbers (LUNs) discovered in the -+Fibre Channel (FC) Storage Area Network (SAN). -+This causes extra SAN traffic for each target port WWPN. -+ -+.B lsluns -a -+shows the encryption state of the attached LUNs. -+This causes extra SAN traffic for each attached LUN. -+ -+Limit the listing by specifying one or more adapters (FCP device -+bus-IDs) or target port WWPNs or both. -+ -+For all other uses, such as listing attached LUNs or properties other than -+encryption, use other tools such as -+.B lszfcp \-D -+or -+.BR "lsscsi \-tv" . - - .SH OPTIONS - .TP -+.BR \-a ", " \-\-active -+Show the encryption state of the attached LUNs. Encrypted devices are indicated -+with a bracketed X immediately following the LUN number. -+.TP -+.BI \-c\ busid \fR,\ \fB\-\-ccw= busid -+Filter LUNs by adapter with the specified FCP device bus-ID. This option can be -+specified multiple times. When used in conjunction with \fB\-p\fR, only those -+LUNs are listed that also satisfy at least one of the \fB\-p\fR constraints. -+.TP -+.BI \-p\ wwpn \fR,\ \fB\-\-port= wwpn -+Filter LUNs by target port with the specified WWPN. This option can be -+specified multiple times. When used in conjunction with \fB\-c\fR, only those -+LUNs are listed that also satisfy at least one of the \fB\-c\fR constraints. -+.TP - .BR \-h ", " \-\-help - Print help message and exit. - .TP - .BR \-v ", " \-\-version --Display version info and exit. --.TP --.BI \-c\ adapter \fR,\ \fB\-\-ccw= adapter --Shows LUNs for a specific adapter. --.TP --.BI \-p\ port \fR,\ \fB\-\-port= port --Shows LUNs for a specific port. --.TP --.BR \-a ", " \-\-active --Shows all activated LUNs. In addition information is provided --whether the LUN is encrypted or not. This is indicated with a bracketed X --right after the LUN number. -+Display version information and exit. - - .SH EXAMPLES - .TP - .B "lsluns" - .RS --Shows all available LUNs. -+Lists all LUNs discovered in the FC SAN. - .RE - .TP - .BI "lsluns \-c " 0.0.3922 --Shows all LUNs found on adapter \fI0.0.3922\fR. -+Lists all LUNs discovered in the FC SAN on adapter \fI0.0.3922\fR. - .TP - .BI "lsluns \-p " 0x5005123456789000 --Shows all LUNs for port \fI0x5005123456789000\fR. -+Lists all LUNs discovered in the FC SAN on target port -+\fI0x5005123456789000\fR. - .TP --.BI "lsluns \-c " 0.0.3922 " \-p " 0x5005123456789000 --Shows all LUNs for adapter \fI0.0.3922\fR and port \fI0x5005123456789000\fR. -+.BI "lsluns \-c " 0.0.3922 " \-c " 0.0.fc00 \ -+" \-p " 0x5005123456789000 " \-p " 0x5005abcdefabc000 -+Lists all LUNs discovered in the FC SAN on: -+adpater \fI0.0.3922\fR and port \fI0x5005123456789000\fR, -+adapter \fI0.0.3922\fR and port \fI0x5005abcdefabc000\fR, -+adapter \fI0.0.fc00\fR and port \fI0x5005123456789000\fR, or -+adapter \fI0.0.fc00\fR and port \fI0x5005abcdefabc000\fR. - .TP - .B "lsluns -a" - adapter = 0.0.3c02 -@@ -64,4 +96,9 @@ adapter = 0.0.3c02 - lun = 0x401040a200000000(X) /dev/sg0 Disk IBM:2107900 - lun = 0x401040a300000000 /dev/sg1 Disk IBM:2107900 - --Shows all active LUNs including the information whether the device is encrypted or not. -+Shows the encryption status of attached LUNs. A bracketed X suffixed to a LUN -+indicates that the device is encrypted. -+ -+.SH "SEE ALSO" -+.BR lszfcp (8), -+.BR lsscsi (8) diff --git a/s390-tools-sles15-lsluns-fix-flawed-formatting-of-man-page.patch b/s390-tools-sles15-lsluns-fix-flawed-formatting-of-man-page.patch deleted file mode 100644 index 42e89b7..0000000 --- a/s390-tools-sles15-lsluns-fix-flawed-formatting-of-man-page.patch +++ /dev/null @@ -1,170 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: fix flawed formatting of man page -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: d81c4234295f481559a74fb5ad5f498692ff5738 -Problem-ID: 161888 - -Upstream-Description: - - lsluns: fix flawed formatting of man page - - The formatting in the SYNOPSIS, OPTIONS, and EXAMPLES sections was flawed - in the lsluns(8) man page: - - * The comma between short and long options were erroneously formatted in - bold, which would indicate to be typed exactly as shown. [see man(1)] - - * The option parameters (e.g. adapter and port) were erroneously formatted - in bold instead of italic text (usually displayed as underlined on the - console), which would again indicate to be typed exactly as shown instead - of to be replaced with the appropriate argument. [see man(1)] - - * Ellipses were missing after the the options that may be specified multiple - times (e.g. adapter and port). [see man(1)] - - * Dashes in options in the SYNOPSIS and OPTIONS section needed to be - escaped. [see man-pages(7)] - - * User input in example shell sessions should have been formatted in bold. - [see man-pages(7)] - - Correct formatting based on man(7) and man-pages(7) man pages as reference. - Add proper spacing between options and their surrounding square brackets and - between the three periods of ellipses. - - Signed-off-by: Jens Remus - Reviewed-by: Steffen Maier - Reviewed-by: Benjamin Block - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns.8 | 42 +++++++++++++++++++++++------------------- - 1 file changed, 23 insertions(+), 19 deletions(-) - ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -8,12 +8,12 @@ lsluns \- list available LUNs - - .SH SYNOPSIS - .B lsluns --.RB [ \-h] --.RB [ \-v] --.RB [ \-c --.IR adapter id:0.0.XXXX ] -+.RB [\| \-h \|] -+.RB [\| \-v \|] -+.RB [\| \-c -+.IR adapter\ id:0.0.XXXX \|]\ .\|.\|. - .RB [ \-p --.IR port number:0xXXXXXXXXXXXXXXXX ] -+.IR port\ number:0xXXXXXXXXXXXXXXXX \|]\ .\|.\|. - - .SH DESCRIPTION - .PP -@@ -25,36 +25,40 @@ limited by specifying an adapter or a po - - .SH OPTIONS - .TP --.B -h, --help -+.BR \-h ", " \-\-help - Print help message and exit. - .TP --.B -v, --version -+.BR \-v ", " \-\-version - Display version info and exit. - .TP --.B -c, --ccw -+.BI \-c\ adapter \fR,\ \fB\-\-ccw= adapter - Shows LUNs for a specific adapter. - .TP --.B -p, --port -+.BI \-p\ port \fR,\ \fB\-\-port= port - Shows LUNs for a specific port. - .TP --.B -a, --active -+.BR \-a ", " \-\-active - Shows all activated LUNs. In addition information is provided - whether the LUN is encrypted or not. This is indicated with a bracketed X - right after the LUN number. - - .SH EXAMPLES --.PP --.IP "lsluns" -+.TP -+.B "lsluns" - .RS - Shows all available LUNs. - .RE --.IP "lsluns -c 0.0.3922" --Shows all LUNs found on adapter 0.0.3922. --.IP "lsluns -p 0x5005123456789000" --Shows all LUNs for port 0x5005123456789000. --.IP "lsluns -c 0.0.3922 -p 0x5005123456789000" --Shows all LUNs for adapter 0.0.3922 and port 0x5005123456789000. --.IP "lsluns -a " -+.TP -+.BI "lsluns \-c " 0.0.3922 -+Shows all LUNs found on adapter \fI0.0.3922\fR. -+.TP -+.BI "lsluns \-p " 0x5005123456789000 -+Shows all LUNs for port \fI0x5005123456789000\fR. -+.TP -+.BI "lsluns \-c " 0.0.3922 " \-p " 0x5005123456789000 -+Shows all LUNs for adapter \fI0.0.3922\fR and port \fI0x5005123456789000\fR. -+.TP -+.B "lsluns -a" - adapter = 0.0.3c02 - port = 0x500507630300c562 - lun = 0x401040a200000000(X) /dev/sg0 Disk IBM:2107900 diff --git a/s390-tools-sles15-lsluns-point-out-IBM-Storwize-configuration-requirem.patch b/s390-tools-sles15-lsluns-point-out-IBM-Storwize-configuration-requirem.patch deleted file mode 100644 index 5144b6d..0000000 --- a/s390-tools-sles15-lsluns-point-out-IBM-Storwize-configuration-requirem.patch +++ /dev/null @@ -1,105 +0,0 @@ -Subject: [PATCH] [BZ 161888] lsluns: point out IBM Storwize configuration requirements -From: Jens Remus - -Description: lsluns: Fix filter handling and documentation enhancements. -Symptom: lsluns lists all LUNs discovered in the FC SAN despite user - given filter(s) that do not match anything: - # lsluns -c 0.0.5080 - No valid combination found for adapter '0.0.5080'. Removing - from resource list. - No valid parameters left, using all available resources in - system. - Scanning for LUNs on adapter 0.0.5090 - ... - - lsluns prints the message "No valid combination found for - {adapter|port} '...'. Removing from resource list." for every - adapter and port filter that does not contribute to the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - lsluns is used in unexpected or even unsupported ways. -Problem: Scanning can be resource consumptive. So if a user already wants - to filter, possibly to reduce resource consumption, he does not - want to happen to scan everything and thus consume the worst case - of resources. - - The message "No valid combination found for {adapter|port} '...'. - Removing from resource list." is potentially confusing. It is - unclear which combination is being referred to, especially if - only one single adapter or port filter was specified. There is - also no differentiation whether the denoted adapter or port - exists for its own or not. It just does not exist in the final - filtered results. - - The formatting of the lsluns (8) man page is flawed. - - The lsluns usage text and lsluns (8) man page lack the - information on the intended use cases, requirements, and - restrictions. -Solution: Print a message and exit when all filters match nothing. - - Do not print confusing messages when a filter matches nothing. - - Fix man page formatting. - - Enhance usage text and man page. Clarify discovery use case, - relation to NPIV and to zfcp auto LUN scan. Point out - IBM Storwize configuration requirements. Document restriction to - zfcp-only systems. -Reproduction: Use lsluns and specify adapter bus-ID and/or target port WWPN - filter(s) that do not match anything. Either specify inexistent - bus-IDs and/or WWPNs or invalid filter arguments. -Upstream-ID: 5f768dd52d87efddbd7efa23d57c6da62281728b -Problem-ID: 161888 - -Upstream-Description: - - lsluns: point out IBM Storwize configuration requirements - - Signed-off-by: Steffen Maier - Reviewed-by: Jens Remus - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jens Remus ---- - zconf/lsluns | 4 ++++ - zconf/lsluns.8 | 12 ++++++++++++ - 2 files changed, 16 insertions(+) - ---- a/zconf/lsluns -+++ b/zconf/lsluns -@@ -177,6 +177,10 @@ $PROGRAM_NAME [-c ] ... [-p ] ... [-p ] ... [-h] [-v] - ---- a/zconf/lsluns.8 -+++ b/zconf/lsluns.8 -@@ -64,6 +64,18 @@ If not attached already, lsluns temporar - Do not terminate lsluns with a signal. Signals interfere - with the removal of temporarily attached LUNs. - -+.TP -+Storage Products -+Some storage products return a peripheral device type of 31==0x1f -+with peripheral qualifier 0 in a SCSI standard INQUIRY command -+for an unmapped FCP LUN 0. Examples are: IBM Storwize products, -+including IBM V7000, IBM V840, IBM V9000, and IBM SAN Volume Controller. -+For lsluns to work with such storage products, -+you must have a host mapping on the storage, which maps some volume -+to exported FCP LUN 0x0000000000000000 (Storwize host map property "SCSI ID" 0) -+for each used FCP-device initiator WWPN. The volume can be -+a minimum-sized thin-provisioned shared stand-in volume. -+ - .SH OPTIONS - .TP - .BR \-a ", " \-\-active diff --git a/s390-tools-sles15-mon_procd-fix-parsing-of-proc-pid-stat.patch b/s390-tools-sles15-mon_procd-fix-parsing-of-proc-pid-stat.patch deleted file mode 100644 index 36abbcd..0000000 --- a/s390-tools-sles15-mon_procd-fix-parsing-of-proc-pid-stat.patch +++ /dev/null @@ -1,71 +0,0 @@ -Subject: mon_procd: fix parsing of /proc//stat -From: Gerald Schaefer - -Description: mon_procd: fix parsing of /proc//stat -Symptom: Wrong data from /proc//stat for processes that contain - a ")" in their name. -Problem: The output of /proc//stat will show the process name in - parentheses. The parsing code in read_stat() tries to filter - out the parentheses, which will go wrong when the process name - itself also contains parentheses, e.g. in an output like this: - "2421 ((sd-pam)) S 2420 2420 2420 ..." - In this case, the first closing parentheses will be taken as - end marker, and the sscanf() on the remaining string will - silently fail, leaving its values in uninitialized state and - producing wrong data. -Solution: Use strrchr() instead of strchr() to find the last closing - parentheses. Also add return value checking for sscanf() and - initialize the values to 0. -Reproduction: Use mon_procd on a system with running processes that have a - ")" in their name, like "(sd-pam)". -Upstream-ID: - -Problem-ID: 169483 - -Signed-off-by: Gerald Schaefer ---- - mon_tools/mon_procd.c | 13 ++++++++----- - 1 file changed, 8 insertions(+), 5 deletions(-) - ---- a/mon_tools/mon_procd.c -+++ b/mon_tools/mon_procd.c -@@ -594,17 +594,18 @@ static void cal_task_pcpu(struct task_t - */ - static int read_stat(struct task_t *task) - { -- int ppid, tty, proc; -- unsigned long flags, pri, nice; -- unsigned long long maj_flt, utime, stime, cutime, cstime; -+ unsigned long long maj_flt = 0, utime = 0, stime = 0, cutime = 0, -+ cstime = 0; -+ unsigned long flags = 0, pri = 0, nice = 0; - char *cmd_start, *cmd_end, *cmdlenp, *cmdp; -+ int ppid = 0, tty = 0, proc = 0, rc; - - snprintf(fname, sizeof(fname), "/proc/%u/stat", task->pid); - if (read_file(fname, buf, sizeof(buf) - 1) == -1) - return 0; - - cmd_start = strchr(buf, '(') + 1; -- cmd_end = strchr(cmd_start, ')'); -+ cmd_end = strrchr(cmd_start, ')'); - name_lens.cmd_len = cmd_end - cmd_start; - cmdlenp = mon_record + sizeof(struct monwrite_hdr); - cmdlenp += sizeof(struct procd_hdr); -@@ -625,7 +626,7 @@ static int read_stat(struct task_t *task - memcpy(cmdlenp, &name_lens.cmd_len, sizeof(__u16)); - - cmd_end += 2; -- sscanf(cmd_end, -+ rc = sscanf(cmd_end, - "%c %d %*d %*d %d %*d " - "%lu %*s %*s %Lu %*s " - "%Lu %Lu %Lu %Lu " -@@ -642,6 +643,8 @@ static int read_stat(struct task_t *task - &utime, &stime, &cutime, &cstime, - &pri, &nice, - &proc); -+ if (rc != 12) -+ syslog(LOG_ERR, "bad data in %s \n", fname); - task->ppid = (__u32)ppid; - task->tty = (__u16)tty; - task->flags = (__u32)flags; diff --git a/s390-tools-sles15-mon_tools-Improve-systemctl-start-error-handling.patch b/s390-tools-sles15-mon_tools-Improve-systemctl-start-error-handling.patch deleted file mode 100644 index b450f9d..0000000 --- a/s390-tools-sles15-mon_tools-Improve-systemctl-start-error-handling.patch +++ /dev/null @@ -1,290 +0,0 @@ -Subject: [PATCH] [BZ 161563] mon_tools: Improve systemctl start error handling -From: Gerald Schaefer - -Description: cpuplugd, mon_tools: Improve systemctl start error handling -Symptom: "systemctl start cpuplugd/mon_procd/mon_fsstatd" does not - report any errors in case the startup fails. -Problem: For type=simple, systemd forks/execs the process and if that - is successful, it immediately returns. There is no way to - find out if the initial startup fails. -Solution: Use type=fork and run the process in the background. In this - case systemd waits until the initial process returns. - In addition, use PIDFile and ensure that the pid file is - already available when the initial process returns. To - achieve this, use startup synchronization via pipe. -Reproduction: Add invalid values to the config files and start the daemons - with "systemctl start cpuplugd/mon_procd/mon_fsstatd". -Upstream-ID: 780133f825687bc931489aaf13959c793d2a4501 -Problem-ID: 161563 - -Upstream-Description: - - mon_tools: Improve systemctl start error handling - - This fixes the same issue as in commit 82c8148983fc ("cpuplugd: Improve - systemctl start error handling") for mon_tools (mon_procd and mon_fsstatd). - - Currently "systemctl start mon_procd/fsstatd" does not report any errors - in case the startup fails. - - Example (with mon_procd): - - (change interval in /etc/sysconfig/mon_procd to an invalid value "abc") - # systemctl start mon_procd - - The reason is that for type=simple systemd forks/execs mon_procd and if - that is successful immediately returns. There is no way to find out if the - initial startup fails. - - Fix this by using type=fork and running the process in the background. In - this case systemd waits until the initial process returns. - - In addition use PIDFile and ensure that the pid file is already available - when the initial process returns. To achieve this, use startup - synchronization via pipe. Without that systemd would print the following - warning: - - systemd[1]: mon_procd.service: PID file /var/run/mon_procd.pid not readable - (yet?) after start: No such file or directory - - With this patch, an early startup error like in the example above, is now - reported correctly in "systemctl start": - - # systemctl start mon_procd - Job for mon_procd.service failed because the control process exited... - See "systemctl status mon_procd.service" and "journalctl -xe" for ... - # journalctl -xe | grep mon_procd - mon_procd[3184]: Error: Invalid interval (needs to be greater than 0) - - Signed-off-by: Gerald Schaefer - Signed-off-by: Michael Holzheu - - -Signed-off-by: Gerald Schaefer ---- - mon_tools/mon_fsstatd.c | 40 ++++++++++++++++++++++++++++++++-------- - mon_tools/mon_procd.c | 40 ++++++++++++++++++++++++++++++++-------- - systemd/mon_fsstatd.service.in | 5 +++-- - systemd/mon_procd.service.in | 5 +++-- - 4 files changed, 70 insertions(+), 20 deletions(-) - ---- a/mon_tools/mon_fsstatd.c -+++ b/mon_tools/mon_fsstatd.c -@@ -90,17 +90,18 @@ static void fsstatd_open_monwriter(void) - /* - * Store daemon's pid so it can be stopped - */ --static void store_pid(void) -+static int store_pid(void) - { - FILE *f = fopen(pid_file, "w"); - - if (!f) { - syslog(LOG_ERR, "cannot open pid file %s: %s", pid_file, - strerror(errno)); -- exit(1); -+ return -1; - } - fprintf(f, "%d\n", getpid()); - fclose(f); -+ return 0; - } - - /* -@@ -244,41 +245,64 @@ static void fsstatd_write_ent(struct mnt - */ - static void fsstatd_daemonize(void) - { -+ int pipe_fds[2], startup_rc = 1; - pid_t pid; - -+ if (pipe(pipe_fds) == -1) { -+ syslog(LOG_ERR, "pipe error: %s\n", strerror(errno)); -+ exit(1); -+ } -+ - /* Fork off the parent process */ - pid = fork(); - if (pid < 0) { - syslog(LOG_ERR, "fork error: %s\n", strerror(errno)); - exit(1); - } -- if (pid > 0) -- exit(0); -+ if (pid > 0) { -+ /* Wait for startup return code from daemon */ -+ if (read(pipe_fds[0], &startup_rc, sizeof(startup_rc)) == -1) -+ syslog(LOG_ERR, "pipe read error: %s\n", strerror(errno)); -+ /* With startup_rc == 0, pid file was written at this point */ -+ exit(startup_rc); -+ } - - /* Change the file mode mask */ - umask(0); - -- /* Store daemon pid */ -- store_pid(); - /* Catch SIGINT and SIGTERM to clean up pid file on exit */ - fsstatd_handle_signals(); - - /* Create a new SID for the child process */ - if (setsid() < 0) { - syslog(LOG_ERR, "setsid error: %s\n", strerror(errno)); -- exit(1); -+ goto notify_parent; - } - - /* Change the current working directory */ - if (chdir("/") < 0) { - syslog(LOG_ERR, "chdir error: %s\n", strerror(errno)); -- exit(1); -+ goto notify_parent; - } - - /* Close out the standard file descriptors */ - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); -+ -+ /* Store daemon pid */ -+ if (store_pid() < 0) -+ goto notify_parent; -+ startup_rc = 0; -+ -+notify_parent: -+ /* Inform waiting parent about startup return code */ -+ if (write(pipe_fds[1], &startup_rc, sizeof(startup_rc)) == -1) { -+ syslog(LOG_ERR, "pipe write error: %s\n", strerror(errno)); -+ exit(1); -+ } -+ if (startup_rc != 0) -+ exit(startup_rc); - } - - static int fsstatd_do_work(void) ---- a/mon_tools/mon_procd.c -+++ b/mon_tools/mon_procd.c -@@ -109,17 +109,18 @@ static void procd_open_monwriter(void) - /* - * Store daemon's pid so it can be stopped - */ --static void store_pid(void) -+static int store_pid(void) - { - FILE *f = fopen(pid_file, "w"); - - if (!f) { - syslog(LOG_ERR, "cannot open pid file %s: %s", pid_file, - strerror(errno)); -- exit(1); -+ return -1; - } - fprintf(f, "%d\n", getpid()); - fclose(f); -+ return 0; - } - - /* -@@ -897,41 +898,64 @@ static void read_tasks(void) - */ - static void procd_daemonize(void) - { -+ int pipe_fds[2], startup_rc = 1; - pid_t pid; - -+ if (pipe(pipe_fds) == -1) { -+ syslog(LOG_ERR, "pipe error: %s\n", strerror(errno)); -+ exit(1); -+ } -+ - /* Fork off the parent process */ - pid = fork(); - if (pid < 0) { - syslog(LOG_ERR, "fork error: %s\n", strerror(errno)); - exit(1); - } -- if (pid > 0) -- exit(0); -+ if (pid > 0) { -+ /* Wait for startup return code from daemon */ -+ if (read(pipe_fds[0], &startup_rc, sizeof(startup_rc)) == -1) -+ syslog(LOG_ERR, "pipe read error: %s\n", strerror(errno)); -+ /* With startup_rc == 0, pid file was written at this point */ -+ exit(startup_rc); -+ } - - /* Change the file mode mask */ - umask(0); - -- /* Store daemon pid */ -- store_pid(); - /* Catch SIGINT and SIGTERM to clean up pid file on exit */ - procd_handle_signals(); - - /* Create a new SID for the child process */ - if (setsid() < 0) { - syslog(LOG_ERR, "setsid error: %s\n", strerror(errno)); -- exit(1); -+ goto notify_parent; - } - - /* Change the current working directory */ - if (chdir("/") < 0) { - syslog(LOG_ERR, "chdir error: %s\n", strerror(errno)); -- exit(1); -+ goto notify_parent; - } - - /* Close out the standard file descriptors */ - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); -+ -+ /* Store daemon pid */ -+ if (store_pid() < 0) -+ goto notify_parent; -+ startup_rc = 0; -+ -+notify_parent: -+ /* Inform waiting parent about startup return code */ -+ if (write(pipe_fds[1], &startup_rc, sizeof(startup_rc)) == -1) { -+ syslog(LOG_ERR, "pipe write error: %s\n", strerror(errno)); -+ exit(1); -+ } -+ if (startup_rc != 0) -+ exit(startup_rc); - } - - static int procd_do_work(void) ---- a/systemd/mon_fsstatd.service.in -+++ b/systemd/mon_fsstatd.service.in -@@ -30,10 +30,11 @@ EnvironmentFile=/etc/sysconfig/mon_fssta - - ExecStartPre=-/sbin/modprobe monwriter - ExecStartPre=/sbin/udevadm settle --timeout=10 --ExecStart=@usrsbin_path@/mon_fsstatd -a -i $FSSTAT_INTERVAL -+ExecStart=@usrsbin_path@/mon_fsstatd -i $FSSTAT_INTERVAL - ExecReload=/bin/kill -HUP $MAINPID - KillMode=process --Type=simple -+Type=forking -+PIDFile=/var/run/mon_fsstatd.pid - - [Install] - WantedBy=multi-user.target ---- a/systemd/mon_procd.service.in -+++ b/systemd/mon_procd.service.in -@@ -30,10 +30,11 @@ EnvironmentFile=/etc/sysconfig/mon_procd - - ExecStartPre=-/sbin/modprobe monwriter - ExecStartPre=/sbin/udevadm settle --timeout=10 --ExecStart=@usrsbin_path@/mon_procd -a -i $PROC_INTERVAL -+ExecStart=@usrsbin_path@/mon_procd -i $PROC_INTERVAL - ExecReload=/bin/kill -HUP $MAINPID - KillMode=process --Type=simple -+Type=forking -+PIDFile=/var/run/mon_procd.pid - - [Install] - WantedBy=multi-user.target diff --git a/s390-tools-sles15-zdev-Enable-running-chzdev-from-unknown-root-devices.patch b/s390-tools-sles15-zdev-Enable-running-chzdev-from-unknown-root-devices.patch deleted file mode 100644 index 936ed2a..0000000 --- a/s390-tools-sles15-zdev-Enable-running-chzdev-from-unknown-root-devices.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 2a6a28023bdfe127be68ac605f9a026a82884c80 Mon Sep 17 00:00:00 2001 -From: Peter Oberparleiter -Date: Tue, 5 Dec 2017 15:40:23 +0100 -Subject: [PATCH 1/4] zdev: Enable running chzdev from unknown root devices - -When a persistent device configuration is changed, chzdev tries to -find out if it needs to perform additional steps to make this change -persistent. If this check fails, for example because the root device -is located on a RAM-disk, or on a device type not managed by chzdev, -the tool reports an error and exits with non-zero exit code: - - chzdev: Could not determine device that provides / - -or - - chzdev: Could not determine device that provides loop0 - -This behavior unnecessarily restricts chzdev from being used in -scripted environments like an installation initial RAM-disk. - -Fix this by removing the non-zero exit code and moving the message to -verbose output mode only. - -Signed-off-by: Peter Oberparleiter -Signed-off-by: Michael Holzheu ---- - zdev/src/root.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/zdev/src/root.c b/zdev/src/root.c -index 7f0d39f..668bdbd 100644 ---- a/zdev/src/root.c -+++ b/zdev/src/root.c -@@ -35,9 +35,14 @@ exit_code_t root_check(void) - /* Get list of devices that provide the root device. */ - selected = selected_dev_list_new(); - rc = select_by_path(NULL, selected, config_active, scope_mandatory, -- NULL, NULL, PATH_ROOT, err_print); -- if (rc) -+ NULL, NULL, PATH_ROOT, err_ignore); -+ if (rc) { -+ /* Running from an unknown root device is not an error. */ -+ verb("Note: Could not determine if root device configuration " -+ "needs to be updated\n"); -+ rc = 0; - goto out; -+ } - - /* Determine if any of the devices or device types has been modified. */ - mod = strlist_new(); --- -2.13.6 - diff --git a/s390-tools-sles15-zdev-Fix-zdev-dracut-module-aborting-on-unknown-root.patch b/s390-tools-sles15-zdev-Fix-zdev-dracut-module-aborting-on-unknown-root.patch deleted file mode 100644 index 355926f..0000000 --- a/s390-tools-sles15-zdev-Fix-zdev-dracut-module-aborting-on-unknown-root.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 0348a8443e5f15636f86ef2533a7d6e8fa5d936d Mon Sep 17 00:00:00 2001 -From: Peter Oberparleiter -Date: Thu, 7 Dec 2017 17:21:11 +0100 -Subject: [PATCH 4/4] zdev: Fix zdev dracut module aborting on unknown root - device - -Running dracut when the root device is not known to zdev (for example -because it is located on a virtio block device) will cause the zdev -dracut module to incorrectly return an error in the installkernel() -function. As a result dracut aborts with an error. - -Fix this by ensuring that the non-zero exit code resulting from lszdev -not being able to determine the root device is not passed on to the -calling function. Also remove unnecessary error output in this case -by leaving the install() function early when the root device is not -known to zdev. - -Signed-off-by: Peter Oberparleiter -Signed-off-by: Michael Holzheu ---- - zdev/dracut/95zdev/module-setup.sh | 12 ++++++++++-- - 1 file changed, 10 insertions(+), 2 deletions(-) - -diff --git a/zdev/dracut/95zdev/module-setup.sh b/zdev/dracut/95zdev/module-setup.sh -index 7c67cd7..4c13a65 100644 ---- a/zdev/dracut/95zdev/module-setup.sh -+++ b/zdev/dracut/95zdev/module-setup.sh -@@ -29,13 +29,21 @@ depends() { - } - - installkernel() { -- local _modules=$(lszdev --by-path / --columns MODULES --no-headings) -+ local _modules=$(lszdev --by-path / --columns MODULES --no-headings 2>/dev/null) - -+ [ -z "$_modules" ] && return 0 - [ ! -z "$_modules" ] && instmods $_modules - } - - install() { -- local _tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX) -+ local _tempfile -+ -+ # Exit early if root device type is unknown -+ if ! lszdev --by-path / >/dev/null 2>&1 ; then -+ return 0 -+ fi -+ -+ _tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX) - - if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then - # Use persistent configuration --- -2.13.6 - diff --git a/s390-tools-sles15-zdev-Use-correct-path-to-vmcp-binary.patch b/s390-tools-sles15-zdev-Use-correct-path-to-vmcp-binary.patch deleted file mode 100644 index 681a97b..0000000 --- a/s390-tools-sles15-zdev-Use-correct-path-to-vmcp-binary.patch +++ /dev/null @@ -1,67 +0,0 @@ -From a060dc22db06fb14274b72984ae8db51f00a21cd Mon Sep 17 00:00:00 2001 -From: Peter Oberparleiter -Date: Mon, 13 Nov 2017 12:50:32 +0100 -Subject: [PATCH] zdev: Use correct path to vmcp binary - -The zdev tools use a hard-coded path to locate the vmcp binary. Since -this path may differ between distributions, the vmcp binary may not be -successfully located in all cases. Fix this by using the BINDIR macro -to determine the correct path. This macro is also used during -installation of the vmcp binary itself. - -Reviewed-by: Michael Holzheu -Signed-off-by: Peter Oberparleiter -Signed-off-by: Michael Holzheu ---- - common.mak | 2 ++ - include/lib/zt_common.h | 1 + - zdev/include/path.h | 2 +- - 3 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/common.mak b/common.mak -index b9a9f54..bb6cdf0 100644 ---- a/common.mak -+++ b/common.mak -@@ -193,12 +193,14 @@ ALL_CFLAGS = -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \ - -DS390_TOOLS_LIBDIR=$(TOOLS_LIBDIR) \ - -DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \ - -DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \ -+ -DS390_TOOLS_BINDIR=$(BINDIR) \ - $(CFLAGS) - CXXFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS) - ALL_CXXFLAGS = -DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \ - -DS390_TOOLS_LIBDIR=$(TOOLS_LIBDIR) \ - -DS390_TOOLS_DATADIR=$(TOOLS_DATADIR) \ - -DS390_TOOLS_SYSCONFDIR=$(SYSCONFDIR) \ -+ -DS390_TOOLS_BINDIR=$(BINDIR) \ - $(CXXFLAGS) - ALL_CPPFLAGS = -I $(rootdir)include $(CPPFLAGS) - ALL_LDFLAGS = $(LDFLAGS) -diff --git a/include/lib/zt_common.h b/include/lib/zt_common.h -index e27b7b0..c486428 100644 ---- a/include/lib/zt_common.h -+++ b/include/lib/zt_common.h -@@ -25,6 +25,7 @@ - #define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE) - #define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR) - #define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR) -+#define TOOLS_BINDIR STRINGIFY (S390_TOOLS_BINDIR) - - #define __noreturn __attribute__((noreturn)) - #define __packed __attribute__((packed)) -diff --git a/zdev/include/path.h b/zdev/include/path.h -index 5252bcf..536ca06 100644 ---- a/zdev/include/path.h -+++ b/zdev/include/path.h -@@ -27,7 +27,7 @@ - #define PATH_PROC "/proc" - - #define PATH_UDEVADM "udevadm" --#define PATH_VMCP "/usr/sbin/vmcp" -+#define PATH_VMCP TOOLS_BINDIR "/vmcp" - #define PATH_IP "ip" - - #define PATH_ROOT "/" --- -2.13.6 - diff --git a/s390-tools-sles15-ziomon-re-add-missing-line.patch b/s390-tools-sles15-ziomon-re-add-missing-line.patch deleted file mode 100644 index 2387c74..0000000 --- a/s390-tools-sles15-ziomon-re-add-missing-line.patch +++ /dev/null @@ -1,28 +0,0 @@ -Subject: [PATCH] [BZ 161467] ziomon: Re-add missing line in ziomon_fcpconf -From: Michael Holzheu - -Description: ziomon: Re-add missing line in ziomon_fcpconf -Symptom: ziomon_fcpconf fails on startup with: - Global symbol "$map_dev" requires explicit package name ... -Problem: During the GPL to MIT conversion process from v1.39.0 to - v2.0.0 one line has been lost by accident. -Solution: Re-add that line again. -Reproduction: Call the ziomon_fcpconf tool. -Upstream-ID: 523d833eb31633673847b6da0edbd35903f14dc4 -Problem-ID: 161467 - -Signed-off-by: Michael Holzheu ---- - ziomon/ziomon_fcpconf | 1 + - 1 file changed, 1 insertion(+) - ---- a/ziomon/ziomon_fcpconf -+++ b/ziomon/ziomon_fcpconf -@@ -58,6 +58,7 @@ sub store_mapper_devices - my $src_dir = shift(); - my @entries = grep { ! /^\./ } dir_content($src_dir); - -+ foreach my $map_dev (@entries) { - my $tf = catfile($src_dir, "$map_dev"); - my $mm = `stat -L -c%t:%T $tf`; - chomp($mm); diff --git a/s390-tools-sles15-zipl-remove-invalid-dasdview-command-line-option.patch b/s390-tools-sles15-zipl-remove-invalid-dasdview-command-line-option.patch deleted file mode 100644 index cc9b4e3..0000000 --- a/s390-tools-sles15-zipl-remove-invalid-dasdview-command-line-option.patch +++ /dev/null @@ -1,29 +0,0 @@ -Subject: [PATCH] [BZ 161183] zipl: remove invalid dasdview command line option -From: Stefan Haberland - -Description: zipl: remove invalid dasdview command line option -Symptom: zipl does not work when used with a lvm or device mapper - target. -Problem: The zipl_helper.device-mapper script uses dasdview with - an option "-f" that has been removed recently. -Solution: Remove "-f" from the dasdview call. -Reproduction: Run zipl on a lvm target. -Upstream-ID: - -Problem-ID: 161183 - -Signed-off-by: Stefan Haberland ---- - zipl/src/zipl_helper.device-mapper | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/zipl/src/zipl_helper.device-mapper -+++ b/zipl/src/zipl_helper.device-mapper -@@ -623,7 +623,7 @@ sub get_dasd_info($) - my $type; - local *HANDLE; - -- open(HANDLE, "$dasdview -x -f $dev 2>/dev/null|") or -+ open(HANDLE, "$dasdview -x $dev 2>/dev/null|") or - # dasdview returned with an error - return undef; - while () { diff --git a/s390-tools-sles15sp1-0001-zkey-Add-properties-file-handling-routines.patch b/s390-tools-sles15sp1-0001-zkey-Add-properties-file-handling-routines.patch deleted file mode 100644 index 52110bc..0000000 --- a/s390-tools-sles15sp1-0001-zkey-Add-properties-file-handling-routines.patch +++ /dev/null @@ -1,506 +0,0 @@ -Subject: zkey: Add properties file handling routines -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 340da73bb7f06a9fc2aecfe4e33f1f3a17b3568d -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Add properties file handling routines - - In preparation for a new feature, introduce property file - handling routines. A property file stores key value pairs - in a text file. Optionally a hash of all keys and values - contained in the properties file can be generated to - ensure integrity of the properties file and to detect - manual modifications. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/Makefile | 5 - zkey/properties.c | 409 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - zkey/properties.h | 36 ++++ - 3 files changed, 448 insertions(+), 2 deletions(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -1,15 +1,16 @@ - include ../common.mak - - CPPFLAGS += -I../include --LDLIBS += -ldl -+LDLIBS += -ldl -lcrypto - - all: zkey - - libs = $(rootdir)/libutil/libutil.a - - zkey.o: zkey.c pkey.h misc.h -+properties.o: properties.c properties.h - --zkey: zkey.o $(libs) -+zkey: zkey.o properties.o $(libs) - - install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) ---- /dev/null -+++ b/zkey/properties.c -@@ -0,0 +1,409 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Properties file handling functions -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include -+ -+#include "lib/util_libc.h" -+#include "lib/util_list.h" -+#include "lib/util_panic.h" -+ -+#include "properties.h" -+ -+struct properties { -+ struct util_list list; -+}; -+ -+struct property { -+ struct util_list_node node; -+ char *name; -+ char *value; -+}; -+ -+#define SHA256_DIGEST_LEN 32 -+#define INTEGRITY_KEY_NAME "__hash__" -+ -+#define RESTRICTED_PROPERTY_NAME_CHARS "=\n" -+#define RESTRICTED_PROPERTY_VALUE_CHARS "\n" -+ -+static int openssl_initialized; -+ -+/** -+ * Allocate and initialize a SHA-256 context -+ * -+ * @returns a SHA context -+ */ -+static EVP_MD_CTX *sha256_init(void) -+{ -+ EVP_MD_CTX *ctx; -+ int rc; -+ -+ if (!openssl_initialized) { -+ OpenSSL_add_all_algorithms(); -+ openssl_initialized = 1; -+ } -+ -+ ctx = EVP_MD_CTX_create(); -+ util_assert(ctx != NULL, -+ "Internal error: OpenSSL MD context allocation failed"); -+ -+ rc = EVP_DigestInit_ex(ctx, EVP_sha256(), NULL); -+ util_assert(rc == 1, "Internal error: SHA-256 digest init failed"); -+ -+ return ctx; -+} -+ -+/** -+ * Add data to the SHA-256 context -+ * -+ * @parm[in] ctx the SHA context -+ * @parm[in] data the data to be hashed -+ * @parm[in] data_len the length of the data -+ */ -+static void sha256_update(EVP_MD_CTX *ctx, -+ const char *data, unsigned int data_len) -+{ -+ int rc; -+ -+ util_assert(ctx != NULL, "Internal error: OpenSSL MD context is NULL"); -+ util_assert(data != NULL || data_len == 0, -+ "Internal error: data is NULL"); -+ -+ rc = EVP_DigestUpdate(ctx, data, data_len); -+ -+ util_assert(rc == 1, "Internal error: SHA-256 digest udpdate failed"); -+} -+ -+/** -+ * Produce the digest for the SHA-256 context and free the context -+ * -+ * @parm[in] ctx the SHA context -+ * @parm[out] digest a buffer where the digest is stored -+ * @parm[in/out] digest_len on entry, *digest_len contains the size of the -+ * digest buffer, which must be large enough to hold -+ * a SHA-256 digest (32 bytes), -+ * on exit it contains the size of the digest -+ * returned in the buffer. -+ */ -+static void sha256_final(EVP_MD_CTX *ctx, -+ unsigned char *digest, unsigned int *digest_len) -+{ -+ int rc; -+ -+ util_assert(ctx != NULL, "Internal error: OpenSSL MD context is NULL"); -+ -+ if (digest != NULL && digest_len != NULL) { -+ util_assert(*digest_len >= (unsigned int)EVP_MD_CTX_size(ctx), -+ "Internal error: digest_len is too small"); -+ -+ rc = EVP_DigestFinal_ex(ctx, digest, digest_len); -+ util_assert(rc == 1, -+ "Internal error: SHA-256 digest final failed"); -+ } -+ -+ EVP_MD_CTX_destroy(ctx); -+} -+ -+/** -+ * Allocates a new properties object -+ * -+ * @returns the properties object -+ */ -+struct properties *properties_new(void) -+{ -+ struct properties *properties; -+ -+ properties = util_zalloc(sizeof(struct properties)); -+ -+ util_list_init_offset(&properties->list, -+ offsetof(struct property, node)); -+ return properties; -+} -+ -+/** -+ * Frees a properties object with all its properties -+ * -+ * @param[in] properties the properties object -+ */ -+void properties_free(struct properties *properties) -+{ -+ struct property *property; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ -+ while ((property = util_list_start(&properties->list)) != NULL) { -+ free(property->name); -+ free(property->value); -+ util_list_remove(&properties->list, property); -+ } -+ -+ free(properties); -+} -+ -+/** -+ * Find a property by its name in the list iof properties -+ * -+ * @param[in] properties the properties object -+ * @param[in] name the name of the property to find -+ * -+ * @returns a pointer to the proerty when it has been found, or NULL if not -+ */ -+static struct property *properties_find(struct properties *properties, -+ const char *name) -+{ -+ struct property *property; -+ -+ property = util_list_start(&properties->list); -+ while (property != NULL) { -+ if (strcmp(property->name, name) == 0) -+ return property; -+ property = util_list_next(&properties->list, property); -+ } -+ return NULL; -+} -+ -+/** -+ * Adds or updates a property -+ * -+ * @param[in] properties the properties object -+ * @param[in] name the name of the property -+ * @param[in] value the value of the property -+ * -+ * @returns 0 on success, -+ * -EINVAL if the name or value contains invalid characters -+ */ -+int properties_set(struct properties *properties, -+ const char *name, const char *value) -+{ -+ struct property *property; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ util_assert(value != NULL, "Internal error: value is NULL"); -+ -+ if (strpbrk(name, RESTRICTED_PROPERTY_NAME_CHARS) != NULL) -+ return -EINVAL; -+ if (strpbrk(value, RESTRICTED_PROPERTY_VALUE_CHARS) != NULL) -+ return -EINVAL; -+ -+ property = properties_find(properties, name); -+ if (property != NULL) { -+ free(property->value); -+ property->value = util_strdup(value); -+ } else { -+ property = util_zalloc(sizeof(struct property)); -+ property->name = util_strdup(name); -+ property->value = util_strdup(value); -+ util_list_add_tail(&properties->list, property); -+ } -+ return 0; -+} -+ -+/** -+ * Gets a property -+ * -+ * @param[in] properties the properties object -+ * @param[in] name the name of the property -+ * -+ * @returns a string containing the property value, or NULL if the property -+ * was not found. -+ * Note: The returned string must be freed via free() by the caller. -+ */ -+char *properties_get(struct properties *properties, const char *name) -+{ -+ struct property *property; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ -+ property = properties_find(properties, name); -+ if (property == NULL) -+ return NULL; -+ -+ return util_strdup(property->value); -+} -+ -+/** -+ * Removes a property -+ * -+ * @param[in] properties the properties object -+ * @param[in] name the name of the property -+ * -+ * @returns 0 on success, -ENOENT if the property was not found. -+ */ -+int properties_remove(struct properties *properties, const char *name) -+{ -+ struct property *property; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ -+ property = properties_find(properties, name); -+ if (property == NULL) -+ return -ENOENT; -+ -+ free(property->name); -+ free(property->value); -+ util_list_remove(&properties->list, property); -+ return 0; -+} -+ -+/** -+ * Saves the properties to a file -+ * -+ * @param[in] properties the properties object -+ * @param[in] filename the file name -+ * @param[in] check_integrity if TRUE, an hash of the key and values is -+ * stored as part of the file. -+ * -+ * @returns 0 on success, -EIO the file could not be created -+ */ -+int properties_save(struct properties *properties, const char *filename, -+ bool check_integrity) -+{ -+ char digest_hex[SHA256_DIGEST_LEN * 2 + 1]; -+ unsigned char digest[SHA256_DIGEST_LEN]; -+ unsigned int digest_len = sizeof(digest); -+ struct property *property; -+ EVP_MD_CTX *ctx = NULL; -+ unsigned int i; -+ FILE *fp; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ util_assert(filename != NULL, "Internal error: filename is NULL"); -+ -+ fp = fopen(filename, "w"); -+ if (fp == NULL) -+ return -EIO; -+ -+ if (check_integrity) -+ ctx = sha256_init(); -+ -+ property = util_list_start(&properties->list); -+ while (property != NULL) { -+ fprintf(fp, "%s=%s\n", property->name, property->value); -+ -+ if (check_integrity) { -+ sha256_update(ctx, property->name, -+ strlen(property->name)); -+ sha256_update(ctx, property->value, -+ strlen(property->value)); -+ } -+ -+ property = util_list_next(&properties->list, property); -+ } -+ -+ if (check_integrity) { -+ sha256_final(ctx, digest, &digest_len); -+ util_assert(digest_len <= SHA256_DIGEST_LEN, -+ "Internal error: digest length too long"); -+ -+ for (i = 0; i < digest_len; i++) -+ sprintf(&digest_hex[i * 2], "%02x", digest[i]); -+ digest_hex[digest_len * 2] = '\0'; -+ -+ fprintf(fp, "%s=%s\n", INTEGRITY_KEY_NAME, digest_hex); -+ } -+ -+ fclose(fp); -+ return 0; -+} -+ -+/** -+ * Loads the properties from a file -+ * -+ * @param[in] properties the properties object -+ * @param[in] filename the file name -+ * @param[in] check_integrity if TRUE, an hash of the key and values is -+ * compared with the hash stored as part of the file. -+ * -+ * @returns 0 on success, -EIO the file could not be created, -+ * -EPERM in case of a syntax error or an integrity error -+ */ -+int properties_load(struct properties *properties, const char *filename, -+ bool check_integrity) -+{ -+ char digest_hex[SHA256_DIGEST_LEN * 2 + 1]; -+ unsigned char digest[SHA256_DIGEST_LEN]; -+ unsigned int digest_len = sizeof(digest); -+ char *digest_read = NULL; -+ EVP_MD_CTX *ctx = NULL; -+ char line[4096]; -+ unsigned int len, i; -+ int rc = 0; -+ char *ch; -+ FILE *fp; -+ -+ util_assert(properties != NULL, "Internal error: properties is NULL"); -+ util_assert(filename != NULL, "Internal error: filename is NULL"); -+ -+ fp = fopen(filename, "r"); -+ if (fp == NULL) -+ return -EIO; -+ -+ if (check_integrity) -+ ctx = sha256_init(); -+ -+ while (fgets(line, sizeof(line), fp) != NULL) { -+ len = strlen(line); -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ ch = strchr(line, '='); -+ if (ch == NULL) { -+ rc = -EPERM; -+ goto out; -+ } -+ -+ *ch = '\0'; -+ ch++; -+ -+ if (check_integrity) { -+ if (strcmp(line, INTEGRITY_KEY_NAME) == 0) { -+ digest_read = util_strdup(ch); -+ continue; -+ } -+ -+ sha256_update(ctx, line, strlen(line)); -+ sha256_update(ctx, ch, strlen(ch)); -+ } -+ -+ properties_set(properties, line, ch); -+ } -+ -+ if (check_integrity) { -+ sha256_final(ctx, digest, &digest_len); -+ ctx = NULL; -+ util_assert(digest_len <= SHA256_DIGEST_LEN, -+ "Internal error: digest length too long"); -+ -+ for (i = 0; i < digest_len; i++) -+ sprintf(&digest_hex[i * 2], "%02x", digest[i]); -+ digest_hex[digest_len * 2] = '\0'; -+ -+ if (digest_read == NULL || -+ strcmp(digest_hex, digest_read) != 0) { -+ rc = -EPERM; -+ goto out; -+ } -+ } -+ -+out: -+ if (ctx != NULL) -+ sha256_final(ctx, NULL, NULL); -+ if (digest_read != NULL) -+ free(digest_read); -+ fclose(fp); -+ return rc; -+} ---- /dev/null -+++ b/zkey/properties.h -@@ -0,0 +1,36 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Properties file handling functions -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 PROPFILE_H -+#define PROPFILE_H -+ -+#include -+ -+struct properties; -+ -+struct properties *properties_new(void); -+ -+void properties_free(struct properties *properties); -+ -+int properties_set(struct properties *properties, -+ const char *name, const char *value); -+ -+char *properties_get(struct properties *properties, const char *name); -+ -+int properties_remove(struct properties *properties, const char *name); -+ -+int properties_save(struct properties *properties, const char *filename, -+ bool check_integrity); -+ -+int properties_load(struct properties *properties, const char *filename, -+ bool check_integrity); -+ -+#endif diff --git a/s390-tools-sles15sp1-0002-zkey-Add-build-dependency-to-OpenSSL-libcrypto.patch b/s390-tools-sles15sp1-0002-zkey-Add-build-dependency-to-OpenSSL-libcrypto.patch deleted file mode 100644 index 37ef6da..0000000 --- a/s390-tools-sles15sp1-0002-zkey-Add-build-dependency-to-OpenSSL-libcrypto.patch +++ /dev/null @@ -1,89 +0,0 @@ -Subject: zkey: Add build dependency to OpenSSL (libcrypto) -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 5e24f74fdefc5fe7d315df080832f1b059485f0f -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Add build dependency to OpenSSL (libcrypto) - - The integrity support for the properties file routines use - SHA-256 to build a hash of the keys and values of a property file. - The codes uses the EVP_DigestInit_ex, EVP_DigestUpdate, and - EVP_DigestFinal from the libcrypto library (OpenSSL). - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - README.md | 6 ++++++ - zkey/Makefile | 21 ++++++++++++++++++++- - 2 files changed, 26 insertions(+), 1 deletion(-) - ---- a/README.md -+++ b/README.md -@@ -263,6 +263,7 @@ build options: - | ncurses | `HAVE_NCURSES` | hyptop | - | pfm | `HAVE_PFM` | cpacfstats | - | net-snmp | `HAVE_SNMP` | osasnmpd | -+| openssl | `HAVE_OPENSSL` | zkey | - - This table lists additional build or install options: - -@@ -365,3 +366,8 @@ the different tools are provided: - For running znetconf these programs are required: - - modprobe (kmod) - - vmcp (s390-tools) -+ -+* zkey: -+ For building the zkey tools you need openssl version 0.9.7 or newer installed -+ (openssl-devel.rpm). Tip: you may skip the zkey build by adding -+ `HAVE_OPENSSL=0` to the make invocation. ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -1,9 +1,26 @@ - include ../common.mak - -+ifeq (${HAVE_OPENSSL},0) -+ -+all: -+ $(SKIP) HAVE_OPENSSL=0 -+ -+install: -+ $(SKIP) HAVE_OPENSSL=0 -+ -+else -+ -+check_dep: -+ $(call check_dep, \ -+ "zkey", \ -+ "openssl/evp.h", \ -+ "openssl-devel", \ -+ "HAVE_OPENSSL=0") -+ - CPPFLAGS += -I../include - LDLIBS += -ldl -lcrypto - --all: zkey -+all: check_dep zkey - - libs = $(rootdir)/libutil/libutil.a - -@@ -18,6 +35,8 @@ install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 - -+endif -+ - clean: - rm -f *.o zkey - diff --git a/s390-tools-sles15sp1-0003-zkey-Add-helper-functions-for-comma-separated-string.patch b/s390-tools-sles15sp1-0003-zkey-Add-helper-functions-for-comma-separated-string.patch deleted file mode 100644 index f4badf6..0000000 --- a/s390-tools-sles15sp1-0003-zkey-Add-helper-functions-for-comma-separated-string.patch +++ /dev/null @@ -1,276 +0,0 @@ -Subject: zkey: Add helper functions for comma separated string handling -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: a090a1ffe8bc780059ebed99f19d32a2a6a3426d -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Add helper functions for comma separated string handling - - Comma separated strings are used in property values to store - multiple values in one property. These helper functions allow to - work with such comma separated strings. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/properties.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - zkey/properties.h | 12 +++ - 2 files changed, 226 insertions(+) - ---- a/zkey/properties.c -+++ b/zkey/properties.c -@@ -38,6 +38,8 @@ struct property { - #define RESTRICTED_PROPERTY_NAME_CHARS "=\n" - #define RESTRICTED_PROPERTY_VALUE_CHARS "\n" - -+#define RESTRICTED_STR_LIST_CHARS ",\n" -+ - static int openssl_initialized; - - /** -@@ -407,3 +409,215 @@ out: - fclose(fp); - return rc; - } -+ -+/** -+ * Combines a list of strings into one comma separated string -+ * -+ * @param[in] strings zero terminated array of pointers to C-strings -+ * -+ * @returns a new string. This must be freed by the caller when no longer used. -+ * returns NULL if a string contains an invalid character. -+ */ -+char *str_list_combine(const char **strings) -+{ -+ unsigned int i, size; -+ char *str; -+ -+ util_assert(strings != NULL, "Internal error: strings is NULL"); -+ -+ for (i = 0, size = 0; strings[i] != NULL; i++) { -+ if (strpbrk(strings[i], RESTRICTED_STR_LIST_CHARS) != NULL) -+ return NULL; -+ -+ if (i > 0) -+ size += 1; -+ size += strlen(strings[i]); -+ } -+ -+ str = util_zalloc(size + 1); -+ for (i = 0, size = 0; strings[i] != NULL; i++) { -+ if (i > 0) -+ strcat(str, ","); -+ strcat(str, strings[i]); -+ } -+ -+ return str; -+} -+ -+/** -+ * Splits a comma separated string into its parts -+ * -+ * @param[in] str_list the comma separated string -+ * -+ * @returns a zero terminated array of pointers to C-strings. This array -+ * and all individual C-Strings need to be freed bay the caller when -+ * no longer used. This can be done using str_list_free_string_array(). -+ */ -+char **str_list_split(const char *str_list) -+{ -+ unsigned int i, count; -+ char **list; -+ char *copy; -+ char *tok; -+ -+ util_assert(str_list != NULL, "Internal error: str_list is NULL"); -+ -+ count = str_list_count(str_list); -+ list = util_zalloc((count + 1) * sizeof(char *)); -+ -+ copy = util_strdup(str_list); -+ tok = strtok(copy, ","); -+ i = 0; -+ while (tok != NULL) { -+ list[i] = util_strdup(tok); -+ i++; -+ tok = strtok(NULL, ","); -+ } -+ -+ free(copy); -+ return list; -+} -+ -+/** -+ * Count the number of parts a comma separated string contains -+ * -+ * param[in] str_list the comma separated string -+ * -+ * @returns the number of parts -+ */ -+unsigned int str_list_count(const char *str_list) -+{ -+ unsigned int i, count; -+ -+ util_assert(str_list != NULL, "Internal error: str_list is NULL"); -+ -+ if (strlen(str_list) == 0) -+ return 0; -+ -+ for (i = 0, count = 1; str_list[i] != '\0'; i++) -+ if (str_list[i] == ',') -+ count++; -+ return count; -+} -+ -+/** -+ * Find a string in a comma separated string -+ * -+ * @param str_list the comma separated string. -+ * @param str the string to find -+ * -+ * @returns a pointer to the string within the comma separated string, -+ * or NULL if the string was not found -+ * -+ */ -+static char *str_list_find(const char *str_list, const char *str) -+{ -+ char *before; -+ char *after; -+ char *ch; -+ -+ ch = strstr(str_list, str); -+ if (ch == NULL) -+ return NULL; -+ -+ if (ch != str_list) { -+ before = ch - 1; -+ if (*before != ',') -+ return NULL; -+ } -+ -+ after = ch + strlen(str); -+ if (*after != ',' && *after != '\0') -+ return NULL; -+ -+ return ch; -+} -+ -+/** -+ * Appends a string to a comma separated string -+ * -+ * @param str_list the comma separated string. -+ * @param str the string to add -+ * -+ * @returns a new comma separated string. This must be freed by the caller when -+ * no longer used. If the string to add is already contained in the -+ * comma separated list, it is not added and NULL is returned. -+ * If the string to be added contains a comma, NULL is returned. -+ */ -+char *str_list_add(const char *str_list, const char *str) -+{ -+ char *ret; -+ -+ util_assert(str_list != NULL, "Internal error: str_list is NULL"); -+ util_assert(str != NULL, "Internal error: str is NULL"); -+ -+ if (strpbrk(str, RESTRICTED_STR_LIST_CHARS) != NULL) -+ return NULL; -+ -+ if (str_list_find(str_list, str)) -+ return NULL; -+ -+ ret = util_zalloc(strlen(str_list) + 1 + strlen(str) + 1); -+ strcpy(ret, str_list); -+ if (strlen(str_list) > 0) -+ strcat(ret, ","); -+ strcat(ret, str); -+ -+ return ret; -+} -+ -+/** -+ * Removes a string from a comma separated string -+ * -+ * @param str_list the comma separated string. -+ * @param str the string to remove -+ * -+ * @returns a new comma separated string. This must be freed by the caller when -+ * no longer used. If the string to remove is not found in the -+ * comma separated string, NULL is returned -+ */ -+char *str_list_remove(const char *str_list, const char *str) -+{ -+ char *after; -+ char *ret; -+ char *ch; -+ -+ util_assert(str_list != NULL, "Internal error: str_list is NULL"); -+ util_assert(str != NULL, "Internal error: str is NULL"); -+ -+ ch = str_list_find(str_list, str); -+ if (ch == NULL) -+ return NULL; -+ -+ after = ch + strlen(str); -+ if (*after == ',') { -+ /* there are more parts after the one to remove */ -+ ret = util_zalloc(strlen(str_list) - strlen(str) - 1 + 1); -+ strncpy(ret, str_list, ch - str_list); -+ strcat(ret, after + 1); -+ } else if (ch == str_list) { -+ /* removing the one and only part -> empty string */ -+ ret = util_zalloc(1); -+ } else { -+ /* there are no more parts after the one to remove */ -+ ret = util_zalloc(strlen(str_list) - strlen(str) - 1 + 1); -+ strncpy(ret, str_list, ch - 1 - str_list); -+ } -+ -+ return ret; -+} -+ -+/** -+ * Frees a string array (as produced by str_list_split()) -+ * -+ * @param strings a NULL terminated array of pointers to C-Strings. -+ */ -+void str_list_free_string_array(char **strings) -+{ -+ util_assert(strings != NULL, "Internal error: strings is NULL"); -+ -+ while (*strings != NULL) { -+ free((void *)*strings); -+ strings++; -+ } -+} ---- a/zkey/properties.h -+++ b/zkey/properties.h -@@ -33,4 +33,16 @@ int properties_save(struct properties *p - int properties_load(struct properties *properties, const char *filename, - bool check_integrity); - -+char *str_list_combine(const char **strings); -+ -+char **str_list_split(const char *str_list); -+ -+unsigned int str_list_count(const char *str_list); -+ -+char *str_list_add(const char *str_list, const char *str); -+ -+char *str_list_remove(const char *str_list, const char *str); -+ -+void str_list_free_string_array(char **strings); -+ - #endif diff --git a/s390-tools-sles15sp1-0004-zkey-Externalize-secure-key-back-end-functions.patch b/s390-tools-sles15sp1-0004-zkey-Externalize-secure-key-back-end-functions.patch deleted file mode 100644 index 5f32e43..0000000 --- a/s390-tools-sles15sp1-0004-zkey-Externalize-secure-key-back-end-functions.patch +++ /dev/null @@ -1,1543 +0,0 @@ -Subject: zkey: Externalize secure key back-end functions -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 5872f8a21ba222f9c32f0155ce1ac0f36c12cf39 -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Externalize secure key back-end functions - - To reduce the size of the zkey.c source file, all routines that - deal with secure keys are moved to a new source file pkey.c. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/Makefile | 3 - zkey/pkey.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - zkey/pkey.h | 44 +++ - zkey/zkey.c | 581 +++------------------------------------------ - 4 files changed, 832 insertions(+), 544 deletions(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -25,9 +25,10 @@ all: check_dep zkey - libs = $(rootdir)/libutil/libutil.a - - zkey.o: zkey.c pkey.h misc.h -+pkey.o: pkey.c pkey.h - properties.o: properties.c properties.h - --zkey: zkey.o properties.o $(libs) -+zkey: zkey.o pkey.o properties.o $(libs) - - install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) ---- /dev/null -+++ b/zkey/pkey.c -@@ -0,0 +1,748 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lib/util_base.h" -+#include "lib/util_libc.h" -+#include "lib/util_panic.h" -+ -+#include "pkey.h" -+ -+ -+#define pr_verbose(verbose, fmt...) do { \ -+ if (verbose) \ -+ warnx(fmt); \ -+ } while (0) -+ -+#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? 2 * (keysize) : (keysize)) -+#define HALF_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? (keysize) / 2 : (keysize)) -+ -+/* -+ * Definitions for the CCA library -+ */ -+#define CCA_LIBRARY_NAME "libcsulcca.so" -+ -+#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) { -+ warnx("%s\nEnsure that the IBM CCA Host Libraries and " -+ "Tools are installed properly", dlerror()); -+ return -ELIBACC; -+ } -+ -+ /* Get the Key Token Change function */ -+ *dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC"); -+ if (*dll_CSNBKTC == NULL) { -+ warnx("%s\nEnsure that the IBM CCA Host Libraries and " -+ "Tools are installed properly", dlerror()); -+ dlclose(*lib_csulcca); -+ *lib_csulcca = NULL; -+ return -ELIBACC; -+ } -+ -+ pr_verbose(verbose, "CCA library '%s' has been loaded successfully", -+ CCA_LIBRARY_NAME); -+ return 0; -+} -+ -+/** -+ * Opens the pkey device and returns its file descriptor. -+ * -+ * @param verbose if true, verbose messages are printed -+ * -+ * @returns the file descriptor or -1 to indicate an error -+ */ -+int open_pkey_device(bool verbose) -+{ -+ int pkey_fd; -+ -+ pkey_fd = open(PKEYDEVICE, O_RDWR); -+ if (pkey_fd < 0) { -+ warnx("File '%s:' %s\nEnsure that the 'pkey' kernel module " -+ "is loaded", PKEYDEVICE, strerror(errno)); -+ return -1; -+ } -+ -+ pr_verbose(verbose, "Device '%s' has been opened successfully", -+ PKEYDEVICE); -+ return pkey_fd; -+} -+ -+/** -+ * Read a secure key file and return the allocated buffer and size. -+ * -+ * @param[in] keyfile the name of the file to read -+ * @param[out] secure_key_size on return, the size of the secure key read -+ * @param[in] verbose if true, verbose messages are printed -+ * -+ * @return a buffer containing the secure key, or NULL in case of an error. -+ * The returned buffer must be freed by the caller. -+ */ -+u8 *read_secure_key(const char *keyfile, size_t *secure_key_size, -+ bool verbose) -+{ -+ size_t count, size; -+ struct stat sb; -+ char *msg; -+ FILE *fp; -+ u8 *buf; -+ -+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL"); -+ util_assert(secure_key_size != NULL, -+ "Internal error: secure_key_size is NULL"); -+ -+ if (stat(keyfile, &sb)) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ return NULL; -+ } -+ 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); -+ return NULL; -+ } -+ -+ fp = fopen(keyfile, "r"); -+ if (fp == NULL) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ return NULL; -+ } -+ -+ buf = util_malloc(size); -+ count = fread(buf, 1, size, fp); -+ if (count <= 0) { -+ msg = feof(fp) ? "File is too small" : strerror(errno); -+ warnx("File '%s': %s", keyfile, msg); -+ free(buf); -+ buf = NULL; -+ goto out; -+ } -+ -+ *secure_key_size = size; -+ -+ if (verbose) { -+ pr_verbose(verbose, "%lu bytes read from file '%s'", size, -+ keyfile); -+ util_hexdump_grp(stderr, NULL, buf, 4, size, 0); -+ } -+out: -+ fclose(fp); -+ return buf; -+} -+ -+/** -+ * Write a secure key file -+ * -+ * @param[in] keyfile the name of the file to write -+ * @param[in] secure_key a buffer containing the secure key -+ * @param[in] secure_key_size the size of the secure key -+ * @param[in] verbose if true, verbose messages are printed -+ * -+ * @returns 0 in case of success, -EIO in case of an error -+ */ -+int write_secure_key(const char *keyfile, const u8 *secure_key, -+ size_t secure_key_size, bool verbose) -+{ -+ size_t count; -+ FILE *fp; -+ -+ util_assert(keyfile != NULL, "Internal error: keyfile 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 zero"); -+ -+ fp = fopen(keyfile, "w"); -+ if (fp == NULL) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ return -EIO; -+ } -+ -+ count = fwrite(secure_key, 1, secure_key_size, fp); -+ if (count <= 0) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ fclose(fp); -+ return -EIO; -+ } -+ -+ if (verbose) { -+ pr_verbose(verbose, "%lu bytes written to file '%s'", -+ secure_key_size, keyfile); -+ util_hexdump_grp(stderr, NULL, secure_key, 4, -+ secure_key_size, 0); -+ } -+ fclose(fp); -+ return 0; -+} -+ -+/** -+ * Read a clear key file and return the allocated buffer and size -+ * -+ * @param[in] keyfile the name of the file to read -+ * @param[in] keybits the clear key size in bits. When keybits is 0, then -+ * the file size determines the keybits. -+ * @param[in] xts if true an XTS key is to be read -+ * @param[out] clear_key_size on return, the size of the clear key read -+ * @param[in] verbose if true, verbose messages are printed -+ * -+ * @return a buffer containing the clear key, or NULL in case of an error. -+ * The returned buffer must be freed by the caller. -+ */ -+static u8 *read_clear_key(const char *keyfile, size_t keybits, bool xts, -+ size_t *clear_key_size, bool verbose) -+{ -+ size_t count, size, expected_size; -+ struct stat sb; -+ char *msg; -+ FILE *fp; -+ u8 *buf; -+ -+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL"); -+ util_assert(clear_key_size != NULL, -+ "Internal error: clear_key_size is NULL"); -+ -+ if (stat(keyfile, &sb)) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ return NULL; -+ } -+ size = sb.st_size; -+ -+ if (keybits != 0) { -+ expected_size = DOUBLE_KEYSIZE_FOR_XTS(keybits / 8, xts); -+ if (size != expected_size) { -+ warnx("File '%s' has an invalid size, " -+ "%lu bytes expected", keyfile, expected_size); -+ return NULL; -+ } -+ } else { -+ keybits = DOUBLE_KEYSIZE_FOR_XTS(size * 8, xts); -+ } -+ -+ switch (keybits) { -+ case 128: -+ break; -+ case 192: -+ if (xts) { -+ warnx("File '%s' has an invalid size, " -+ "192 bit keys are not supported with XTS", -+ keyfile); -+ return NULL; -+ } -+ break; -+ case 256: -+ break; -+ default: -+ if (xts) -+ warnx("File '%s' has an invalid size, " -+ "32 or 64 bytes expected", keyfile); -+ else -+ warnx("File '%s' has an invalid size, 16, 24 " -+ "or 32 bytes expected", keyfile); -+ return NULL; -+ } -+ -+ fp = fopen(keyfile, "r"); -+ if (fp == NULL) { -+ warnx("File '%s': %s", keyfile, strerror(errno)); -+ return NULL; -+ } -+ -+ buf = util_malloc(size); -+ count = fread(buf, 1, size, fp); -+ if (count <= 0) { -+ msg = feof(fp) ? "File is too small" : strerror(errno); -+ warnx("File '%s': %s", keyfile, msg); -+ free(buf); -+ buf = NULL; -+ goto out; -+ } -+ -+ *clear_key_size = size; -+ -+ if (verbose) { -+ pr_verbose(verbose, "%lu bytes read from file '%s'", size, -+ keyfile); -+ util_hexdump_grp(stderr, NULL, buf, 4, size, 0); -+ } -+out: -+ fclose(fp); -+ return buf; -+} -+ -+/** -+ * Generate a secure key by random -+ * -+ * @param[in] pkey_fd the pkey file descriptor -+ * @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] 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 -+ * -+ * @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) -+{ -+ struct pkey_genseck gensec; -+ size_t secure_key_size; -+ u8 *secure_key; -+ int rc; -+ -+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); -+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL"); -+ -+ if (keybits == 0) -+ keybits = DEFAULT_KEYBITS; -+ -+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts); -+ secure_key = util_malloc(secure_key_size); -+ -+ pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain); -+ -+ 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: -+ warnx("Invalid value for '--keybits'/'-c': '%lu'", keybits); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec); -+ if (rc < 0) { -+ rc = -errno; -+ warnx("Failed to generate a secure key: %s", strerror(errno)); -+ goto out; -+ } -+ -+ memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE); -+ -+ if (xts) { -+ rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec); -+ if (rc < 0) { -+ rc = -errno; -+ warnx("Failed to generate a secure key: %s", -+ strerror(errno)); -+ goto out; -+ } -+ -+ memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey, -+ SECURE_KEY_SIZE); -+ } -+ -+ pr_verbose(verbose, "Successfully generated a secure key"); -+ -+ rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose); -+ -+out: -+ free(secure_key); -+ return rc; -+} -+ -+ -+/* -+ * Generate a secure key from a clear key file -+ * -+ * @param[in] pkey_fd the pkey file descriptor -+ * @param[in] keyfile the file name of the secure key to generate -+ * @param[in] keybits the cryptographic size of the key in bits. When -+ * keybits is 0, then the clear key file size -+ * 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] 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 -+ * -+ * @returns 0 on success, a negative errno in case of an error -+ */ -+int generate_secure_key_clear(int pkey_fd, const char *keyfile, -+ size_t keybits, bool xts, -+ const char *clearkeyfile, -+ u16 card, u16 domain, -+ bool verbose) -+{ -+ struct pkey_clr2seck clr2sec; -+ size_t secure_key_size; -+ size_t clear_key_size; -+ u8 *secure_key; -+ u8 *clear_key; -+ int rc; -+ -+ util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1"); -+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL"); -+ util_assert(clearkeyfile != NULL, -+ "Internal error: clearkeyfile is NULL"); -+ -+ secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts); -+ secure_key = util_malloc(secure_key_size); -+ -+ 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); -+ -+ 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: -+ warnx("Invalid clear key size: '%lu' bytes", clear_key_size); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ memcpy(&clr2sec.clrkey, clear_key, -+ HALF_KEYSIZE_FOR_XTS(clear_key_size, xts)); -+ -+ 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)); -+ goto out; -+ } -+ -+ memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE); -+ -+ if (xts) { -+ memcpy(&clr2sec.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)); -+ goto out; -+ } -+ -+ memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey, -+ SECURE_KEY_SIZE); -+ } -+ -+ pr_verbose(verbose, -+ "Successfully generated a secure key from a clear key"); -+ -+ rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose); -+ -+out: -+ memset(&clr2sec, 0, sizeof(clr2sec)); -+ memset(clear_key, 0, clear_key_size); -+ free(clear_key); -+ free(secure_key); -+ return rc; -+} -+ -+/** -+ * 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 -+ * @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[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, -+ u8 *secure_key, size_t secure_key_size, -+ u16 part1_keysize, u32 part1_attributes, -+ size_t *clear_key_bitsize, bool verbose) -+{ -+ struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; -+ struct pkey_verifykey verifykey; -+ struct secaeskeytoken *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); -+ -+ if (secure_key_size != 2 * SECURE_KEY_SIZE) { -+ pr_verbose(verbose, "Size of secure key is too small: " -+ "%lu expected %lu", secure_key_size, -+ 2 * SECURE_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); -+ if (rc < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to validate a 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 (verifykey.keysize != part1_keysize) { -+ pr_verbose(verbose, "XTS secure key contains 2 keys using " -+ "different key sizes"); -+ return -EINVAL; -+ } -+ -+ if (verifykey.attributes != part1_attributes) { -+ pr_verbose(verbose, "XTS secure key contains 2 keys using " -+ "different attributes"); -+ return -EINVAL; -+ } -+ -+ if (clear_key_bitsize) -+ *clear_key_bitsize += verifykey.keysize; -+ -+ return 0; -+} -+ -+/** -+ * Validates a secure key -+ * -+ * @param[in] pkey_fd the pkey file descriptor -+ * @param[in] secure_key a buffer containing the secure key -+ * @param[in] secure_key_size the secure key size -+ * @param[out] clear_key_bitsize on return , the cryptographic size of the -+ * 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] verbose if true, verbose messages are printed -+ * -+ * @returns 0 on success, a negative errno in case of an error -+ */ -+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) -+{ -+ struct secaeskeytoken *token = (struct secaeskeytoken *)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) { -+ pr_verbose(verbose, "Size of secure key is too small: " -+ "%lu expected %lu", secure_key_size, -+ SECURE_KEY_SIZE); -+ return -EINVAL; -+ } -+ -+ memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey)); -+ -+ rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey); -+ if (rc < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to validate a 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 > SECURE_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) -+ *is_old_mk = (verifykey.attributes & -+ PKEY_VERIFY_ATTR_OLD_MKVP) != 0; -+ -+ pr_verbose(verbose, "Secure key validation completed successfully"); -+ -+ return 0; -+} ---- a/zkey/pkey.h -+++ b/zkey/pkey.h -@@ -4,7 +4,7 @@ - * This header file defines the interface to the pkey kernel module. - * It defines a set of IOCTL commands with its associated structures. - * -- * Copyright 2017 IBM Corp. -+ * Copyright IBM Corp. 2017, 2018 - * - * s390-tools is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. -@@ -82,4 +82,44 @@ struct pkey_verifykey { - - #define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey) - --#endif -\ No newline at end of file -+#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); -+ -+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, -+ size_t keybits, bool xts, 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, -+ u16 card, u16 domain, -+ bool verbose); -+ -+u8 *read_secure_key(const char *keyfile, size_t *secure_key_size, -+ bool verbose); -+ -+int write_secure_key(const char *keyfile, const u8 *secure_key, -+ size_t secure_key_size, bool verbose); -+ -+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); -+ -+int key_token_change(t_CSNBKTC dll_CSNBKTC, -+ u8 *secure_key, unsigned int secure_key_size, -+ char *method, bool verbose); -+ -+#endif ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -188,9 +188,6 @@ static struct zkey_command zkey_commands - #define pr_verbose(fmt...) if (g.verbose) \ - warnx(fmt) - --#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) (xts) ? 2 * (keysize) : (keysize) --#define HALF_KEYSIZE_FOR_XTS(keysize, xts) (xts) ? (keysize) / 2 : (keysize) -- - static void print_usage_command(const struct zkey_command *command) - { - char command_str[ZKEY_COMMAND_STR_LEN]; -@@ -253,19 +250,6 @@ static void print_help(const struct zkey - } - - /* -- * Definitions for the CCA library -- */ --#define CCA_LIBRARY_NAME "libcsulcca.so" -- --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); -- --/* - * Global variables for program options - */ - static struct zkey_globals { -@@ -283,212 +267,6 @@ static struct zkey_globals { - .pkey_fd = -1, - }; - --#define DEFAULT_KEYBITS 256 -- --static int load_cca_library(void) --{ -- /* Load the CCA library */ -- g.lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW); -- if (g.lib_csulcca == NULL) { -- warnx("%s\nEnsure that the IBM CCA Host Libraries and " -- "Tools are installed properly", dlerror()); -- return EXIT_FAILURE; -- } -- -- /* Get the Key Token Change function */ -- g.dll_CSNBKTC = (t_CSNBKTC)dlsym(g.lib_csulcca, "CSNBKTC"); -- if (g.dll_CSNBKTC == NULL) { -- warnx("%s\nEnsure that the IBM CCA Host Libraries and " -- "Tools are installed properly", dlerror()); -- dlclose(g.lib_csulcca); -- g.lib_csulcca = NULL; -- return EXIT_FAILURE; -- } -- -- pr_verbose("CCA library '%s' has been loaded successfully", -- CCA_LIBRARY_NAME); -- -- return EXIT_SUCCESS; --} -- --static int open_pkey_device(void) --{ -- g.pkey_fd = open(PKEYDEVICE, O_RDWR); -- if (g.pkey_fd < 0) { -- warnx("File '%s:' %s\nEnsure that the 'pkey' kernel module " -- "is loaded", PKEYDEVICE, strerror(errno)); -- return EXIT_FAILURE; -- } -- -- pr_verbose("Device '%s' has been opened successfully", PKEYDEVICE); -- -- return EXIT_SUCCESS; --} -- --/* -- * Read a secure key file and return the allocated buffer and size -- */ --static u8 *read_secure_key(const char *keyfile, size_t *secure_key_size) --{ -- size_t count, size; -- struct stat sb; -- char *msg; -- FILE *fp; -- u8 *buf; -- -- if (stat(keyfile, &sb)) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- return NULL; -- } -- 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); -- return NULL; -- } -- -- fp = fopen(keyfile, "r"); -- if (fp == NULL) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- return NULL; -- } -- -- buf = util_malloc(size); -- count = fread(buf, 1, size, fp); -- if (count <= 0) { -- msg = feof(fp) ? "File is too small" : strerror(errno); -- warnx("File '%s': %s", keyfile, msg); -- free(buf); -- buf = NULL; -- goto out; -- } -- -- *secure_key_size = size; -- -- if (g.verbose) { -- pr_verbose("%lu bytes read from file '%s'", size, keyfile); -- util_hexdump_grp(stderr, NULL, buf, 4, size, 0); -- } --out: -- fclose(fp); -- return buf; --} -- --/* -- * Write a secure key file -- */ --static int write_secure_key(const char *keyfile, const u8 *secure_key, -- size_t secure_key_size) --{ -- size_t count; -- FILE *fp; -- -- fp = fopen(keyfile, "w"); -- if (fp == NULL) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- return EXIT_FAILURE; -- } -- -- count = fwrite(secure_key, 1, secure_key_size, fp); -- if (count <= 0) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- fclose(fp); -- return EXIT_FAILURE; -- } -- -- if (g.verbose) { -- pr_verbose("%lu bytes written to file '%s'", -- secure_key_size, keyfile); -- util_hexdump_grp(stderr, NULL, secure_key, 4, -- secure_key_size, 0); -- } -- fclose(fp); -- return EXIT_SUCCESS; --} -- --/* -- * Read a clear key file and return the allocated buffer and size -- * -- * When keybits is 0, then the file size determines the keybits. -- */ --static u8 *read_clear_key(const char *keyfile, size_t keybits, -- size_t *clear_key_size) --{ -- size_t count, size, expected_size; -- struct stat sb; -- char *msg; -- FILE *fp; -- u8 *buf; -- -- if (stat(keyfile, &sb)) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- return NULL; -- } -- size = sb.st_size; -- -- if (keybits != 0) { -- expected_size = DOUBLE_KEYSIZE_FOR_XTS(keybits / 8, g.xts); -- if (size != expected_size) { -- warnx("File '%s' has an invalid size, " -- "%lu bytes expected", keyfile, expected_size); -- return NULL; -- } -- } else { -- keybits = DOUBLE_KEYSIZE_FOR_XTS(size * 8, g.xts); -- } -- -- switch (keybits) { -- case 128: -- break; -- case 192: -- if (g.xts) { -- warnx("File '%s' has an invalid size, " -- "192 bit keys are not supported with XTS", -- keyfile); -- return NULL; -- } -- break; -- case 256: -- break; -- default: -- if (g.xts) -- warnx("File '%s' has an invalid size, " -- "32 or 64 bytes expected", keyfile); -- else -- warnx("File '%s' has an invalid size, 16, 24 " -- "or 32 bytes expected", keyfile); -- return NULL; -- } -- -- fp = fopen(keyfile, "r"); -- if (fp == NULL) { -- warnx("File '%s': %s", keyfile, strerror(errno)); -- return NULL; -- } -- -- buf = util_malloc(size); -- count = fread(buf, 1, size ,fp); -- if (count <= 0) { -- msg = feof(fp) ? "File is too small" : strerror(errno); -- warnx("File '%s': %s", keyfile, msg); -- free(buf); -- buf = NULL; -- goto out; -- } -- -- *clear_key_size = size; -- -- if (g.verbose) { -- pr_verbose("%lu bytes read from file '%s'", size, keyfile); -- util_hexdump_grp(stderr, NULL, buf, 4, size, 0); -- } --out: -- fclose(fp); -- return buf; --} -- - /* - * Command handler for 'generate with clear key' - * -@@ -496,76 +274,15 @@ out: - */ - static int command_generate_clear(const char *keyfile) - { -- struct pkey_clr2seck clr2sec; -- size_t secure_key_size; -- size_t clear_key_size; -- u8 *secure_key; -- u8 *clear_key; - int rc; - -- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, g.xts); -- secure_key = util_malloc(secure_key_size); -- -- clear_key = read_clear_key(g.clearkeyfile, g.keybits, &clear_key_size); -- if (clear_key == NULL) -- return EXIT_FAILURE; -- -- clr2sec.cardnr = AUTOSELECT; -- clr2sec.domain = AUTOSELECT; -- switch (HALF_KEYSIZE_FOR_XTS(clear_key_size * 8, g.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: -- warnx("Invalid clear key size: '%lu' bytes", clear_key_size); -- rc = EXIT_FAILURE; -- goto out; -- } -- -- memcpy(&clr2sec.clrkey, clear_key, -- HALF_KEYSIZE_FOR_XTS(clear_key_size, g.xts)); -- -- rc = ioctl(g.pkey_fd, PKEY_CLR2SECK, &clr2sec); -- if (rc < 0) { -- warnx("Failed to generate a secure key from a " -- "clear key: %s", strerror(errno)); -+ rc = generate_secure_key_clear(g.pkey_fd, keyfile, -+ g.keybits, g.xts, -+ g.clearkeyfile, -+ AUTOSELECT, AUTOSELECT, -+ g.verbose); -+ if (rc != 0) - rc = EXIT_FAILURE; -- goto out; -- } -- -- memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE); -- -- if (g.xts) { -- memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2, -- clear_key_size / 2); -- -- rc = ioctl(g.pkey_fd, PKEY_CLR2SECK, &clr2sec); -- if (rc < 0) { -- warnx("Failed to generate a secure key from " -- "a clear key: %s", strerror(errno)); -- rc = EXIT_FAILURE; -- goto out; -- } -- -- memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey, -- SECURE_KEY_SIZE); -- } -- -- pr_verbose("Successfully generated a secure key from a clear key"); -- -- rc = write_secure_key(keyfile, secure_key, secure_key_size); -- --out: -- memset(&clr2sec, 0, sizeof(clr2sec)); -- memset(clear_key, 0, clear_key_size); -- free(clear_key); -- free(secure_key); - return rc; - } - -@@ -576,69 +293,15 @@ out: - */ - static int command_generate_random(const char *keyfile) - { -- struct pkey_genseck gensec; -- size_t secure_key_size; -- u8 *secure_key; - int rc; - -- if (g.keybits == 0) -- g.keybits = DEFAULT_KEYBITS; -- -- secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, g.xts); -- secure_key = util_malloc(secure_key_size); -- -- gensec.cardnr = AUTOSELECT; -- gensec.domain = AUTOSELECT; -- switch (g.keybits) { -- case 128: -- gensec.keytype = PKEY_KEYTYPE_AES_128; -- break; -- case 192: -- if (g.xts) { -- warnx("Invalid value for '--keybits'|'-c' " -- "for XTS: '%lu'", g.keybits); -- rc = EXIT_FAILURE; -- goto out; -- } -- gensec.keytype = PKEY_KEYTYPE_AES_192; -- break; -- case 256: -- gensec.keytype = PKEY_KEYTYPE_AES_256; -- break; -- default: -- warnx("Invalid value for '--keybits'/'-c': '%lu'", g.keybits); -+ rc = generate_secure_key_random(g.pkey_fd, keyfile, -+ g.keybits, g.xts, -+ AUTOSELECT, AUTOSELECT, -+ g.verbose); -+ if (rc != 0) - rc = EXIT_FAILURE; -- goto out; -- } -- -- rc = ioctl(g.pkey_fd, PKEY_GENSECK, &gensec); -- if (rc < 0) { -- warnx("Failed to generate a secure key: %s", strerror(errno)); -- rc = EXIT_FAILURE; -- goto out; -- } -- -- memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE); -- -- if (g.xts) { -- rc = ioctl(g.pkey_fd, PKEY_GENSECK, &gensec); -- if (rc < 0) { -- warnx("Failed to generate a secure key: %s", -- strerror(errno)); -- rc = EXIT_FAILURE; -- goto out; -- } -- -- memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey, -- SECURE_KEY_SIZE); -- } -- -- pr_verbose("Successfully generated a secure key"); - -- rc = write_secure_key(keyfile, secure_key, secure_key_size); -- --out: -- free(secure_key); - return rc; - } - -@@ -653,182 +316,6 @@ static int command_generate(const char * - : command_generate_random(keyfile); - } - --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; -- } --} -- --static int key_token_change(u8 *secure_key, unsigned int secure_key_size, -- char *method) --{ -- 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; -- -- memcpy(rule_array, method, 8); -- memcpy(rule_array + 8, "AES ", 8); -- rule_array_count = 2; -- -- g.dll_CSNBKTC(&return_code, &reason_code, -- &exit_data_len, exit_data, -- &rule_array_count, rule_array, -- secure_key); -- -- pr_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 EXIT_FAILURE; -- } -- -- if (secure_key_size == 2 * SECURE_KEY_SIZE) { -- g.dll_CSNBKTC(&return_code, &reason_code, -- &exit_data_len, exit_data, -- &rule_array_count, rule_array, -- secure_key + SECURE_KEY_SIZE); -- -- pr_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 EXIT_FAILURE; -- } -- } -- return EXIT_SUCCESS; --} -- --static int validate_secure_xts_key(u8 *secure_key, size_t secure_key_size, -- u16 part1_keysize, u32 part1_attributes, -- size_t *clear_key_bitsize) --{ -- struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; -- struct pkey_verifykey verifykey; -- struct secaeskeytoken *token2; -- int rc; -- -- /* XTS uses 2 secure key tokens concatenated to each other */ -- token2 = (struct secaeskeytoken *)(secure_key + SECURE_KEY_SIZE); -- -- if (secure_key_size != 2 * SECURE_KEY_SIZE) { -- pr_verbose("Size of secure key is too small: %lu expected %lu", -- secure_key_size, 2 * SECURE_KEY_SIZE); -- return EXIT_FAILURE; -- } -- -- if (token->bitsize != token2->bitsize) { -- pr_verbose("XTS secure key contains 2 clear keys of " -- "different sizes"); -- return EXIT_FAILURE; -- } -- if (token->keysize != token2->keysize) { -- pr_verbose("XTS secure key contains 2 keys of different " -- "sizes"); -- return EXIT_FAILURE; -- } -- if (memcmp(&token->mkvp, &token2->mkvp, sizeof(token->mkvp)) != 0) { -- pr_verbose("XTS secure key contains 2 keys using different " -- "CCA master keys"); -- return EXIT_FAILURE; -- } -- -- memcpy(&verifykey.seckey, token2, sizeof(verifykey.seckey)); -- -- rc = ioctl(g.pkey_fd, PKEY_VERIFYKEY, &verifykey); -- if (rc < 0) { -- warnx("Failed to validate a secure key: %s", strerror(errno)); -- return EXIT_FAILURE; -- } -- -- if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) { -- pr_verbose("Secure key is not an AES key"); -- return EXIT_FAILURE; -- } -- -- if (verifykey.keysize != part1_keysize) { -- pr_verbose("XTS secure key contains 2 keys using different " -- "key sizes"); -- return EXIT_FAILURE; -- } -- -- if (verifykey.attributes != part1_attributes) { -- pr_verbose("XTS secure key contains 2 keys using different " -- "attributes"); -- return EXIT_FAILURE; -- } -- -- if (clear_key_bitsize) -- *clear_key_bitsize += verifykey.keysize; -- -- return EXIT_SUCCESS; --} -- --static int validate_secure_key(u8 *secure_key, size_t secure_key_size, -- size_t *clear_key_bitsize, int *is_old_mk) --{ -- struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key; -- struct pkey_verifykey verifykey; -- int rc; -- -- if (secure_key_size < SECURE_KEY_SIZE) { -- pr_verbose("Size of secure key is too small: %lu expected %lu", -- secure_key_size, SECURE_KEY_SIZE); -- return EXIT_FAILURE; -- } -- -- memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey)); -- -- rc = ioctl(g.pkey_fd, PKEY_VERIFYKEY, &verifykey); -- if (rc < 0) { -- warnx("Failed to validate a secure key: %s", strerror(errno)); -- return EXIT_FAILURE; -- } -- -- if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) { -- pr_verbose("Secure key is not an AES key"); -- return EXIT_FAILURE; -- } -- -- if (clear_key_bitsize) -- *clear_key_bitsize = verifykey.keysize; -- -- /* XTS uses 2 secure key tokens concatenated to each other */ -- if (secure_key_size > SECURE_KEY_SIZE) { -- rc = validate_secure_xts_key(secure_key, secure_key_size, -- verifykey.keysize, -- verifykey.attributes, -- clear_key_bitsize); -- if (rc != EXIT_SUCCESS) -- return rc; -- } -- -- if (is_old_mk) -- *is_old_mk = (verifykey.attributes & -- PKEY_VERIFY_ATTR_OLD_MKVP) != 0; -- -- pr_verbose("Secure key validation completed successfully"); -- -- return EXIT_SUCCESS; --} - - /* - * Command handler for 'reencipher'. -@@ -842,14 +329,15 @@ static int command_reencipher(const char - u8 *secure_key; - - /* Read the secure key to be re-enciphered */ -- secure_key = read_secure_key(keyfile, &secure_key_size); -+ secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose); - if (secure_key == NULL) - return EXIT_FAILURE; - -- rc = validate_secure_key(secure_key, secure_key_size, NULL, -- &is_old_mk); -- if (rc != EXIT_SUCCESS) { -+ rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, NULL, -+ &is_old_mk, g.verbose); -+ if (rc != 0) { - warnx("The secure key in file '%s' is not valid", keyfile); -+ rc = EXIT_FAILURE; - goto out; - } - -@@ -884,10 +372,14 @@ static int command_reencipher(const char - pr_verbose("Secure key will be re-enciphered from OLD to the " - "CURRENT CCA master key"); - -- rc = key_token_change(secure_key, secure_key_size, "RTCMK "); -- if (rc != EXIT_SUCCESS) { -+ rc = key_token_change(g.dll_CSNBKTC, -+ 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"); -+ rc = EXIT_FAILURE; - goto out; - } - } -@@ -895,10 +387,13 @@ static int command_reencipher(const char - pr_verbose("Secure key will be re-enciphered from CURRENT " - "to the NEW CCA master key"); - -- rc = key_token_change(secure_key, secure_key_size, "RTNMK "); -- if (rc != EXIT_SUCCESS) { -+ rc = key_token_change(g.dll_CSNBKTC, -+ 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"); -+ rc = EXIT_FAILURE; - goto out; - } - } -@@ -907,7 +402,9 @@ static int command_reencipher(const char - - /* Write the migrated secure key */ - rc = write_secure_key(g.outputfile ? g.outputfile : keyfile, -- secure_key, secure_key_size); -+ secure_key, secure_key_size, g.verbose); -+ if (rc != 0) -+ rc = EXIT_FAILURE; - out: - free(secure_key); - return rc; -@@ -927,14 +424,15 @@ static int command_validate(const char * - int rc; - - /* Read the secure key to be re-enciphered */ -- secure_key = read_secure_key(keyfile, &secure_key_size); -+ secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose); - if (secure_key == NULL) - return EXIT_FAILURE; - -- rc = validate_secure_key(secure_key, secure_key_size, &clear_key_size, -- &is_old_mk); -- if (rc != EXIT_SUCCESS) { -+ rc = validate_secure_key(g.pkey_fd, secure_key, secure_key_size, -+ &clear_key_size, &is_old_mk, g.verbose); -+ if (rc != 0) { - warnx("The secure key in file '%s' is not valid", keyfile); -+ rc = EXIT_FAILURE; - goto out; - } - -@@ -1083,13 +581,14 @@ int main(int argc, char *argv[]) - } - - if (command->need_cca_library) { -- rc = load_cca_library(); -- if (rc != EXIT_SUCCESS) -+ rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC, -+ g.verbose); -+ if (rc != 0) - goto out; - } - if (command->need_pkey_device) { -- rc = open_pkey_device(); -- if (rc != EXIT_SUCCESS) -+ g.pkey_fd = open_pkey_device(g.verbose); -+ if (g.pkey_fd == -1) - goto out; - } - diff --git a/s390-tools-sles15sp1-0005-zkey-Add-keystore-implementation.patch b/s390-tools-sles15sp1-0005-zkey-Add-keystore-implementation.patch deleted file mode 100644 index 7a007de..0000000 --- a/s390-tools-sles15sp1-0005-zkey-Add-keystore-implementation.patch +++ /dev/null @@ -1,3427 +0,0 @@ -Subject: zkey: Add keystore implementation -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: c944f23d7e1f983499b4c5fcf04430dc49902f04 -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Add keystore implementation - - Add a keystore implementation that stores secure AES keys in a - key repository, located in a directory, e.g. '/etc/zkey/repository'. - The keystore allows you to generate, validate, re-encipher, modify, - list, delete, etc secure keys. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/Makefile | 3 - zkey/keystore.c | 3299 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - zkey/keystore.h | 77 + - 3 files changed, 3378 insertions(+), 1 deletion(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -27,8 +27,9 @@ libs = $(rootdir)/libutil/libutil.a - zkey.o: zkey.c pkey.h misc.h - pkey.o: pkey.c pkey.h - properties.o: properties.c properties.h -+keystore.o: keystore.c keystore.h properties.h - --zkey: zkey.o pkey.o properties.o $(libs) -+zkey: zkey.o pkey.o properties.o keystore.o $(libs) - - install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) ---- /dev/null -+++ b/zkey/keystore.c -@@ -0,0 +1,3299 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Keystore handling functions -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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" -+#include "lib/util_rec.h" -+ -+#include "keystore.h" -+#include "pkey.h" -+#include "properties.h" -+ -+struct key_filenames { -+ char *skey_filename; -+ char *info_filename; -+ char *renc_filename; -+}; -+ -+#define FILE_EXTENSION_LEN 5 -+#define SKEY_FILE_EXTENSION ".skey" -+#define INFO_FILE_EXTENSION ".info" -+#define RENC_FILE_EXTENSION ".renc" -+ -+#define LOCK_FILE_NAME ".lock" -+ -+#define PROP_NAME_KEY_TYPE "key-type" -+#define PROP_NAME_CIPHER "cipher" -+#define PROP_NAME_IV_MODE "iv-mode" -+#define PROP_NAME_DESCRIPTION "description" -+#define PROP_NAME_VOLUMES "volumes" -+#define PROP_NAME_APQNS "apqns" -+#define PROP_NAME_SECTOR_SIZE "sector-size" -+#define PROP_NAME_CREATION_TIME "creation-time" -+#define PROP_NAME_CHANGE_TIME "update-time" -+#define PROP_NAME_REENC_TIME "reencipher-time" -+ -+#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" -+#define REC_CLR_KEY_SIZE "Clear key size" -+#define REC_XTS "XTS type key" -+#define REC_VOLUMES "Volumes" -+#define REC_APQNS "APQNs" -+#define REC_KEY_FILE "Key file name" -+#define REC_SECTOR_SIZE "Sector size" -+#define REC_STATUS "Status" -+#define REC_MASTERKEY "Encrypted with" -+#define REC_CREATION_TIME "Created" -+#define REC_CHANGE_TIME "Changed" -+#define REC_REENC_TIME "Re-enciphered" -+ -+#define pr_verbose(keystore, fmt...) do { \ -+ if (keystore->verbose) \ -+ warnx(fmt); \ -+ } while (0) -+ -+/** -+ * Gets the file names of the .skey and .info and .renc files for a named -+ * key in the key strore's directory -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[out] names is filled with the names of the files -+ * -+ * @returns 0 for success or a negative errno in case of an error* -+ */ -+static int _keystore_get_key_filenames(struct keystore *keystore, -+ const char *name, -+ struct key_filenames *names) -+{ -+ if (strpbrk(name, "/\\ *?'\"")) { -+ warnx("Key name '%s' contains invalid characters", name); -+ return -EINVAL; -+ } -+ -+ util_asprintf(&names->skey_filename, "%s/%s%s", keystore->directory, -+ name, SKEY_FILE_EXTENSION); -+ util_asprintf(&names->info_filename, "%s/%s%s", keystore->directory, -+ name, INFO_FILE_EXTENSION); -+ util_asprintf(&names->renc_filename, "%s/%s%s", keystore->directory, -+ name, RENC_FILE_EXTENSION); -+ -+ pr_verbose(keystore, "File names for key '%s': '%s' and '%s'", name, -+ names->skey_filename, names->info_filename); -+ return 0; -+} -+ -+/** -+ * Checks if the .renc file exists. -+ * -+ * @param[in] file_names names of the files -+ * -+ * @returns 1 if the file exist, 0 if the file do not exist -+ */ -+static int _keystore_reencipher_key_exists(struct key_filenames *file_names) -+{ -+ struct stat sb; -+ int rc; -+ -+ rc = stat(file_names->renc_filename, &sb); -+ if (rc == 0 && !S_ISREG(sb.st_mode)) -+ rc = 1; -+ -+ return !rc; -+} -+ -+/** -+ * Checks if both, the .skey and the .info (and .renc) files exist. -+ * -+ * @param[in] file_names names of the files -+ * -+ * @returns 1 if all files exist, 0 if all files do not exist, -1 if one -+ * file exists but other one does not exist (inconsistent state) -+ */ -+static int _keystore_exists_keyfiles(struct key_filenames *file_names) -+{ -+ struct stat sb_skey, sb_info; -+ int rc_skey, rc_info; -+ -+ rc_skey = stat(file_names->skey_filename, &sb_skey); -+ if (rc_skey == 0 && !S_ISREG(sb_skey.st_mode)) -+ rc_skey = 1; -+ -+ rc_info = stat(file_names->info_filename, &sb_info); -+ if (rc_info == 0 && !S_ISREG(sb_info.st_mode)) -+ rc_info = 1; -+ -+ if (rc_skey == 0 && rc_info == 0) -+ return 1; -+ if (rc_skey != 0 && rc_info != 0 && -+ _keystore_reencipher_key_exists(file_names) == 0) -+ return 0; -+ return -1; -+} -+ -+/** -+ * Checks if the files belonging to a key exist. If not an appropriate error -+ * message is issued. -+ * -+ * @param[in] file_names names of the files -+ * @param[in] name name of the key -+ * -+ * @returns 0 if the files exist, -ENOENT if the files do not exist, -EPERM if -+ * one file exists but the other does not exist (inconsistent state) -+ */ -+static int _keystore_ensure_keyfiles_exist(struct key_filenames *file_names, -+ const char *name) -+{ -+ int rc; -+ -+ rc = _keystore_exists_keyfiles(file_names); -+ if (rc == 0) { -+ warnx("Key '%s' does not exist", name); -+ return -ENOENT; -+ } -+ if (rc == -1) { -+ warnx("Key '%s' is in an inconsistent state", name); -+ return -EPERM; -+ } -+ -+ return 0; -+} -+ -+/** -+ * Checks if the files belonging to a key do not exist. If they files exist, -+ * an appropriate error message is issued. -+ * -+ * @param[in] file_names names of the files -+ * @param[in] name name of the key -+ * -+ * @returns 0 if the files exist, -EEXIST if the files exist already, -EPERM if -+ * one file exists but the other does not exist (inconsistent state) -+ */ -+static int _keystore_ensure_keyfiles_not_exist(struct key_filenames *file_names, -+ const char *name) -+{ -+ int rc; -+ -+ rc = _keystore_exists_keyfiles(file_names); -+ if (rc == 1) { -+ warnx("Key '%s' exists already", name); -+ return -EEXIST; -+ } -+ if (rc == -1) { -+ warnx("Key '%s' is in an inconsistent state", name); -+ return -EPERM; -+ } -+ -+ return 0; -+} -+ -+/** -+ * Frees the file names stored inside the struct key_filenames -+ * -+ * @param[in] names names of the files -+ */ -+static void _keystore_free_key_filenames(struct key_filenames *names) -+{ -+ if (names->skey_filename) -+ free(names->skey_filename); -+ if (names->info_filename) -+ free(names->info_filename); -+ if (names->renc_filename) -+ free(names->renc_filename); -+} -+ -+/** -+ * Sets the file permissions of the file to the permissions and the group -+ * of the repository directory -+ * -+ * @param[in] keystroe the keystore -+ * @param[in] filename the name of the file to set permissions for -+ * -+ * @returns 0 on success, or a negative errno value on failure -+ */ -+static int _keystore_set_file_permission(struct keystore *keystore, -+ const char *filename) -+{ -+ int rc; -+ -+ if (chmod(filename, keystore->mode) != 0) { -+ rc = -errno; -+ warnx("chmod faild on file '%s': %s", filename, strerror(-rc)); -+ return rc; -+ } -+ -+ if (chown(filename, geteuid(), keystore->owner) != 0) { -+ rc = -errno; -+ warnx("chown faild on file '%s': %s", filename, strerror(-rc)); -+ return rc; -+ } -+ -+ return 0; -+} -+ -+/** -+ * Checks if the sector size is power of two and in range 512 - 4096 bytes. -+ * -+ * @param[in] sector_size the sector size -+ * -+ * @returns 1 if the sector size is valid, 0 otherwise -+ */ -+static int _keystore_valid_sector_size(size_t sector_size) -+{ -+ if (sector_size == 0) -+ return 1; -+ if (sector_size < 512 || sector_size > 4096) -+ return 0; -+ if (sector_size & (sector_size - 1)) -+ return 0; -+ return 1; -+} -+ -+typedef int (*check_association_t)(const char *value, bool remove, -+ char **normalized, void *private); -+ -+/** -+ * Set an association property. For each object set function check_func is -+ * called (if not NULL). -+ * -+ * @param[in/out] key_props the properties object to modify -+ * @param[in] property the name of the property to modify -+ * @param[in] newvalue the new value(s) to add, remove or set -+ * @param[in] msg_obj the name of the object for error messages -+ * @param[in] check_func a function to call on each object before it is -+ * added, removed or set to the property -+ * @param[in] check_private a private pointer passed to check_func -+ * -+ * @returns 0 for success, or a negative errno value in case of an error, or -+ * whatever check_func returns if check_func returns a non-zero value. -+ */ -+static int _keystore_set_association(struct properties *key_props, -+ const char *property, -+ const char *newvalue, -+ const char *msg_obj, -+ check_association_t check_func, -+ void *check_private) -+{ -+ char *normalized = NULL; -+ char **newvals = NULL; -+ char *value = NULL; -+ char *changedval; -+ char *newval; -+ int i, rc = 0; -+ -+ newvals = str_list_split(newvalue); -+ if (newvals == NULL) -+ return -EINVAL; -+ -+ for (i = 0; newvals[i] != NULL; i++) { -+ if (check_func != NULL) { -+ rc = check_func(newvals[i], 0, &normalized, -+ check_private); -+ if (rc != 0) -+ goto out; -+ } -+ -+ newval = normalized != NULL ? normalized : newvals[i]; -+ if (value == NULL) -+ changedval = str_list_add("", newval); -+ else -+ changedval = str_list_add(value, newval); -+ if (changedval == NULL) { -+ warnx("The %s '%s' is already specified or contains " -+ "invalid characters", msg_obj, newval); -+ rc = -EEXIST; -+ goto out; -+ } -+ if (normalized != NULL) -+ free(normalized); -+ normalized = NULL; -+ free(value); -+ value = changedval; -+ } -+ -+ rc = properties_set(key_props, property, value != NULL ? value : ""); -+ if (rc != 0) -+ warnx("Invalid characters in %ss", msg_obj); -+ -+out: -+ if (newvals != NULL) -+ str_list_free_string_array(newvals); -+ if (value != NULL) -+ free(value); -+ if (normalized != NULL) -+ free(normalized); -+ return rc; -+} -+ -+/** -+ * Add a value to an association property. For each object added function -+ * check_func is called (if not NULL). -+ * -+ * @param[in/out] key_props the properties object to modify -+ * @param[in] property the name of the property to modify -+ * @param[in] newvalue the new value(s) to add, remove or set -+ * @param[in] msg_obj the name of the object for error messages -+ * @param[in] check_func a function to call on each object before it is -+ * added, removed or set to the property -+ * @param[in] check_private a private pointer passed to check_func -+ * -+ * @returns 0 for success, or a negative errno value in case of an error, or -+ * whatever check_func returns if check_func returns a non-zero value. -+ */ -+static int _keystore_add_association(struct properties *key_props, -+ const char *property, -+ const char *newvalue, -+ const char *msg_obj, -+ check_association_t check_func, -+ void *check_private) -+{ -+ char *normalized = NULL; -+ char **newvals = NULL; -+ char *changedval; -+ char *newval; -+ int i, rc = 0; -+ char *value; -+ -+ value = properties_get(key_props, property); -+ if (value == NULL) -+ return _keystore_set_association(key_props, property, -+ newvalue, msg_obj, -+ check_func, check_private); -+ -+ newvals = str_list_split(newvalue); -+ if (newvals == NULL) { -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ for (i = 0; newvals[i] != NULL; i++) { -+ if (check_func != NULL) { -+ rc = check_func(newvals[i], 0, &normalized, -+ check_private); -+ if (rc != 0) -+ goto out; -+ } -+ -+ newval = normalized != NULL ? normalized : newvals[i]; -+ changedval = str_list_add(value, newval); -+ if (changedval == NULL) { -+ warnx("The %s '%s' is already associated with this key " -+ "or contains invalid characters", msg_obj, -+ newval); -+ rc = -EEXIST; -+ goto out; -+ } -+ if (normalized != NULL) -+ free(normalized); -+ normalized = NULL; -+ free(value); -+ value = changedval; -+ } -+ -+ rc = properties_set(key_props, property, value); -+ if (rc != 0) -+ warnx("Invalid characters in %ss", msg_obj); -+ -+out: -+ if (newvals != NULL) -+ str_list_free_string_array(newvals); -+ if (value != NULL) -+ free(value); -+ if (normalized != NULL) -+ free(normalized); -+ return rc; -+} -+ -+/** -+ * Removes a value from an association property. For each object removed -+ * function check_func is called (if not NULL). -+ * -+ * @param[in/out] key_props the properties object to modify -+ * @param[in] property the name of the property to modify -+ * @param[in] delvalue the value(s) to remove -+ * @param[in] msg_obj the name of the object for error messages -+ * @param[in] check_func a function to call on each object before it is -+ * added, removed or set to the property -+ * @param[in] check_private a private pointer passed to check_func -+ * -+ * @returns 0 for success, or a negative errno value in case of an error, or -+ * whatever check_func returns if check_func returns a non-zero value. -+ */ -+static int _keystore_remove_association(struct properties *key_props, -+ const char *property, -+ const char *delvalue, -+ const char *msg_obj, -+ check_association_t check_func, -+ void *check_private) -+{ -+ char *normalized = NULL; -+ char **delvals = NULL; -+ char *changedval; -+ char *delval; -+ int i, rc = 0; -+ char *value; -+ -+ value = properties_get(key_props, property); -+ if (value == NULL) { -+ warnx("No %ss are currently associated with this key", msg_obj); -+ return -ENOENT; -+ } -+ -+ delvals = str_list_split(delvalue); -+ if (delvals == NULL) { -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ for (i = 0; delvals[i] != NULL; i++) { -+ if (check_func != NULL) { -+ rc = check_func(delvals[i], 1, &normalized, -+ check_private); -+ if (rc != 0) -+ goto out; -+ } -+ -+ delval = normalized != NULL ? normalized : delvals[i]; -+ changedval = str_list_remove(value, delval); -+ if (changedval == NULL) { -+ warnx("%s '%s' is not associated with this key", -+ msg_obj, delval); -+ rc = -ENOENT; -+ goto out; -+ } -+ if (normalized != NULL) -+ free(normalized); -+ normalized = NULL; -+ free(value); -+ value = changedval; -+ } -+ -+ rc = properties_set(key_props, property, value); -+ if (rc != 0) -+ warnx("Invalid characters in %ss", msg_obj); -+ -+out: -+ if (delvals != NULL) -+ str_list_free_string_array(delvals); -+ if (value != NULL) -+ free(value); -+ if (normalized != NULL) -+ free(normalized); -+ return rc; -+} -+ -+/** -+ * Change an association property. This function adds the objects in the -+ * comma separated string when newvalue begins with a '+'. It removes the -+ * objects when newvalue begins with a '-', or it sets the property to -+ * newvalue when newvalue does not begin with '+' or '-'. For each object -+ * added, Removed or set function check_func is called (if not NULL). -+ * -+ * @param[in/out] key_props the properties object to modify -+ * @param[in] property the name of the property to modify -+ * @param[in] newvalue the new value(s) to add, remove or set -+ * @param[in] msg_obj the name of the object for error messages -+ * @param[in] check_func a function to call on each object before it is -+ * added, removed or set to the property -+ * @param[in] check_private a private pointer passed to check_func -+ * -+ * @returns 0 for success, or a negative errno value in case of an error, or -+ * whatever check_func returns if check_func returns a non-zero value. -+ */ -+static int _keystore_change_association(struct properties *key_props, -+ const char *property, -+ const char *newvalue, -+ const char *msg_obj, -+ check_association_t check_func, -+ void *check_private) -+{ -+ switch (*newvalue) { -+ case '+': -+ return _keystore_add_association(key_props, property, -+ &newvalue[1], msg_obj, -+ check_func, check_private); -+ case '-': -+ return _keystore_remove_association(key_props, property, -+ &newvalue[1], msg_obj, -+ check_func, check_private); -+ default: -+ return _keystore_set_association(key_props, property, -+ newvalue, msg_obj, -+ check_func, check_private); -+ -+ } -+} -+ -+/** -+ * Filter match function for APQNs -+ * -+ * @param[in] pattern the pattern to match -+ * @param[in] apqn the apqn to match -+ * @param[in] flags Not used here -+ * -+ * @returns Zero if string matches pattern, FNM_NOMATCH if there is no match -+ * or another nonzero value if there is an error. -+ */ -+static int _keystore_apqn_match(const char *pattern, const char *apqn, -+ int UNUSED(flags)) -+{ -+ char *modified; -+ char *pattern_domain; -+ char *pattern_card; -+ char *copy; -+ int card, domain; -+ size_t i; -+ char *ch; -+ int rc; -+ -+ if (sscanf(pattern, "%x.%x", &card, &domain) == 2) { -+ util_asprintf(&modified, "%02x.%04x", card, domain); -+ goto match; -+ } -+ -+ copy = util_strdup(pattern); -+ -+ ch = strchr(copy, '.'); -+ if (ch != NULL) { -+ *ch = '\0'; -+ pattern_card = copy; -+ pattern_domain = ch + 1; -+ -+ modified = NULL; -+ if (strchr(pattern_card, '*') == NULL && -+ strlen(pattern_card) < 2) { -+ for (i = 0; i < 2 - strlen(pattern_card); i++) -+ modified = util_strcat_realloc(modified, "0"); -+ } -+ modified = util_strcat_realloc(modified, pattern_card); -+ -+ modified = util_strcat_realloc(modified, "."); -+ -+ if (strchr(pattern_domain, '*') == NULL && -+ strlen(pattern_domain) < 4) { -+ for (i = 0; i < 4 - strlen(pattern_domain); i++) -+ modified = util_strcat_realloc(modified, "0"); -+ } -+ modified = util_strcat_realloc(modified, pattern_domain); -+ } else { -+ modified = util_strdup(copy); -+ } -+ free(copy); -+ -+match: -+ rc = fnmatch(modified, apqn, FNM_CASEFOLD); -+ -+ free(modified); -+ return rc; -+} -+ -+typedef int (*filter_match_t)(const char *pattern, const char *string, -+ int flags); -+ -+/* -+ * Checks if the value matches the filter list. The value can be a comma -+ * separated string. -+ * -+ * If the filter values contain a second part separated by a colon (':'), then -+ * the filter matches only if both parts match. If the filter values do not -+ * contain a second part,then only the first part is checked, and the second -+ * parts of the values are ignored. -+ * -+ * @param[in] value the value to check -+ * @param[in] filter_list a list of filter strings to match the value with -+ * @param[in] match_func the filter match function. If NULL fnmatch() is used. -+ * -+ * @returns 1 for a match, 0 for not matched -+ */ -+static int _keystore_match_filter(const char *value, -+ char **filter_list, -+ filter_match_t match_func) -+{ -+ char **value_list; -+ int i, k, rc = 0; -+ char *ch; -+ -+ if (filter_list == NULL) -+ return 1; -+ -+ if (match_func == NULL) -+ match_func = fnmatch; -+ -+ value_list = str_list_split(value); -+ for (i = 0; filter_list[i] != NULL && rc == 0; i++) { -+ for (k = 0; value_list[k] != NULL; k++) { -+ /* -+ * Ignore part after ':' of value if filter does -+ * not also contain a ':' part. -+ */ -+ if (strchr(filter_list[i], ':') == NULL) { -+ ch = strchr(value_list[k], ':'); -+ if (ch != NULL) -+ *ch = '\0'; -+ } -+ -+ if (match_func(filter_list[i], value_list[k], 0) == 0) { -+ rc = 1; -+ break; -+ } -+ } -+ } -+ -+ str_list_free_string_array(value_list); -+ return rc; -+} -+ -+/* -+ * Checks if the property value matches the filter list. The property value -+ * can be a comma separated string. -+ * -+ * If the filter values contain a second part separated by a colon (':'), then -+ * the filter matches only if both parts match. If the filter values do not -+ * contain a second part,then only the first part is checked, and the second -+ * parts of the values are ignored. -+ * -+ * @param[in] properties a properties object -+ * @param[in] property the name of the property to check -+ * @param[in] filter_list a list of filter strings to match the value with -+ * @param[in] match_func the filter match function. If NULL fnmatch() is used. -+ * -+ * @returns 1 for a match, 0 for not matched -+ */ -+static int _keystore_match_filter_property(struct properties *properties, -+ const char *property, -+ char **filter_list, -+ filter_match_t match_func) -+{ -+ char *value; -+ int rc; -+ -+ if (filter_list == NULL) -+ return 1; -+ -+ value = properties_get(properties, property); -+ if (value == NULL) -+ return 0; -+ -+ rc = _keystore_match_filter(value, filter_list, match_func); -+ -+ free(value); -+ return rc; -+} -+ -+/** -+ * Checks if a key name matches a name filter -+ * -+ * @param[in] name the name to check -+ * @param[in] name_filter the name filter to match against -+ * -+ * @returns 1 if the filter matches, 0 otherwise -+ */ -+static int _keystore_match_name_filter(const char *name, -+ const char *name_filter) -+{ -+ if (name_filter == NULL) -+ return 1; -+ -+ if (fnmatch(name_filter, name, 0) != 0) -+ return 0; -+ -+ return 1; -+} -+ -+/** -+ * Filters directory entries for scanfile(). Only entries that are regular -+ * files and who's name ends with '.info' are matched. -+ */ -+static int _keystore_info_file_filter(const struct dirent *dirent) -+{ -+ size_t len; -+ -+ if (dirent->d_type != DT_REG) -+ return 0; -+ -+ len = strlen(dirent->d_name); -+ if (len > FILE_EXTENSION_LEN && -+ strcmp(&dirent->d_name[len - FILE_EXTENSION_LEN], -+ INFO_FILE_EXTENSION) == 0) -+ return 1; -+ -+ return 0; -+} -+ -+typedef int (*process_key_t)(struct keystore *keystore, -+ const char *name, struct properties *properties, -+ struct key_filenames *file_names, void *private); -+ -+/** -+ * Iterates over all keys stored in the keystore. For every key that matches -+ * the specified filter process_func is called. -+ * -+ * @param[in] keystore the key store -+ * @param[in] name_filter the name filter. Can contain wild cards. -+ * NULL means no name filter. -+ * @param[in] volume_filter the volume filter. Can contain wild cards, and -+ * mutliple volume filters separated by commas. -+ * If the filter does not contain the ':dm-name' part, -+ * then the volumes are matched without the dm-name -+ * part. If the filter contains the ':dm-name' part, -+ * then the filter is matched including the dm-name -+ * part. -+ * NULL means no volume filter. -+ * specification is ignored for filter matching. -+ * @param[in] apqn_filter the APQN filter. Can contain wild cards, and -+ * mutliple APQN filters separated by commas. -+ * NULL means no APQN 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 -+ * -+ * @returns 0 for success, or a negative errno value in case of an error, or -+ * whatever process_func returns if process_func returns a non-zero -+ * value. -+ */ -+static int _keystore_process_filtered(struct keystore *keystore, -+ const char *name_filter, -+ const char *volume_filter, -+ const char *apqn_filter, -+ process_key_t process_func, -+ void *process_private) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ char **apqn_filter_list = NULL; -+ char **vol_filter_list = NULL; -+ struct properties *key_props; -+ struct dirent **namelist; -+ int n, i, rc = 0; -+ bool skip = 0; -+ char *name; -+ int len; -+ -+ pr_verbose(keystore, "Process_filtered: name_filter = '%s', " -+ "volume_filter = '%s', apqn_filter = '%s'", name_filter, -+ volume_filter, apqn_filter); -+ -+ if (volume_filter != NULL) -+ vol_filter_list = str_list_split(volume_filter); -+ if (apqn_filter != NULL) -+ apqn_filter_list = str_list_split(apqn_filter); -+ -+ n = scandir(keystore->directory, &namelist, _keystore_info_file_filter, -+ alphasort); -+ if (n == -1) { -+ rc = -errno; -+ pr_verbose(keystore, "scandir failed with: %s", strerror(-rc)); -+ return rc; -+ } -+ -+ for (i = 0; i < n ; i++) { -+ if (skip) -+ goto free; -+ -+ name = namelist[i]->d_name; -+ len = strlen(name); -+ if (len > FILE_EXTENSION_LEN) -+ name[len - FILE_EXTENSION_LEN] = '\0'; -+ -+ if (_keystore_match_name_filter(name, name_filter) == 0) { -+ pr_verbose(keystore, -+ "Key '%s' filtered out due to name filter", -+ name); -+ goto free; -+ } -+ -+ rc = _keystore_get_key_filenames(keystore, name, &file_names); -+ if (rc != 0) -+ goto free; -+ -+ rc = _keystore_ensure_keyfiles_exist(&file_names, name); -+ if (rc != 0) -+ goto free_names; -+ -+ key_props = properties_new(); -+ rc = properties_load(key_props, file_names.info_filename, 1); -+ if (rc != 0) { -+ warnx("Key '%s' does not exist or is invalid", name); -+ goto free_prop; -+ } -+ -+ rc = _keystore_match_filter_property(key_props, -+ PROP_NAME_VOLUMES, -+ vol_filter_list, NULL); -+ if (rc == 0) { -+ pr_verbose(keystore, -+ "Key '%s' filtered out due to volumes filter", -+ name); -+ goto free_prop; -+ } -+ -+ rc = _keystore_match_filter_property(key_props, -+ PROP_NAME_APQNS, -+ apqn_filter_list, -+ _keystore_apqn_match); -+ if (rc == 0) { -+ pr_verbose(keystore, -+ "Key '%s' filtered out due to APQN filter", -+ name); -+ goto free_prop; -+ } -+ -+ rc = process_func(keystore, name, key_props, &file_names, -+ process_private); -+ if (rc != 0) { -+ pr_verbose(keystore, "Process function returned %d", -+ rc); -+ skip = 1; -+ } -+ -+free_prop: -+ properties_free(key_props); -+free_names: -+ _keystore_free_key_filenames(&file_names); -+free: -+ free(namelist[i]); -+ } -+ free(namelist); -+ -+ if (vol_filter_list) -+ str_list_free_string_array(vol_filter_list); -+ if (apqn_filter_list) -+ str_list_free_string_array(apqn_filter_list); -+ -+ pr_verbose(keystore, "Process_filtered rc = %d", rc); -+ 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; -+} -+ -+/** -+ * Checks an APQN value for its syntax. This is a callback function for -+ * function _keystore_change_association(). -+ * -+ * @param[in] apqn the APQN value to check -+ * @param[in] remove if true the apqn is removed -+ * @param[out] normalized normalized value on return or NULL if no change -+ * @param[in] private private data (not used here) -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+static int _keystore_apqn_check(const char *apqn, bool remove, -+ char **normalized, void *UNUSED(private)) -+{ -+ int rc, card, domain; -+ regmatch_t pmatch[1]; -+ regex_t reg_buf; -+ -+ *normalized = NULL; -+ -+ rc = regcomp(®_buf, "[[:xdigit:]]+\\.[[:xdigit:]]", REG_EXTENDED); -+ if (rc != 0) -+ return -EIO; -+ -+ rc = regexec(®_buf, apqn, (size_t) 1, pmatch, 0); -+ if (rc != 0) { -+ warnx("the APQN '%s' is not valid", apqn); -+ return -EINVAL; -+ } -+ -+ if (sscanf(apqn, "%x.%x", &card, &domain) != 2) -+ return -EINVAL; -+ -+ util_asprintf(normalized, "%02x.%04x", card, domain); -+ -+ if (remove) -+ return 0; -+ -+ rc = _keystore_is_apqn_online(card, domain); -+ if (rc != 1) { -+ warnx("The APQN %02x.%04x is %s", card, domain, -+ rc == -1 ? "not a CCA card" : "not online"); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+ -+struct volume_check { -+ struct keystore *keystore; -+ const char *name; -+ const char *volume; -+}; -+ -+/** -+ * Processing callback function for the volume association check function. -+ * -+ * @param[in] keystore the keystore (not used here) -+ * @param[in] name the name of the key -+ * @param[in] properties the properties object of the key (not used here) -+ * @param[in] file_names the file names used by this key (not used here) -+ * @param[in] private private data: struct volume_check -+ * -+ * @returns 0 if the key name is equal to the key we are checking the volume -+ * associations for, -EINVAL otherwise (i.e. to indicate duplicate -+ * volume association) -+ */ -+static int _keystore_volume_check_process(struct keystore *UNUSED(keystore), -+ const char *name, -+ struct properties *UNUSED(properties), -+ struct key_filenames -+ *UNUSED(file_names), -+ void *private) -+{ -+ struct volume_check *info = (struct volume_check *)private; -+ -+ warnx("Key '%s' is already associated with volume '%s'", name, -+ info->volume); -+ return -EINVAL; -+} -+ -+/** -+ * Checks if the volume is a block device -+ * -+ * @param[in] volume the volume to check -+ * -+ * @return 1 if the volume is a block device, 0 otherwise -+ */ -+static int _keystore_is_block_device(const char *volume) -+{ -+ struct stat sb; -+ -+ if (stat(volume, &sb)) -+ return 0; -+ if (!S_ISBLK(sb.st_mode)) -+ return 0; -+ -+ return 1; -+} -+ -+/** -+ * Checks an Volume value for its syntax and if it is already associated with -+ * another key. This is a callback function for function -+ * _keystore_change_association(). -+ * -+ * @param[in] volume the Volume value to check -+ * @param[in] remove if true the volume is removed -+ * @param[out] normalized normalized value on return or NULL if no change -+ * @param[in] private private data: struct volume_check -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+static int _keystore_volume_check(const char *volume, bool remove, -+ char **normalized, void *private) -+{ -+ struct volume_check *info = (struct volume_check *)private; -+ char *ch; -+ int rc; -+ -+ *normalized = NULL; -+ -+ if (strpbrk(volume, "*?") != NULL) { -+ warnx("Volume name can not contain '*' or '?'"); -+ return -EINVAL; -+ } -+ -+ info->volume = util_strdup(volume); -+ ch = strchr(info->volume, ':'); -+ if (ch == NULL || strlen(ch + 1) == 0) { -+ warnx("Volume specification must contain a dm-crypt mapping " -+ "name separated by a colon"); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ if (remove) { -+ rc = 0; -+ goto out; -+ } -+ -+ /* -+ * Strip off the ':dm-name' part, so that the volume filter only -+ * matches the volume part. -+ */ -+ *ch = '\0'; -+ -+ if (!_keystore_is_block_device(info->volume)) { -+ warnx("Volume '%s' is not a block device or is not available", -+ info->volume); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = _keystore_process_filtered(info->keystore, NULL, info->volume, -+ NULL, _keystore_volume_check_process, -+ info); -+out: -+ free((void *)info->volume); -+ info->volume = NULL; -+ return rc; -+} -+ -+/** -+ * Locks the repository against other processes. -+ * -+ * @param[in] keystore the keystore -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+static int _keystore_lock_repository(struct keystore *keystore) -+{ -+ char *lock_file_name; -+ struct stat sb; -+ int rc; -+ -+ util_asprintf(&lock_file_name, "%s/%s", keystore->directory, -+ LOCK_FILE_NAME); -+ -+ if (stat(lock_file_name, &sb) == 0) { -+ keystore->lock_fd = open(lock_file_name, O_RDONLY); -+ if (keystore->lock_fd == -1) { -+ rc = -errno; -+ warnx("Failed to open lock file '%s': %s", -+ lock_file_name, -+ strerror(-rc)); -+ goto out; -+ } -+ } else { -+ keystore->lock_fd = open(lock_file_name, O_CREAT | O_RDONLY, -+ keystore->mode); -+ if (keystore->lock_fd == -1) { -+ rc = -errno; -+ warnx("Failed to create lock file '%s': %s", -+ lock_file_name, -+ strerror(-rc)); -+ goto out; -+ } -+ -+ if (fchown(keystore->lock_fd, geteuid(), -+ keystore->owner) != 0) { -+ rc = -errno; -+ warnx("chown faild on file '%s': %s", lock_file_name, -+ strerror(-rc)); -+ return rc; -+ } -+ } -+ -+ rc = flock(keystore->lock_fd, LOCK_EX); -+ if (rc == -1) { -+ rc = -errno; -+ warnx("Failed to obtain the file lock on '%s': %s", -+ lock_file_name, strerror((-rc))); -+ } -+ -+out: -+ free(lock_file_name); -+ return rc; -+} -+ -+/** -+ * Unlocks the repository -+ * -+ * @param[in] keystore the keystore -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+static int _keystore_unlock_repository(struct keystore *keystore) -+{ -+ int rc; -+ -+ if (keystore->lock_fd == -1) -+ return 0; -+ -+ rc = flock(keystore->lock_fd, LOCK_UN); -+ if (rc == -1) { -+ rc = -errno; -+ warnx("Failed to release the file lock: %s", strerror((-rc))); -+ } -+ -+ close(keystore->lock_fd); -+ keystore->lock_fd = -1; -+ -+ return rc; -+} -+ -+/** -+ * Allocates new keystore object -+ * -+ * @param[in] directory the directory where the keystore resides -+ * @param[in] verbose if true, verbose messages are printed -+ * -+ * @returns a new keystore object -+ */ -+struct keystore *keystore_new(const char *directory, bool verbose) -+{ -+ struct keystore *keystore; -+ struct stat sb; -+ int rc; -+ -+ util_assert(directory != NULL, "Internal error: directory is NULL"); -+ -+ if (stat(directory, &sb) != 0) { -+ warnx("'%s' does not exist", directory); -+ return NULL; -+ } -+ if (!(sb.st_mode & S_IFDIR)) { -+ warnx("'%s' is not a directory", directory); -+ return NULL; -+ } -+ if (!util_path_is_readable(directory) || -+ !util_path_is_writable(directory)) { -+ warnx("Permission denied for '%s'", directory); -+ return NULL; -+ } -+ if (sb.st_mode & S_IWOTH) { -+ warnx("Directory '%s' is writable for others, this is not " -+ "accepted", directory); -+ return NULL; -+ } -+ -+ keystore = util_zalloc(sizeof(struct keystore)); -+ -+ keystore->owner = sb.st_gid; -+ keystore->mode = sb.st_mode & (S_IRUSR | S_IWUSR | -+ S_IRGRP | S_IWGRP | -+ S_IROTH); -+ keystore->lock_fd = -1; -+ keystore->verbose = verbose; -+ keystore->directory = util_strdup(directory); -+ if (keystore->directory[strlen(keystore->directory)-1] == '/') -+ keystore->directory[strlen(keystore->directory)-1] = '\0'; -+ -+ rc = _keystore_lock_repository(keystore); -+ if (rc != 0) { -+ keystore_free(keystore); -+ return NULL; -+ } -+ -+ pr_verbose(keystore, "Keystore in directory '%s' opened successfully", -+ keystore->directory); -+ return keystore; -+} -+ -+/** -+ * Sets a timestamp to be used as creation/update/reencipher time into -+ * the specified property -+ * -+ * @param[in] properties the properties object -+ * @param[in] property the name of the property to set -+ * -+ * @returns 0 on success, or a negative errno value on error -+ */ -+static int _keystore_set_timestamp_property(struct properties *properties, -+ const char *property) -+{ -+ char *time_str; -+ struct tm *tm; -+ time_t t; -+ int rc; -+ -+ t = time(NULL); -+ tm = localtime(&t); -+ util_assert(tm != NULL, "Internal error: tm is NULL"); -+ -+ time_str = util_zalloc(200); -+ rc = strftime(time_str, 200, "%F %T", tm); -+ util_assert(rc > 0, "Internal error: strftime failed"); -+ -+ rc = properties_set(properties, property, time_str); -+ -+ free(time_str); -+ return rc; -+} -+ -+/** -+ * Sets the default properties of a key, such as key-type, cipher-name, and -+ * IV-mode -+ * -+ * @param[in] key_props the properties object -+ */ -+static int _keystore_set_default_properties(struct properties *key_props) -+{ -+ int rc; -+ -+ rc = properties_set(key_props, PROP_NAME_KEY_TYPE, "CCA-AESDATA"); -+ if (rc != 0) -+ return rc; -+ -+ rc = properties_set(key_props, PROP_NAME_CIPHER, "paes"); -+ if (rc != 0) -+ return rc; -+ -+ rc = properties_set(key_props, PROP_NAME_IV_MODE, "plain64"); -+ if (rc != 0) -+ return rc; -+ -+ rc = _keystore_set_timestamp_property(key_props, -+ PROP_NAME_CREATION_TIME); -+ if (rc != 0) -+ return rc; -+ -+ return 0; -+} -+ -+/** -+ * Creates an initial .info file for a key -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] info_filename the file name of the key info file -+ * @param[in] description textual description of the key (optional, can be NULL) -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * @param[in] apqns a comma separated list of APQNs associated with this -+ * key (optional, can be NULL) -+ * @param[in] sector_size the sector size to use with dm-crypt. It must be power -+ * of two and in range 512 - 4096 bytes. 0 means that -+ * the sector size is not specified and the system -+ * default is used. -+ */ -+static int _keystore_create_info_file(struct keystore *keystore, -+ const char *name, -+ const char *info_filename, -+ const char *description, -+ const char *volumes, const char *apqns, -+ size_t sector_size) -+{ -+ struct volume_check vol_check = { .keystore = keystore, .name = name }; -+ struct properties *key_props; -+ char temp[10]; -+ int rc; -+ -+ key_props = properties_new(); -+ rc = _keystore_set_default_properties(key_props); -+ if (rc != 0) -+ goto out; -+ -+ rc = properties_set(key_props, PROP_NAME_DESCRIPTION, -+ description != NULL ? description : ""); -+ if (rc != 0) { -+ warnx("Invalid characters in description"); -+ goto out; -+ } -+ -+ rc = _keystore_change_association(key_props, PROP_NAME_VOLUMES, -+ volumes != NULL ? volumes : "", -+ "volume", _keystore_volume_check, -+ &vol_check); -+ if (rc != 0) -+ goto out; -+ -+ rc = _keystore_change_association(key_props, PROP_NAME_APQNS, -+ apqns != NULL ? apqns : "", -+ "APQN", _keystore_apqn_check, NULL); -+ if (rc != 0) -+ goto out; -+ -+ if (!_keystore_valid_sector_size(sector_size)) { -+ warnx("Invalid sector-size specified"); -+ rc = -EINVAL; -+ goto out; -+ } -+ sprintf(temp, "%lu", sector_size); -+ rc = properties_set(key_props, PROP_NAME_SECTOR_SIZE, -+ temp); -+ if (rc != 0) { -+ warnx("Invalid characters in sector-size"); -+ goto out; -+ } -+ -+ rc = properties_save(key_props, info_filename, 1); -+ if (rc != 0) { -+ pr_verbose(keystore, -+ "Key info file '%s' could not be written: %s", -+ info_filename, strerror(-rc)); -+ goto out; -+ } -+ -+ rc = _keystore_set_file_permission(keystore, info_filename); -+ if (rc != 0) { -+ remove(info_filename); -+ goto out; -+ } -+ -+out: -+ properties_free(key_props); -+ return rc; -+} -+ -+/** -+ * Extracts a card/domain pair from the specified APQns, or uses AUTOSELECT -+ * if no APQNs are specified. -+ */ -+static int _keystore_get_card_domain(const char *apqns, unsigned int *card, -+ unsigned int *domain) -+{ -+ char **apqn_list; -+ char *normalized = NULL; -+ int rc = 0; -+ -+ *card = AUTOSELECT; -+ *domain = AUTOSELECT; -+ -+ if (apqns == NULL) -+ return 0; -+ -+ apqn_list = str_list_split(apqns); -+ if (apqn_list[0] == NULL) -+ goto out; -+ -+ rc = _keystore_apqn_check(apqn_list[0], 0, &normalized, NULL); -+ if (normalized != NULL) -+ free(normalized); -+ if (rc != 0) -+ goto out; -+ -+ if (sscanf(apqn_list[0], "%x.%x", card, domain) != 2) { -+ rc = -EINVAL; -+ goto out; -+ } -+ -+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 -+ * @param[in] name the name of the key -+ * @param[in] description textual description of the key (optional, can be NULL) -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * @param[in] apqns a comma separated list of APQNs associated with this -+ * key (optional, can be NULL) -+ * @param[in] sector_size the sector size to use with dm-crypt. It must be power -+ * of two and in range 512 - 4096 bytes. 0 means that -+ * the sector size is not specified and the system -+ * default is used. -+ * @param[in] keybits cryptographical size of the key in bits -+ * @param[in] xts if true, an XTS key is generated -+ * @param[in] clear_key_file if not NULL the secure key is generated from the -+ * clear key contained in the file denoted here. -+ * if NULL, the secure key is generated by random. -+ * @param[in] pkey_fd the file descriptor of /dev/pkey -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_generate_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, size_t sector_size, -+ size_t keybits, bool xts, const char *clear_key_file, -+ int pkey_fd) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ struct properties *key_props = NULL; -+ unsigned int card, domain; -+ int rc; -+ -+ 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_free_key_filenames; -+ -+ rc = _keystore_ensure_keyfiles_not_exist(&file_names, name); -+ if (rc != 0) -+ goto out_free_key_filenames; -+ -+ rc = _keystore_get_card_domain(apqns, &card, &domain); -+ if (rc != 0) -+ goto out_free_key_filenames; -+ -+ if (clear_key_file == NULL) -+ rc = generate_secure_key_random(pkey_fd, -+ file_names.skey_filename, -+ keybits, xts, card, domain, -+ keystore->verbose); -+ else -+ rc = generate_secure_key_clear(pkey_fd, -+ file_names.skey_filename, -+ keybits, xts, clear_key_file, -+ card, domain, -+ keystore->verbose); -+ if (rc != 0) -+ goto out_free_props; -+ -+ rc = _keystore_set_file_permission(keystore, file_names.skey_filename); -+ if (rc != 0) -+ goto out_free_props; -+ -+ rc = _keystore_create_info_file(keystore, name, -+ file_names.info_filename, -+ description, volumes, apqns, -+ sector_size); -+ if (rc != 0) -+ goto out_free_props; -+ -+ pr_verbose(keystore, -+ "Successfully generated a secure key in '%s' and key info " -+ "in '%s'", file_names.skey_filename, -+ file_names.info_filename); -+ -+out_free_props: -+ if (key_props != NULL) -+ properties_free(key_props); -+ if (rc != 0 && rc != -EEXIST) -+ remove(file_names.skey_filename); -+out_free_key_filenames: -+ _keystore_free_key_filenames(&file_names); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to generate key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Imports a secure key from a file and adds it to the key store -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] description textual description of the key (optional, can be NULL) -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * @param[in] apqns a comma separated list of APQNs associated with this -+ * key (optional, can be NULL) -+ * @param[in] sector_size the sector size to use with dm-crypt. It must be power -+ * of two and in range 512 - 4096 bytes. 0 means that -+ * the sector size is not specified and the system -+ * default is used. -+ * @param[in] import_file The name of a secure key containing the kley to import -+ * -+ * @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, size_t sector_size, -+ const char *import_file) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ struct properties *key_props = NULL; -+ size_t secure_key_size; -+ u8 *secure_key; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ util_assert(import_file != NULL, "Internal error: import_file is NULL"); -+ -+ rc = _keystore_get_key_filenames(keystore, name, &file_names); -+ if (rc != 0) -+ goto out_free_key_filenames; -+ -+ rc = _keystore_ensure_keyfiles_not_exist(&file_names, name); -+ if (rc != 0) -+ goto out_free_key_filenames; -+ -+ secure_key = read_secure_key(import_file, &secure_key_size, -+ keystore->verbose); -+ if (secure_key == NULL) { -+ rc = -ENOENT; -+ goto out_free_key_filenames; -+ } -+ -+ rc = write_secure_key(file_names.skey_filename, secure_key, -+ secure_key_size, keystore->verbose); -+ free(secure_key); -+ if (rc != 0) -+ goto out_free_props; -+ -+ rc = _keystore_set_file_permission(keystore, file_names.skey_filename); -+ if (rc != 0) -+ goto out_free_props; -+ -+ rc = _keystore_create_info_file(keystore, name, -+ file_names.info_filename, -+ description, volumes, apqns, -+ sector_size); -+ if (rc != 0) -+ goto out_free_props; -+ -+ pr_verbose(keystore, -+ "Successfully imported a secure key in '%s' and key info in '%s'", -+ file_names.skey_filename, file_names.info_filename); -+ -+out_free_props: -+ if (key_props != NULL) -+ properties_free(key_props); -+ if (rc != 0 && rc != -EEXIST) -+ remove(file_names.skey_filename); -+out_free_key_filenames: -+ _keystore_free_key_filenames(&file_names); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to import key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+ -+/** -+ * Changes properties of a key in the keystore. -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] description textual description of the key. If NULL then the -+ * description is not changed. -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key, or a volume prefixed with '+' or '-' to add or -+ * remove that volume respectively. If NULL then the -+ * volumes are not changed. -+ * @param[in] apqns a comma separated list of APQNs associated with this -+ * key, or an APQN prefixed with '+' or '-' to add or -+ * remove that APQN respectively. IfNULL then the APQNs -+ * are not changed. -+ * @param[in] sector_size the sector size to use with dm-crypt. It must be power -+ * of two and in range 512 - 4096 bytes. 0 means that -+ * the sector size is not specified and the system -+ * default is used. Specify -1 if this property should -+ * not be changed. -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ * -+ */ -+int keystore_change_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, long int sector_size) -+{ -+ struct volume_check vol_check = { .keystore = keystore, .name = name }; -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ struct properties *key_props = NULL; -+ char temp[10]; -+ int rc; -+ -+ 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; -+ -+ key_props = properties_new(); -+ rc = properties_load(key_props, file_names.info_filename, 1); -+ if (rc != 0) { -+ warnx("Key '%s' does not exist or is invalid", name); -+ goto out; -+ } -+ -+ if (description != NULL) { -+ rc = properties_set(key_props, PROP_NAME_DESCRIPTION, -+ description); -+ if (rc != 0) { -+ warnx("Invalid characters in description"); -+ goto out; -+ } -+ } -+ -+ if (volumes != NULL) { -+ rc = _keystore_change_association(key_props, PROP_NAME_VOLUMES, -+ volumes, "volume", -+ _keystore_volume_check, -+ &vol_check); -+ if (rc != 0) -+ goto out; -+ } -+ -+ if (apqns != NULL) { -+ rc = _keystore_change_association(key_props, PROP_NAME_APQNS, -+ apqns, "APQN", -+ _keystore_apqn_check, NULL); -+ if (rc != 0) -+ goto out; -+ } -+ -+ if (sector_size >= 0) { -+ if (!_keystore_valid_sector_size(sector_size)) { -+ warnx("Invalid sector-size specified"); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ sprintf(temp, "%lu", sector_size); -+ rc = properties_set(key_props, PROP_NAME_SECTOR_SIZE, -+ temp); -+ if (rc != 0) { -+ warnx("Invalid characters in sector-size"); -+ goto out; -+ } -+ } -+ -+ rc = _keystore_set_timestamp_property(key_props, PROP_NAME_CHANGE_TIME); -+ if (rc != 0) -+ goto out; -+ -+ rc = properties_save(key_props, file_names.info_filename, 1); -+ if (rc != 0) { -+ pr_verbose(keystore, -+ "Key info file '%s' could not be written: %s", -+ file_names.info_filename, strerror(-rc)); -+ goto out; -+ } -+ -+ rc = _keystore_set_file_permission(keystore, file_names.info_filename); -+ if (rc != 0) -+ goto out; -+ -+ pr_verbose(keystore, "Successfully changed key '%s'", name); -+ -+out: -+ _keystore_free_key_filenames(&file_names); -+ if (key_props != NULL) -+ properties_free(key_props); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to change key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Renames a key in the keystore -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] newname the new name of the key -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_rename_key(struct keystore *keystore, const char *name, -+ const char *newname) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ struct key_filenames new_names = { NULL, NULL, NULL }; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ util_assert(newname != NULL, "Internal error: newname 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; -+ -+ rc = _keystore_get_key_filenames(keystore, newname, &new_names); -+ if (rc != 0) -+ goto out; -+ -+ rc = _keystore_ensure_keyfiles_not_exist(&new_names, newname); -+ if (rc != 0) -+ goto out; -+ -+ if (rename(file_names.skey_filename, new_names.skey_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to rename '%s': %s", -+ file_names.skey_filename, strerror(-rc)); -+ goto out; -+ } -+ if (rename(file_names.info_filename, new_names.info_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to rename '%s': %s", -+ file_names.info_filename, strerror(-rc)); -+ rename(new_names.skey_filename, file_names.skey_filename); -+ } -+ if (_keystore_reencipher_key_exists(&file_names)) { -+ if (rename(file_names.renc_filename, -+ new_names.renc_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to rename '%s': %s", -+ file_names.renc_filename, strerror(-rc)); -+ rename(new_names.skey_filename, -+ file_names.skey_filename); -+ rename(new_names.info_filename, -+ file_names.info_filename); -+ } -+ } -+ -+ pr_verbose(keystore, "Successfully renamed key '%s' to '%s'", name, -+ newname); -+ -+out: -+ _keystore_free_key_filenames(&file_names); -+ _keystore_free_key_filenames(&new_names); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to rename key '%s'to '%s': %s", -+ name, newname, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Sets up a util_rec used for displaying key information -+ * -+ * @param[in] validation if true the record is used for validate, else it is -+ * used for display -+ * -+ * @returns a pointer to a set up struct util_rec. -+ */ -+static struct util_rec *_keystore_setup_record(bool validation) -+{ -+ struct util_rec *rec; -+ -+ rec = util_rec_new_long("-", ":", REC_KEY, 23, 54); -+ util_rec_def(rec, REC_KEY, UTIL_REC_ALIGN_LEFT, 54, REC_KEY); -+ if (validation) -+ util_rec_def(rec, REC_STATUS, UTIL_REC_ALIGN_LEFT, 54, -+ REC_STATUS); -+ util_rec_def(rec, REC_DESCRIPTION, UTIL_REC_ALIGN_LEFT, 54, -+ REC_DESCRIPTION); -+ util_rec_def(rec, REC_SEC_KEY_SIZE, UTIL_REC_ALIGN_LEFT, 20, -+ REC_SEC_KEY_SIZE); -+ 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); -+ if (validation) -+ util_rec_def(rec, REC_MASTERKEY, UTIL_REC_ALIGN_LEFT, 54, -+ REC_MASTERKEY); -+ util_rec_def(rec, REC_VOLUMES, UTIL_REC_ALIGN_LEFT, 54, REC_VOLUMES); -+ util_rec_def(rec, REC_APQNS, UTIL_REC_ALIGN_LEFT, 54, REC_APQNS); -+ util_rec_def(rec, REC_KEY_FILE, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_FILE); -+ util_rec_def(rec, REC_SECTOR_SIZE, UTIL_REC_ALIGN_LEFT, 54, -+ REC_SECTOR_SIZE); -+ util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54, -+ REC_CREATION_TIME); -+ util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54, -+ REC_CHANGE_TIME); -+ util_rec_def(rec, REC_REENC_TIME, UTIL_REC_ALIGN_LEFT, 54, -+ REC_REENC_TIME); -+ -+ return rec; -+} -+ -+static void _keystore_print_record(struct util_rec *rec, -+ const char *name, -+ struct properties *properties, -+ 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) -+{ -+ char *volumes_argz = NULL; -+ size_t volumes_argz_len; -+ char *apqns_argz = NULL; -+ size_t sector_size = 0; -+ size_t apqns_argz_len; -+ char *description; -+ char *reencipher; -+ char *creation; -+ char *volumes; -+ char *change; -+ char *apqns; -+ char *temp; -+ -+ description = properties_get(properties, PROP_NAME_DESCRIPTION); -+ volumes = properties_get(properties, PROP_NAME_VOLUMES); -+ if (volumes != NULL) -+ util_assert(argz_create_sep(volumes, ',', -+ &volumes_argz, -+ &volumes_argz_len) == 0, -+ "Internal error: argz_create_sep failed"); -+ apqns = properties_get(properties, PROP_NAME_APQNS); -+ if (apqns != NULL) -+ util_assert(argz_create_sep(apqns, ',', -+ &apqns_argz, -+ &apqns_argz_len) == 0, -+ "Internal error: argz_create_sep failed"); -+ -+ temp = properties_get(properties, PROP_NAME_SECTOR_SIZE); -+ if (temp != NULL) { -+ util_assert(sscanf(temp, "%lu", §or_size) == 1, -+ "Internal error: sscanf failed"); -+ free(temp); -+ } -+ -+ creation = properties_get(properties, PROP_NAME_CREATION_TIME); -+ change = properties_get(properties, PROP_NAME_CHANGE_TIME); -+ reencipher = properties_get(properties, PROP_NAME_REENC_TIME); -+ -+ util_rec_set(rec, REC_KEY, name); -+ if (validation) -+ util_rec_set(rec, REC_STATUS, valid ? "Valid" : "Invalid"); -+ 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) -+ 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"); -+ if (validation) { -+ if (valid) -+ util_rec_set(rec, REC_MASTERKEY, -+ is_old_mk ? "OLD CCA master key" : -+ "CURRENT CCA master key"); -+ else -+ util_rec_set(rec, REC_MASTERKEY, "(unknown)"); -+ } -+ if (volumes_argz != NULL) -+ util_rec_set_argz(rec, REC_VOLUMES, volumes_argz, -+ volumes_argz_len); -+ else -+ util_rec_set(rec, REC_VOLUMES, "(none)"); -+ if (apqns_argz != NULL) -+ util_rec_set_argz(rec, REC_APQNS, -+ apqns_argz, apqns_argz_len); -+ else -+ util_rec_set(rec, REC_APQNS, "(none)"); -+ util_rec_set(rec, REC_KEY_FILE, skey_filename); -+ if (sector_size == 0) -+ util_rec_set(rec, REC_SECTOR_SIZE, "(system default)"); -+ else -+ util_rec_set(rec, REC_SECTOR_SIZE, "%lu bytes", -+ sector_size); -+ util_rec_set(rec, REC_CREATION_TIME, creation); -+ util_rec_set(rec, REC_CHANGE_TIME, -+ change != NULL ? change : "(never)"); -+ util_rec_set(rec, REC_REENC_TIME, "%s %s", -+ reencipher != NULL ? reencipher : "(never)", -+ reenc_pending ? "(re-enciphering pending)" : ""); -+ -+ util_rec_print(rec); -+ -+ if (description != NULL) -+ free(description); -+ if (volumes != NULL) -+ free(volumes); -+ if (volumes_argz != NULL) -+ free(volumes_argz); -+ if (apqns != NULL) -+ free(apqns); -+ if (apqns_argz != NULL) -+ free(apqns_argz); -+ if (creation != NULL) -+ free(creation); -+ if (change != NULL) -+ free(change); -+ if (reencipher != NULL) -+ free(reencipher); -+} -+ -+struct validate_info { -+ struct util_rec *rec; -+ int pkey_fd; -+ unsigned long int num_valid; -+ unsigned long int num_invalid; -+ unsigned long int num_warnings; -+}; -+ -+/** -+ * Displays the status of the associated APQNs. -+ * -+ * @param[in] properties the properties of the key -+ * @param[in] name the name of the key -+ * -+ * @returns 0 in case of success, 1 if at least one of the APQNs is not -+ * available -+ */ -+static int _keystore_display_apqn_status(struct properties *properties, -+ const char *name) -+{ -+ int i, rc, card, domain, warning = 0; -+ char **apqn_list; -+ 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 = _keystore_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; -+ } -+ } -+ -+ if (warning) -+ printf("\n"); -+ -+ free(apqns); -+ str_list_free_string_array(apqn_list); -+ return warning; -+} -+/** -+ * Displays the status of the associated volumes. -+ * -+ * @param[in] properties the properties of the key -+ * @param[in] name the name of the key -+ * -+ * @returns 0 in case of success, 1 if at least one of the volumes is not -+ * available -+ */ -+static int _keystore_display_volume_status(struct properties *properties, -+ const char *name) -+{ -+ int i, warning = 0; -+ char **volume_list; -+ char *volumes; -+ char *ch; -+ -+ volumes = properties_get(properties, PROP_NAME_VOLUMES); -+ if (volumes == NULL) -+ return 0; -+ volume_list = str_list_split(volumes); -+ -+ for (i = 0; volume_list[i] != NULL; i++) { -+ -+ ch = strchr(volume_list[i], ':'); -+ if (ch != NULL) -+ *ch = '\0'; -+ -+ if (!_keystore_is_block_device(volume_list[i])) { -+ printf("WARNING: The volume '%s' associated with " -+ "key '%s' is not available\n", volume_list[i], -+ name); -+ warning = 1; -+ } -+ } -+ -+ if (warning) -+ printf("\n"); -+ -+ free(volumes); -+ str_list_free_string_array(volume_list); -+ return warning; -+} -+ -+/** -+ * Processing function for the key validate function. Prints validation -+ * information for the key to be validated. -+ * -+ * @param[in] keystore the keystore -+ * @param[in] name the name of the key -+ * @param[in] properties the properties object of the key -+ * @param[in] file_names the file names used by this key -+ * @param[in] private private data: struct validate_info -+ * -+ * @returns 0 if the validation is successful, a negative errno value otherwise -+ */ -+static int _keystore_process_validate(struct keystore *keystore, -+ const char *name, -+ struct properties *properties, -+ struct key_filenames *file_names, -+ void *private) -+{ -+ struct validate_info *info = (struct validate_info *)private; -+ size_t clear_key_bitsize; -+ size_t secure_key_size; -+ u8 *secure_key; -+ int is_old_mk; -+ int rc, valid; -+ -+ rc = _keystore_ensure_keyfiles_exist(file_names, name); -+ 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 = validate_secure_key(info->pkey_fd, secure_key, secure_key_size, -+ &clear_key_bitsize, &is_old_mk, -+ keystore->verbose); -+ if (rc != 0) { -+ valid = 0; -+ info->num_invalid++; -+ rc = 0; -+ } else { -+ info->num_valid++; -+ valid = 1; -+ } -+ free(secure_key); -+ -+ _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)); -+ -+ if (valid && is_old_mk) { -+ util_print_indented("WARNING: The secure key is currently " -+ "enciphered with the OLD CCA master key " -+ "and should be re-enciphered with the " -+ "CURRENT CCA master key as soon as " -+ "possible to avoid data loss\n", 0); -+ info->num_warnings++; -+ } -+ if (_keystore_display_apqn_status(properties, name) != 0) -+ info->num_warnings++; -+ if (_keystore_display_volume_status(properties, name) != 0) -+ info->num_warnings++; -+ -+out: -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to validate key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Validates one or multiple keys in the keystore -+ * -+ * @param[in] keystore the key store -+ * @param[in] name_filter the name filter to select the key (can be NULL) -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_validate_key(struct keystore *keystore, const char *name_filter, -+ const char *apqn_filter, int pkey_fd) -+{ -+ struct validate_info info; -+ struct util_rec *rec; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ rec = _keystore_setup_record(1); -+ -+ info.pkey_fd = pkey_fd; -+ info.rec = rec; -+ info.num_valid = 0; -+ info.num_invalid = 0; -+ info.num_warnings = 0; -+ -+ rc = _keystore_process_filtered(keystore, name_filter, NULL, -+ apqn_filter, -+ _keystore_process_validate, &info); -+ -+ util_rec_free(rec); -+ -+ if (rc != 0) { -+ pr_verbose(keystore, "Failed to validate keys: %s", -+ strerror(-rc)); -+ } else { -+ pr_verbose(keystore, "Successfully validated keys"); -+ printf("%lu keys are valid, %lu keys are invalid, %lu " -+ "warnings\n", info.num_valid, info.num_invalid, -+ info.num_warnings); -+ } -+ return rc; -+} -+ -+struct reencipher_params { -+ bool from_old; -+ bool to_new; -+ bool complete; -+ int inplace; /* -1 = autodetect, 0 = not in-place, 1 = in-place */ -+}; -+ -+struct reencipher_info { -+ struct reencipher_params params; -+ int pkey_fd; -+ t_CSNBKTC dll_CSNBKTC; -+ unsigned long num_reenciphered; -+ unsigned long num_failed; -+ unsigned long num_skipped; -+}; -+ -+/** -+ * Perform the reencipherment of a key -+ * -+ * @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] params reenciphering parameters -+ * @param[in] secure_key a buffer containing the secure key -+ * @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 -+ * @returns 0 if the re-enciphering is successful, a negative errno value -+ * otherwise, 1 if it was skipped -+ */ -+static int _keystore_perform_reencipher(struct keystore *keystore, -+ const char *name, -+ t_CSNBKTC dll_CSNBKTC, -+ struct reencipher_params *params, -+ u8 *secure_key, size_t secure_key_size, -+ bool is_old_mk) -+{ -+ int rc; -+ -+ if (!params->from_old && !params->to_new) { -+ /* Autodetect reencipher mode */ -+ if (is_old_mk) { -+ params->from_old = 1; -+ util_print_indented("The secure key is currently " -+ "enciphered with the OLD CCA " -+ "master key and is being " -+ "re-enciphered with the CURRENT " -+ "CCA master key\n", 0); -+ } else { -+ params->to_new = 1; -+ util_print_indented("The secure key is currently " -+ "enciphered with the CURRENT CCA " -+ "master key and is being " -+ "re-enciphered with the NEW CCA " -+ "master key\n", 0); -+ } -+ } -+ -+ 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; -+ -+ pr_verbose(keystore, -+ "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, -+ METHOD_OLD_TO_CURRENT, -+ keystore->verbose); -+ if (rc != 0) { -+ warnx("Failed to re-encipher '%s' from OLD to " -+ "CURRENT CCA master key", name); -+ return rc; -+ } -+ } -+ if (params->to_new) { -+ pr_verbose(keystore, -+ "Secure key '%s' will be re-enciphered from " -+ "CURRENT to the NEW CCA master key", name); -+ -+ if (params->inplace == -1) -+ params->inplace = 0; -+ -+ rc = key_token_change(dll_CSNBKTC, -+ 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); -+ return rc; -+ } -+ } -+ -+ return 0; -+} -+ -+/** -+ * Processing function for the key re-enciphering function. -+ * -+ * @param[in] keystore the keystore -+ * @param[in] name the name of the key -+ * @param[in] properties the properties object of the key (not used here) -+ * @param[in] file_names the file names used by this key -+ * @param[in] private private data: struct reencipher_info -+ * -+ * @returns 0 if the re-enciphering is successful, a negative errno value -+ * otherwise -+ */ -+static int _keystore_process_reencipher(struct keystore *keystore, -+ const char *name, -+ struct properties *properties, -+ struct key_filenames *file_names, -+ void *private) -+{ -+ struct reencipher_info *info = (struct reencipher_info *)private; -+ struct reencipher_params params = info->params; -+ size_t clear_key_bitsize; -+ size_t secure_key_size; -+ u8 *secure_key = NULL; -+ char *out_file; -+ int is_old_mk; -+ char *temp; -+ int rc; -+ -+ rc = _keystore_ensure_keyfiles_exist(file_names, name); -+ if (rc != 0) -+ goto out; -+ -+ pr_verbose(keystore, "Complete reencipher: %d", params.complete); -+ pr_verbose(keystore, "In-place reencipher: %d", params.inplace); -+ -+ if (params.complete) { -+ if (!_keystore_reencipher_key_exists(file_names)) { -+ warnx("Staged re-enciphering in not pending for key " -+ "'%s', skipping", -+ name); -+ info->num_skipped++; -+ rc = 0; -+ goto out; -+ } -+ -+ printf("Completing re-enciphering for key '%s'\n", name); -+ -+ params.inplace = 1; -+ } -+ -+ secure_key = read_secure_key(params.complete ? -+ file_names->renc_filename : -+ file_names->skey_filename, -+ &secure_key_size, keystore->verbose); -+ if (secure_key == NULL) { -+ rc = -ENOENT; -+ goto out; -+ } -+ -+ rc = validate_secure_key(info->pkey_fd, secure_key, secure_key_size, -+ &clear_key_bitsize, &is_old_mk, -+ keystore->verbose); -+ if (rc != 0) { -+ if (params.complete) { -+ warnx("Key '%s' is not valid, re-enciphering is not " -+ "completed", name); -+ warnx("Possibly the CCA master key not yet been set?"); -+ } else { -+ warnx("Key '%s' is not valid, it is not re-enciphered", -+ name); -+ info->num_skipped++; -+ rc = 0; -+ } -+ goto out; -+ } -+ -+ 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); -+ if (rc < 0) -+ goto out; -+ if (rc > 0) { -+ info->num_skipped++; -+ rc = 0; -+ goto out; -+ } -+ } -+ -+ pr_verbose(keystore, "In-place reencipher: %d", params.inplace); -+ -+ out_file = params.inplace == 1 ? file_names->skey_filename : -+ file_names->renc_filename; -+ rc = write_secure_key(out_file, secure_key, -+ secure_key_size, keystore->verbose); -+ if (rc != 0) -+ goto out; -+ -+ rc = _keystore_set_file_permission(keystore, out_file); -+ if (rc != 0) -+ goto out; -+ -+ if (params.complete || params.inplace == 1) { -+ rc = _keystore_set_timestamp_property(properties, -+ PROP_NAME_REENC_TIME); -+ if (rc != 0) -+ 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 = _keystore_set_file_permission(keystore, -+ file_names->info_filename); -+ if (rc != 0) -+ goto out; -+ } -+ -+ if (params.complete || -+ (params.inplace && _keystore_reencipher_key_exists(file_names))) { -+ if (remove(file_names->renc_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to remove '%s': %s", -+ file_names->renc_filename, strerror(-rc)); -+ goto out; -+ } -+ } -+ -+ if (params.inplace != 1) { -+ util_asprintf(&temp, "Staged re-enciphering has completed for " -+ "key '%s'. Run 'zkey reencipher' with option " -+ "'--complete' when the NEW CCA master key has " -+ "been set (moved to the CURRENT master key " -+ "register) to complete the re-enciphering " -+ "process", name); -+ util_print_indented(temp, 0); -+ free(temp); -+ } -+ -+ info->num_reenciphered++; -+ -+out: -+ if (secure_key != NULL) -+ free(secure_key); -+ -+ printf("\n"); -+ -+ if (rc != 0) { -+ info->num_failed++; -+ pr_verbose(keystore, "Failed to re-encipher key '%s': %s", -+ name, strerror(-rc)); -+ rc = 0; -+ } -+ return rc; -+} -+ -+/** -+ * Reenciphers a key in the keystore -+ * -+ * @param[in] keystore the key store -+ * @param[in] name_filter the name filter to select the key (can be NULL) -+ * @param[in] apqn_filter the APQN filter to seletc the key (can be NULL) -+ * @param[in] from_old If true the key is reenciphered from the OLD to the -+ * CURRENT CCA master key. -+ * @param[in] to_new If true the key is reenciphered from the CURRENT to -+ * the OLD CCA master key. -+ * @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 -+ * 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. -+ * Note: if both inplace and staged are FLASE, then the key is re-enciphered -+ * inplace when for OLD-to-CURRENT, and is reenciphered staged for -+ * CURRENT-to-NEW. -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_reencipher_key(struct keystore *keystore, const char *name_filter, -+ const char *apqn_filter, -+ bool from_old, bool to_new, bool inplace, -+ bool staged, bool complete, int pkey_fd, -+ t_CSNBKTC dll_CSNBKTC) -+{ -+ struct reencipher_info info; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ info.params.from_old = from_old; -+ info.params.to_new = to_new; -+ info.params.inplace = -1; -+ if (inplace) -+ info.params.inplace = 1; -+ if (staged) -+ info.params.inplace = 0; -+ info.params.complete = complete; -+ info.pkey_fd = pkey_fd; -+ info.dll_CSNBKTC = dll_CSNBKTC; -+ info.num_failed = 0; -+ info.num_reenciphered = 0; -+ info.num_skipped = 0; -+ -+ rc = _keystore_process_filtered(keystore, name_filter, NULL, -+ apqn_filter, -+ _keystore_process_reencipher, &info); -+ -+ if (rc != 0) { -+ pr_verbose(keystore, "Failed to re-encipher keys: %s", -+ strerror(-rc)); -+ } else { -+ pr_verbose(keystore, "Successfully re-enciphered keys"); -+ printf("%lu keys re-enciphered, %lu keys skipped, %lu keys " -+ "failed to re-encipher\n", -+ info.num_reenciphered, info.num_skipped, -+ info.num_failed); -+ if (info.num_failed > 0) -+ rc = -EIO; -+ } -+ return rc; -+} -+ -+/** -+ * Copies (duplicates) a key in the keystore. Any existing volume associations -+ * are removed from the copy, because a volume can only be associated to one -+ * key. However, you can set new volume associations using the volumes -+ * parameter. -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] newname the new name of the key -+ * @param[in] volumes a comma separated list of volumes associated with this -+ * key (optional, can be NULL) -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_copy_key(struct keystore *keystore, const char *name, -+ const char *newname, const char *volumes) -+{ -+ struct volume_check vol_check = { .keystore = keystore, -+ .name = newname }; -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ struct key_filenames new_names = { NULL, NULL, NULL }; -+ struct properties *key_prop = NULL; -+ size_t secure_key_size; -+ u8 *secure_key; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ util_assert(newname != NULL, "Internal error: newname 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; -+ -+ rc = _keystore_get_key_filenames(keystore, newname, &new_names); -+ if (rc != 0) -+ goto out; -+ -+ rc = _keystore_ensure_keyfiles_not_exist(&new_names, newname); -+ 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 = write_secure_key(new_names.skey_filename, secure_key, -+ secure_key_size, keystore->verbose); -+ free(secure_key); -+ if (rc != 0) -+ goto out; -+ -+ rc = _keystore_set_file_permission(keystore, new_names.skey_filename); -+ if (rc != 0) -+ goto out; -+ -+ key_prop = properties_new(); -+ rc = properties_load(key_prop, file_names.info_filename, 1); -+ if (rc != 0) { -+ warnx("Key '%s' does not exist or is invalid", name); -+ remove(file_names.skey_filename); -+ goto out; -+ } -+ -+ /* -+ * Remove any volume association, since a volume can only be associated -+ * with one key -+ */ -+ rc = properties_set(key_prop, PROP_NAME_VOLUMES, ""); -+ if (rc != 0) -+ goto out; -+ -+ if (volumes != NULL) { -+ rc = _keystore_change_association(key_prop, PROP_NAME_VOLUMES, -+ volumes, -+ "volume", -+ _keystore_volume_check, -+ &vol_check); -+ if (rc != 0) -+ goto out; -+ } -+ -+ rc = properties_remove(key_prop, PROP_NAME_CHANGE_TIME); -+ if (rc != 0 && rc != -ENOENT) -+ goto out; -+ -+ rc = properties_remove(key_prop, PROP_NAME_REENC_TIME); -+ if (rc != 0 && rc != -ENOENT) -+ goto out; -+ -+ rc = _keystore_set_timestamp_property(key_prop, -+ PROP_NAME_CREATION_TIME); -+ if (rc != 0) -+ goto out; -+ -+ rc = properties_save(key_prop, new_names.info_filename, 1); -+ if (rc != 0) { -+ pr_verbose(keystore, -+ "Key info file '%s' could not be written: %s", -+ new_names.info_filename, strerror(-rc)); -+ remove(new_names.skey_filename); -+ goto out; -+ } -+ -+ rc = _keystore_set_file_permission(keystore, new_names.info_filename); -+ if (rc != 0) -+ goto out; -+ -+ pr_verbose(keystore, "Successfully copied key '%s' to '%s'", name, -+ newname); -+ -+out: -+ if (rc != 0) { -+ remove(new_names.skey_filename); -+ remove(new_names.info_filename); -+ } -+ -+ _keystore_free_key_filenames(&file_names); -+ _keystore_free_key_filenames(&new_names); -+ if (key_prop != NULL) -+ properties_free(key_prop); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to copy key '%s'to '%s': %s", -+ name, newname, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Exports a key from the keystore to a file -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] export_file the name of the file to export the key to -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_export_key(struct keystore *keystore, const char *name, -+ const char *export_file) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ size_t secure_key_size; -+ u8 *secure_key; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(name != NULL, "Internal error: name is NULL"); -+ util_assert(export_file != NULL, "Internal error: export_file 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; -+ -+ secure_key = read_secure_key(file_names.skey_filename, -+ &secure_key_size, keystore->verbose); -+ if (secure_key == NULL) { -+ rc = -ENOENT; -+ goto out; -+ } -+ -+ rc = write_secure_key(export_file, secure_key, -+ secure_key_size, keystore->verbose); -+ free(secure_key); -+ -+ pr_verbose(keystore, "Successfully exported key '%s' to '%s'", name, -+ export_file); -+ -+out: -+ _keystore_free_key_filenames(&file_names); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to export key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Prompts the user to confirm deletion of a key -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] file_names the file names of the key -+ * -+ * @returnd 0 if the user confirmed the deletion, a negative errno value -+ * otherwise -+ */ -+static int _keystore_propmp_for_remove(struct keystore *keystore, -+ const char *name, -+ struct key_filenames *file_names) -+{ -+ struct properties *key_prop; -+ char *volumes = NULL; -+ char **volume_list = NULL; -+ char str[20]; -+ int rc, i; -+ -+ key_prop = properties_new(); -+ rc = properties_load(key_prop, file_names->info_filename, 1); -+ if (rc != 0) { -+ warnx("Key '%s' does not exist or is invalid", name); -+ goto out; -+ } -+ -+ volumes = properties_get(key_prop, PROP_NAME_VOLUMES); -+ if (volumes != NULL && strlen(volumes) > 0) { -+ volume_list = str_list_split(volumes); -+ -+ warnx("When you remove key '%s' the following volumes will " -+ "no longer be usable:", name); -+ for (i = 0; volume_list[i] != NULL; i++) -+ fprintf(stderr, "%s\n", volume_list[i]); -+ } -+ -+ printf("%s: Remove key '%s'? ", 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) { -+ rc = -ECANCELED; -+ goto out; -+ } -+ -+out: -+ properties_free(key_prop); -+ if (volume_list != NULL) -+ str_list_free_string_array(volume_list); -+ -+ return rc; -+} -+ -+/** -+ * Removes a key from the keystore -+ * -+ * @param[in] keystore the key store -+ * @param[in] name the name of the key -+ * @param[in] quiet if true no confirmation prompt is shown -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_remove_key(struct keystore *keystore, const char *name, -+ bool quiet) -+{ -+ struct key_filenames file_names = { NULL, NULL, NULL }; -+ int rc; -+ -+ 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; -+ -+ if (!quiet) { -+ if (_keystore_propmp_for_remove(keystore, name, -+ &file_names) != 0) -+ goto out; -+ } -+ -+ if (remove(file_names.skey_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to remove '%s': %s", -+ file_names.skey_filename, strerror(-rc)); -+ goto out; -+ } -+ if (remove(file_names.info_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to remove '%s': %s", -+ file_names.info_filename, strerror(-rc)); -+ } -+ if (_keystore_reencipher_key_exists(&file_names)) { -+ if (remove(file_names.renc_filename) != 0) { -+ rc = -errno; -+ pr_verbose(keystore, "Failed to remove '%s': %s", -+ file_names.renc_filename, strerror(-rc)); -+ } -+ } -+ pr_verbose(keystore, "Successfully removed key '%s'", name); -+ -+out: -+ _keystore_free_key_filenames(&file_names); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to remove key '%s': %s", -+ name, strerror(-rc)); -+ return rc; -+} -+ -+/** -+ * Processing function for the key display function. -+ * -+ * @param[in] keystore the keystore -+ * @param[in] name the name of the key -+ * @param[in] properties the properties object of the key -+ * @param[in] file_names the file names used by this key -+ * @param[in] private private data: struct reencipher_info -+ * -+ * @returns 0 if the display is successful, a negative errno value otherwise -+ */ -+static int _keystore_display_key(struct keystore *keystore, -+ const char *name, -+ struct properties *properties, -+ struct key_filenames *file_names, -+ void *private) -+{ -+ struct util_rec *rec = (struct util_rec *)private; -+ struct secaeskeytoken *secure_key; -+ size_t secure_key_size; -+ int rc = 0; -+ -+ secure_key = (struct secaeskeytoken *) -+ 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) { -+ pr_verbose(keystore, -+ "Size of secure key is too small: %lu expected %lu", -+ secure_key_size, SECURE_KEY_SIZE); -+ rc = -EIO; -+ goto out; -+ } -+ -+ _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, -+ _keystore_reencipher_key_exists(file_names)); -+ -+out: -+ free(secure_key); -+ return rc; -+} -+ -+/** -+ * Lists keys in the keystore that matches the filters -+ * -+ * @param[in] keystore the key store -+ * @param[in] name_filter the name filter. Can contain wild cards. -+ * NULL means no name filter. -+ * @param[in] volume_filter the volume filter. Can contain wild cards, and -+ * mutliple volume filters separated by commas. -+ * The ':dm-name' part of the volume is optional -+ * for the volume filter. If not specified, the filter -+ * checks the volume part only. -+ * NULL means no volume filter. -+ * @param[in] apqn_filter the APQN filter. Can contain wild cards, and -+ * mutliple APQN filters separated by commas. -+ * NULL means no APQN 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) -+{ -+ struct util_rec *rec; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ rec = _keystore_setup_record(0); -+ -+ rc = _keystore_process_filtered(keystore, name_filter, volume_filter, -+ apqn_filter, _keystore_display_key, -+ rec); -+ util_rec_free(rec); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Failed to list keys: %s", -+ strerror(-rc)); -+ else -+ pr_verbose(keystore, "Successfully listed keys"); -+ return rc; -+} -+ -+/** -+ * Executes a command via system(). -+ * -+ * @param[in] cmd the command to execute -+ * @param[in] msg_cmd the short command name (for messages) -+ * -+ * @returns the exit code of the command execution, or -1 in case of an error -+ */ -+static int _keystore_execute_cmd(const char *cmd, -+ const char *msg_cmd) -+{ -+ int rc; -+ -+ rc = setenv("PATH", "/bin:/usr/bin:/usr/sbin", 1); -+ if (rc < 0) -+ return rc; -+ -+ rc = system(cmd); -+ if (WIFEXITED(rc)) { -+ rc = WEXITSTATUS(rc); -+ if (rc != 0) -+ printf("%s exit code: %d\n", msg_cmd, rc); -+ } else { -+ rc = -EIO; -+ warnx("%s terminated abnormally", msg_cmd); -+ } -+ -+ return rc; -+} -+ -+ -+struct crypt_info { -+ bool execute; -+ char **volume_filter; -+ int (*process_func)(struct keystore *keystore, -+ const char *volume, -+ const char *dmname, -+ const char *cipher_spec, -+ const char *key_file_name, -+ size_t key_file_size, -+ size_t sector_size, -+ struct crypt_info *info); -+}; -+ -+/** -+ * Processing function for the cryptsetup function. Builds a cryptsetup command -+ * line and optionally executes it. -+ * -+ * @param[in] keystore the keystore (not used here) -+ * @param[in] volume the volume to mount -+ * @param[in] dmname the debice mapper name -+ * @param[in] cipher_spec the cipher specification -+ * @param[in] key_file_name the key file name -+ * @param[in] key_file_size the size of the key file in bytes -+ * @param sector_size the sector size in bytes or 0 if not specified -+ * @param[in] info processing info -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+static int _keystore_process_cryptsetup(struct keystore *keystore, -+ const char *volume, -+ const char *dmname, -+ const char *cipher_spec, -+ const char *key_file_name, -+ size_t key_file_size, -+ size_t sector_size, -+ struct crypt_info *info) -+{ -+ char temp[100]; -+ int rc = 0; -+ char *cmd; -+ -+ sprintf(temp, "--sector-size %lu ", sector_size); -+ util_asprintf(&cmd, -+ "cryptsetup plainOpen %s--key-file '%s' --key-size %lu " -+ "--cipher %s %s%s %s", -+ keystore->verbose ? "-v " : "", key_file_name, -+ key_file_size * 8, cipher_spec, -+ sector_size > 0 ? temp : "", volume, dmname); -+ -+ if (info->execute) { -+ printf("Executing: %s\n", cmd); -+ rc = _keystore_execute_cmd(cmd, "cryptsetup"); -+ } else { -+ printf("%s\n", cmd); -+ } -+ -+ free(cmd); -+ return rc; -+} -+ -+/** -+ * Processing function for the crypttab function. Builds a crypttab entry -+ * and prints it. -+ * -+ * @param[in] keystore the keystore (not used here) -+ * @param[in] volume the volume to mount -+ * @param[in] dmname the debice mapper name -+ * @param[in] cipher_spec the cipher specification -+ * @param[in] key_file_name the key file name -+ * @param[in] key_file_size the size of the key file in bytes -+ * @param sector_size the sector size in bytes or 0 if not specified -+ * @param[in] info processing info (not used here) -+ * -+ * @returns 0 if successful, a negative errno value otherwise -+ */ -+ -+static int _keystore_process_crypttab(struct keystore *UNUSED(keystore), -+ const char *volume, -+ const char *dmname, -+ const char *cipher_spec, -+ const char *key_file_name, -+ size_t key_file_size, -+ size_t sector_size, -+ struct crypt_info *UNUSED(info)) -+{ -+ char temp[1000]; -+ -+ if (sector_size > 0) { -+ sprintf(temp, -+ "WARNING: volume '%s' is using a sector size of %lu. " -+ "At the time this utility was developed, systemd's " -+ "support of crypttab did not support to specify a " -+ "sector size with plain dm-crypt devices. The generated " -+ "crypttab entry may or may not work, and may need " -+ "manual adoptions.", volume, sector_size); -+ util_print_indented(temp, 0); -+ } -+ -+ sprintf(temp, ",sector-size=%lu", sector_size); -+ printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu,hash=plain%s\n", -+ dmname, volume, key_file_name, cipher_spec, key_file_size * 8, -+ sector_size > 0 ? temp : ""); -+ -+ return 0; -+} -+ -+/** -+ * Builds a cipher specification for cryptsetup/crypttab -+ * -+ * @param properties the key properties -+ * @param is_xts if true, the key is an XTS key -+ * -+ * @returns the cipher spec string (must be freed by the caller) -+ */ -+static char *_keystore_build_cipher_spec(struct properties *properties, -+ bool is_xts) -+{ -+ char *cipher_spec = NULL; -+ char *cipher = NULL; -+ char *ivmode = NULL; -+ -+ cipher = properties_get(properties, PROP_NAME_CIPHER); -+ if (cipher == NULL) -+ goto out; -+ -+ ivmode = properties_get(properties, PROP_NAME_IV_MODE); -+ if (ivmode == NULL) -+ goto out; -+ -+ util_asprintf(&cipher_spec, "%s-%s-%s", cipher, is_xts ? "xts" : "cbc", -+ ivmode); -+ -+out: -+ if (cipher != NULL) -+ free(cipher); -+ if (ivmode != NULL) -+ free(ivmode); -+ -+ return cipher_spec; -+} -+ -+/** -+ * 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. -+ * -+ * @param[in] keystore the keystore -+ * @param[in] name the name of the key -+ * @param[in] properties the properties object of the key -+ * @param[in] file_names the file names used by this key -+ * @param[in] private private data: struct crypt_info -+ * -+ * @returns 0 if the validation is successful, a negative errno value otherwise -+ */ -+static int _keystore_process_crypt(struct keystore *keystore, -+ const char *name, -+ struct properties *properties, -+ struct key_filenames *file_names, -+ void *private) -+{ -+ struct crypt_info *info = (struct crypt_info *)private; -+ char **volume_list = NULL; -+ char *cipher_spec = NULL; -+ size_t secure_key_size; -+ size_t sector_size = 0; -+ char *volumes = NULL; -+ char *dmname; -+ char *temp; -+ int rc = 0; -+ char *vol; -+ 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; -+ } -+ -+ cipher_spec = _keystore_build_cipher_spec(properties, -+ IS_XTS(secure_key_size)); -+ if (cipher_spec == NULL) { -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ volumes = properties_get(properties, PROP_NAME_VOLUMES); -+ if (volumes == NULL) -+ return -EINVAL; -+ volume_list = str_list_split(volumes); -+ -+ temp = properties_get(properties, PROP_NAME_SECTOR_SIZE); -+ if (temp != NULL) { -+ util_assert(sscanf(temp, "%lu", §or_size) == 1, -+ "Internal error: sscanf failed"); -+ free(temp); -+ } -+ -+ for (i = 0; volume_list[i] != NULL && rc == 0; i++) { -+ vol = volume_list[i]; -+ if (_keystore_match_filter(vol, info->volume_filter, -+ NULL) != 0) { -+ ch = strchr(vol, ':'); -+ if (ch == NULL) { -+ warnx("Volume does not contain a dm-name part." -+ " Key: '%s'", name); -+ rc = -EINVAL; -+ break; -+ } -+ *ch = '\0'; -+ dmname = ch + 1; -+ -+ rc = info->process_func(keystore, vol, dmname, -+ cipher_spec, file_names->skey_filename, -+ secure_key_size, sector_size, info); -+ if (rc != 0) -+ break; -+ } -+ } -+ -+out: -+ if (volumes != NULL) -+ free(volumes); -+ if (volume_list != NULL) -+ str_list_free_string_array(volume_list); -+ if (cipher_spec != NULL) -+ free(cipher_spec); -+ return rc; -+} -+ -+/** -+ * Generates cryptsetup commands for one or multiple volumes. -+ * -+ * @param[in] keystore the key store -+ * @param[in] volume_filter the volume filter. Can contain wild cards, and -+ * mutliple volume filters separated by commas. -+ * The ':dm-name' part of the volume is optional -+ * for the volume filter. If not specified, the filter -+ * checks the volume part only. -+ * @param[in] execute If TRUE the cryptsetup command is executed, -+ * otherwise it is printed to stdout -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, -+ bool execute) -+{ -+ struct crypt_info info = { 0 }; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ if (volume_filter == NULL) -+ volume_filter = "*"; -+ info.execute = execute; -+ info.volume_filter = str_list_split(volume_filter); -+ info.process_func = _keystore_process_cryptsetup; -+ -+ rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, -+ _keystore_process_crypt, &info); -+ -+ str_list_free_string_array(info.volume_filter); -+ -+ if (rc < 0) -+ pr_verbose(keystore, "Cryptsetup failed with: %s", -+ strerror(-rc)); -+ else if (rc > 0) -+ pr_verbose(keystore, "Cryptsetup failed with: %d", rc); -+ else -+ pr_verbose(keystore, -+ "Successfully generated cryptsetup commands"); -+ -+ return rc; -+} -+ -+/** -+ * Generates crypttab entries for one or multiple volumes. -+ * -+ * @param[in] keystore the key store -+ * @param[in] volume_filter the volume filter. Can contain wild cards, and -+ * mutliple volume filters separated by commas. -+ * The ':dm-name' part of the volume is optional -+ * for the volume filter. If not specified, the filter -+ * checks the volume part only. -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+int keystore_crypttab(struct keystore *keystore, const char *volume_filter) -+{ -+ struct crypt_info info = { 0 }; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ if (volume_filter == NULL) -+ volume_filter = "*"; -+ info.volume_filter = str_list_split(volume_filter); -+ info.process_func = _keystore_process_crypttab; -+ -+ rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, -+ _keystore_process_crypt, &info); -+ -+ str_list_free_string_array(info.volume_filter); -+ -+ if (rc != 0) -+ pr_verbose(keystore, "Cryptsetup failed with: %s", -+ strerror(-rc)); -+ else -+ pr_verbose(keystore, "Successfully generated crypttab entries"); -+ -+ return rc; -+} -+ -+/** -+ * Frees a keystore object -+ * -+ * @param[in] keystore the key store -+ */ -+void keystore_free(struct keystore *keystore) -+{ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ -+ _keystore_unlock_repository(keystore); -+ free(keystore->directory); -+ free(keystore); -+} ---- /dev/null -+++ b/zkey/keystore.h -@@ -0,0 +1,77 @@ -+/* -+ * zkey - Generate, re-encipher, and validate secure keys -+ * -+ * Keystore handling functions -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 KEYSTORE_H -+#define KEYSTORE_H -+ -+#include -+ -+#include "pkey.h" -+ -+struct keystore { -+ bool verbose; -+ char *directory; -+ int lock_fd; -+ mode_t mode; -+ gid_t owner; -+}; -+ -+struct keystore *keystore_new(const char *directory, bool verbose); -+ -+int keystore_generate_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, size_t sector_size, -+ size_t keybits, bool xts, const char *clear_key_file, -+ int pkey_fd); -+ -+int keystore_import_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, size_t sector_size, -+ const char *import_file); -+ -+int keystore_change_key(struct keystore *keystore, const char *name, -+ const char *description, const char *volumes, -+ const char *apqns, long int sector_size); -+ -+int keystore_rename_key(struct keystore *keystore, const char *name, -+ const char *newname); -+ -+int keystore_validate_key(struct keystore *keystore, const char *name_filter, -+ const char *apqn_filter, int pkey_fd); -+ -+int keystore_reencipher_key(struct keystore *keystore, const char *name_filter, -+ const char *apqn_filter, -+ bool from_old, bool to_new, bool inplace, -+ bool staged, bool complete, int pkey_fd, -+ t_CSNBKTC dll_CSNBKTC); -+ -+int keystore_copy_key(struct keystore *keystore, const char *name, -+ const char *newname, const char *volumes); -+ -+int keystore_export_key(struct keystore *keystore, const char *name, -+ const char *export_file); -+ -+int keystore_remove_key(struct keystore *keystore, const char *name, -+ bool quiet); -+ -+int keystore_list_keys(struct keystore *keystore, const char *name_filter, -+ const char *volume_filter, const char *apqn_filter); -+ -+int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, -+ bool execute); -+ -+int keystore_crypttab(struct keystore *keystore, const char *volume_filter); -+ -+void keystore_free(struct keystore *keystore); -+ -+ -+ -+#endif diff --git a/s390-tools-sles15sp1-0006-zkey-Add-keystore-related-commands.patch b/s390-tools-sles15sp1-0006-zkey-Add-keystore-related-commands.patch deleted file mode 100644 index f20bf5a..0000000 --- a/s390-tools-sles15sp1-0006-zkey-Add-keystore-related-commands.patch +++ /dev/null @@ -1,1418 +0,0 @@ -Subject: zkey: Add keystore related commands -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: e2f92e4079eb3588574e3346a56472fb26128a7d -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Add keystore related commands - - Add new commands to the zkey utility to store secure AES keys in - the secure key repository provided by the keystore implementation - introduced in the previous commit. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/misc.h | 19 - - zkey/zkey.c | 1072 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- - 2 files changed, 1024 insertions(+), 67 deletions(-) - ---- a/zkey/misc.h -+++ b/zkey/misc.h -@@ -3,7 +3,7 @@ - * - * Local helper functions - * -- * Copyright 2017 IBM Corp. -+ * Copyright IBM Corp. 2017, 2018 - * - * s390-tools is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. -@@ -37,7 +37,7 @@ void misc_print_invalid_command(const ch - /** - * An required parameter has not been specified - * -- * @param[in] option Parameter string -+ * @param[in] parm_name Parameter string - */ - void misc_print_required_parm(const char *parm_name) - { -@@ -45,4 +45,17 @@ void misc_print_required_parm(const char - util_prg_print_parse_error(); - } - --#endif -\ No newline at end of file -+/** -+ * An required parameter has not been specified -+ * -+ * @param[in] parm_name1 Parameter string 1 -+ * @param[in] parm_name2 Parameter string 2 -+ */ -+static void misc_print_required_parms(const char *parm_name1, -+ const char *parm_name2) -+{ -+ warnx("Parameter '%s' or '%s' is required", parm_name1, parm_name2); -+ util_prg_print_parse_error(); -+} -+ -+#endif ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -1,7 +1,7 @@ - /* - * zkey - Generate, re-encipher, and validate secure keys - * -- * Copyright 2017 IBM Corp. -+ * Copyright IBM Corp. 2017, 2018 - * - * s390-tools is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. -@@ -27,6 +27,7 @@ - #include "lib/util_prg.h" - #include "lib/zt_common.h" - -+#include "keystore.h" - #include "misc.h" - #include "pkey.h" - -@@ -34,30 +35,77 @@ - * Program configuration - */ - const struct util_prg prg = { -- .desc = "Generate, re-encipher, and validate secure AES keys", -- .command_args = "COMMAND SECURE-KEY-FILE", -+ .desc = "Manage secure AES keys", -+ .command_args = "COMMAND [SECURE-KEY-FILE]", - .args = "", - .copyright_vec = { - { - .owner = "IBM Corp.", - .pub_first = 2017, -- .pub_last = 2017, -+ .pub_last = 2018, - }, - UTIL_PRG_COPYRIGHT_END - } - }; - - /* -+ * Global variables for program options -+ */ -+static struct zkey_globals { -+ char *pos_arg; -+ char *clearkeyfile; -+ char *outputfile; -+ bool xts; -+ bool verbose; -+ long int keybits; -+ bool tonew; -+ bool fromold; -+ bool complete; -+ bool inplace; -+ bool staged; -+ char *name; -+ char *description; -+ char *volumes; -+ char *apqns; -+ long int sector_size; -+ char *newname; -+ bool run; -+ bool force; -+ void *lib_csulcca; -+ t_CSNBKTC dll_CSNBKTC; -+ int pkey_fd; -+ struct keystore *keystore; -+} g = { -+ .pkey_fd = -1, -+ .sector_size = -1, -+}; -+ -+/* - * Available commands - */ - #define COMMAND_GENERATE "generate" - #define COMMAND_REENCIPHER "reencipher" - #define COMMAND_VALIDATE "validate" -+#define COMMAND_IMPORT "import" -+#define COMMAND_EXPORT "export" -+#define COMMAND_LIST "list " -+#define COMMAND_REMOVE "remove" -+#define COMMAND_CHANGE "change" -+#define COMMAND_RENAME "rename" -+#define COMMAND_COPY "copy " -+#define COMMAND_CRYPTTAB "crypttab" -+#define COMMAND_CRYPTSETUP "cryptsetup" -+ -+#define ZKEY_COMMAND_MAX_LEN 10 -+ -+#define ENVVAR_ZKEY_REPOSITORY "ZKEY_REPOSITORY" -+#define DEFAULT_KEYSTORE "/etc/zkey/repository" - - /* - * Configuration of command line options - */ - static struct util_opt opt_vec[] = { -+ /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, - .desc = "OPTIONS", -@@ -91,6 +139,49 @@ static struct util_opt opt_vec[] = { - .command = COMMAND_GENERATE, - }, - { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository. If " -+ "option --name/-N is specified, then the generated " -+ "secure AES key is stored in the repository. Parameter " -+ "SECURE-KEY-FILE is not used when option --name/-M is " -+ "specified", -+ .command = COMMAND_GENERATE, -+ }, -+ { -+ .option = { "description", required_argument, NULL, 'd'}, -+ .argument = "DESCRIPTION", -+ .desc = "Textual description of the secure AES key in the " -+ "repository", -+ .command = COMMAND_GENERATE, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME:DMNAME[,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository", -+ .command = COMMAND_GENERATE, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository", -+ .command = COMMAND_GENERATE, -+ }, -+ { -+ .option = { "sector-size", required_argument, NULL, 'S'}, -+ .argument = "bytes", -+ .desc = "The sector size used with dm-crypt. It must be a power " -+ "of two and in range 512 - 4096 bytes. If this option " -+ "is omitted, the system default sector size (512) is " -+ "used", -+ .command = COMMAND_GENERATE, -+ }, -+ /***********************************************************/ -+ { - .flags = UTIL_OPT_FLAG_SECTION, - .desc = "OPTIONS", - .command = COMMAND_REENCIPHER, -@@ -119,12 +210,322 @@ static struct util_opt opt_vec[] = { - .command = COMMAND_REENCIPHER, - }, - { -+ .option = {"complete", 0, NULL, 'p'}, -+ .desc = "Completes a pending re-enciphering of a secure AES " -+ "key that was re-enciphered with the master key in the " -+ "NEW register", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = {"in-place", 0, NULL, 'i'}, -+ .desc = "Forces an in-place re-enchipering of a secure AES key", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = {"staged", 0, NULL, 's'}, -+ .desc = "Forces a staged re-enchipering of a secure AES key", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES keys in the repository that " -+ "are to be re-enciphered. You can use wild-cards to " -+ "select the keys to re-encipher.", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository. Use this option to re-encipher all keys " -+ "associated with specific crypto cards", -+ .command = COMMAND_REENCIPHER, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_VALIDATE, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES keys in the repository that " -+ "are to be validated. You can use wild-cards to select " -+ "the keys to validate.", -+ .command = COMMAND_VALIDATE, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository. Use this option to validate all keys " -+ "associated with specific crypto cards", -+ .command = COMMAND_VALIDATE, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_IMPORT, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the imported secure AES key in the repository", -+ .command = COMMAND_IMPORT, -+ }, -+ { -+ .option = { "description", required_argument, NULL, 'd'}, -+ .argument = "DESCRIPTION", -+ .desc = "Textual description of the secure AES key in the " -+ "repository", -+ .command = COMMAND_IMPORT, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME:DMNAME[,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository", -+ .command = COMMAND_IMPORT, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository", -+ .command = COMMAND_IMPORT, -+ }, -+ { -+ .option = { "sector-size", required_argument, NULL, 'S'}, -+ .argument = "512|4096", -+ .desc = "The sector size used with dm-crypt. It must be power " -+ "of two and in range 512 - 4096 bytes. If this option " -+ "is omitted, the system default sector size (512) is " -+ "used", -+ .command = COMMAND_IMPORT, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_EXPORT, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository that is " -+ "to be exported", -+ .command = COMMAND_EXPORT, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_LIST, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES keys in the repository that " -+ "are to be listed. You can use wild-cards to select " -+ "the keys to list.", -+ .command = COMMAND_LIST, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME[:DMNAME][,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository. Use this option to list all keys " -+ "associated with specific volumes. The device-mapper " -+ "name (DMNAME) is optional. If specified, only those " -+ "keys are listed where both, the volume and the device-" -+ "mapper name matches", -+ .command = COMMAND_LIST, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository. Use this option to list all keys " -+ "associated with specific crypto cards", -+ .command = COMMAND_LIST, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_REMOVE, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository that is " -+ "to be removed", -+ .command = COMMAND_REMOVE, -+ }, -+ { -+ .option = {"force", 0, NULL, 'F'}, -+ .desc = "Do not prompt for a confirmation when removing a key", -+ .command = COMMAND_REMOVE, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_CHANGE, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository that is " -+ "to be changed", -+ .command = COMMAND_CHANGE, -+ }, -+ { -+ .option = { "description", required_argument, NULL, 'd'}, -+ .argument = "DESCRIPTION", -+ .desc = "Textual description of the secure AES key in the " -+ "repository", -+ .command = COMMAND_CHANGE, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "[+|-]VOLUME:DMNAME[,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository. To add pairs of volume and device-" -+ "mapper names to the key specify '+VOLUME:DMNAME[,...]'. " -+ "To remove pairs of volume and device-mapper names " -+ "from the key specify '-VOLUME:DMNAME[,...]'", -+ .command = COMMAND_CHANGE, -+ }, -+ { -+ .option = { "apqns", required_argument, NULL, 'a'}, -+ .argument = "[+|-]CARD.DOMAIN[,...]", -+ .desc = "Comma-separated pairs of crypto cards and domains " -+ "that are associated with the secure AES key in the " -+ "repository. To add pairs of crypto cards and domains " -+ "to the key specify '+CARD.DOMAIN[,...]'. To remove " -+ "pairs of crypto cards and domains from the key " -+ "specify '-CARD.DOMAIN[,...]'", -+ .command = COMMAND_CHANGE, -+ }, -+ { -+ .option = { "sector-size", required_argument, NULL, 'S'}, -+ .argument = "0|512|4096", -+ .desc = "The sector size used with dm-crypt. It must be power " -+ "of two and in range 512 - 4096 bytes. If this option " -+ "is omitted, the system default sector size (512) is " -+ "used", -+ .command = COMMAND_CHANGE, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_RENAME, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository that is " -+ "to be renamed", -+ .command = COMMAND_RENAME, -+ }, -+ { -+ .option = { "new-name", required_argument, NULL, 'w'}, -+ .argument = "NEW-NAME", -+ .desc = "New name of the secure AES key in the repository", -+ .command = COMMAND_RENAME, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_COPY, -+ }, -+ { -+ .option = { "name", required_argument, NULL, 'N'}, -+ .argument = "NAME", -+ .desc = "Name of the secure AES key in the repository that is " -+ "to be copied", -+ .command = COMMAND_COPY, -+ }, -+ { -+ .option = { "new-name", required_argument, NULL, 'w'}, -+ .argument = "NEW-NAME", -+ .desc = "New name of the secure AES key in the repository", -+ .command = COMMAND_COPY, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME:DMNAME[,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the copied secure AES " -+ "key in the repository. If option '--volumes/-l' is " -+ "omitted, no volumes are associated with the copied " -+ "key, because only one key can be associated to a " -+ "specific volume.", -+ .command = COMMAND_COPY, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_CRYPTTAB, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME[:DMNAME][,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository. Use this option to select the volumes " -+ "for which a crypttab entry is to be generated. The " -+ "device-mapper name (DMNAME) is optional. If specified, " -+ "only those volumes are selected where both, the " -+ "volume and the device-mapper name matches", -+ .command = COMMAND_CRYPTTAB, -+ }, -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_CRYPTSETUP, -+ }, -+ { -+ .option = { "volumes", required_argument, NULL, 'l'}, -+ .argument = "VOLUME[:DMNAME][,...]", -+ .desc = "Comma-separated pairs of volume and device-mapper " -+ "names that are associated with the secure AES key in " -+ "the repository. Use this option to select the volumes " -+ "for which a cryptsetup command is to be generated or " -+ "run. The device-mapper name (DMNAME) is optional." -+ " If specified, only those volumes are selected where " -+ "both, the volume and the device-mapper name matches", -+ .command = COMMAND_CRYPTSETUP, -+ }, -+ { -+ .option = {"run", 0, NULL, 'r'}, -+ .desc = "Runs the generated cryptsetup command", -+ .command = COMMAND_CRYPTSETUP, -+ }, -+ /***********************************************************/ -+ { - .flags = UTIL_OPT_FLAG_SECTION, - .desc = "COMMON OPTIONS" - }, - { - .option = {"verbose", 0, NULL, 'V'}, -- .desc = "Print additional information messages during processing", -+ .desc = "Print additional information messages during " -+ "processing", - }, - UTIL_OPT_HELP, - UTIL_OPT_VERSION, -@@ -139,17 +540,31 @@ static struct util_opt opt_vec[] = { - struct zkey_command { - char *command; - unsigned int abbrev_len; -- int (*function)(const char *keyfile); -+ int (*function)(void); - int need_cca_library; - int need_pkey_device; - char *short_desc; - char *long_desc; - int has_options; -+ char *pos_arg; -+ int pos_arg_optional; -+ char *pos_arg_alternate; -+ char **arg_alternate_value; -+ int need_keystore; - }; - --static int command_generate(const char *keyfile); --static int command_reencipher(const char *keyfile); --static int command_validate(const char *keyfile); -+static int command_generate(void); -+static int command_reencipher(void); -+static int command_validate(void); -+static int command_import(void); -+static int command_export(void); -+static int command_list(void); -+static int command_remove(void); -+static int command_change(void); -+static int command_rename(void); -+static int command_copy(void); -+static int command_crypttab(void); -+static int command_cryptsetup(void); - - static struct zkey_command zkey_commands[] = { - { -@@ -159,8 +574,14 @@ static struct zkey_command zkey_commands - .need_pkey_device = 1, - .short_desc = "Generate a secure AES key", - .long_desc = "Generate a secure AES key either by " -- "random or from a specified clear key", -+ "random or from a specified clear key and store " -+ "it either into SECURE-KEY-FILE or into the " -+ "repository", - .has_options = 1, -+ .pos_arg = "[SECURE-KEY-FILE]", -+ .pos_arg_optional = 1, -+ .pos_arg_alternate = "--name/-N", -+ .arg_alternate_value = &g.name, - }, - { - .command = COMMAND_REENCIPHER, -@@ -170,8 +591,12 @@ static struct zkey_command zkey_commands - .need_pkey_device = 1, - .short_desc = "Re-encipher an existing secure AES key", - .long_desc = "Re-encipher an existing secure AES " -- "key with another CCA master key", -+ "key that is either contained in SECURE-KEY-FILE " -+ "or is stored in the repository with another " -+ "CCA master key", - .has_options = 1, -+ .pos_arg = "[SECURE-KEY-FILE]", -+ .pos_arg_optional = 1, - }, - { - .command = COMMAND_VALIDATE, -@@ -179,8 +604,100 @@ static struct zkey_command zkey_commands - .function = command_validate, - .need_pkey_device = 1, - .short_desc = "Validate an existing secure AES key", -- .long_desc = "Validate an existing secure AES key and print " -- "information about the key", -+ .long_desc = "Validate an existing secure AES key that is " -+ "either contained in SECURE-KEY-FILE or is stored" -+ "in the repository and print information about " -+ "the key", -+ .has_options = 1, -+ .pos_arg = "[SECURE-KEY-FILE]", -+ .pos_arg_optional = 1, -+ }, -+ { -+ .command = COMMAND_IMPORT, -+ .abbrev_len = 2, -+ .function = command_import, -+ .short_desc = "Import a secure AES key", -+ .long_desc = "Import a secure AES key from a file into the " -+ "repository", -+ .has_options = 1, -+ .pos_arg = "SECURE-KEY-FILE", -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_EXPORT, -+ .abbrev_len = 2, -+ .function = command_export, -+ .short_desc = "Export a secure AES key", -+ .long_desc = "Export a secure AES key from the repository to " -+ "a file", -+ .has_options = 1, -+ .pos_arg = "SECURE-KEY-FILE", -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_LIST, -+ .abbrev_len = 2, -+ .function = command_list, -+ .short_desc = "List keys in the repository", -+ .long_desc = "List secure AES key in the repository", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_REMOVE, -+ .abbrev_len = 3, -+ .function = command_remove, -+ .short_desc = "Remove a secure AES key", -+ .long_desc = "Remove a secure AES key from the repository", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_CHANGE, -+ .abbrev_len = 2, -+ .function = command_change, -+ .short_desc = "Change a secure AES key", -+ .long_desc = "Change the properties of a secure AES key in " -+ "the repository", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_RENAME, -+ .abbrev_len = 3, -+ .function = command_rename, -+ .short_desc = "Rename a secure AES key", -+ .long_desc = "Rename a secure AES key in the repository", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_COPY, -+ .abbrev_len = 2, -+ .function = command_copy, -+ .short_desc = "Copy a secure AES key", -+ .long_desc = "Copy a secure AES key in the repository", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_CRYPTTAB, -+ .abbrev_len = 6, -+ .function = command_crypttab, -+ .short_desc = "Generate crypttab entries", -+ .long_desc = "Generate crypttab entries for selected volumes", -+ .has_options = 1, -+ .need_keystore = 1, -+ }, -+ { -+ .command = COMMAND_CRYPTSETUP, -+ .abbrev_len = 6, -+ .function = command_cryptsetup, -+ .short_desc = "Generate or run cryptsetup commands", -+ .long_desc = "Generate or run cryptsetup commands for " -+ "selected volumes", -+ .has_options = 1, -+ .need_keystore = 1, - }, - { .command = NULL } - }; -@@ -197,9 +714,12 @@ static void print_usage_command(const st - for (i = 0; i < command->abbrev_len; i++) - command_str[i] = toupper(command_str[i]); - -- printf("Usage: %s %s SECURE-KEY-FILE", -+ printf("Usage: %s %s", - program_invocation_short_name, command_str); -- printf(" [OPTIONS]"); -+ if (command->pos_arg != NULL) -+ printf(" %s", command->pos_arg); -+ if (command->has_options) -+ printf(" [OPTIONS]"); - if (prg.args) - printf(" %s", prg.args); - printf("\n\n"); -@@ -222,7 +742,8 @@ static void print_usage_command_list(voi - strcpy(command_str, cmd->command); - for (i = 0; i < cmd->abbrev_len; i++) - command_str[i] = toupper(command_str[i]); -- printf(" %s\t%s\n", command_str, cmd->short_desc); -+ printf(" %-*s %s\n", ZKEY_COMMAND_MAX_LEN, command_str, -+ cmd->short_desc); - cmd++; - } - printf("\n"); -@@ -250,40 +771,21 @@ static void print_help(const struct zkey - } - - /* -- * Global variables for program options -- */ --static struct zkey_globals { -- char *clearkeyfile; -- char *outputfile; -- int xts; -- int verbose; -- long int keybits; -- int tonew; -- int fromold; -- void *lib_csulcca; -- t_CSNBKTC dll_CSNBKTC; -- int pkey_fd; --} g = { -- .pkey_fd = -1, --}; -- --/* - * Command handler for 'generate with clear key' - * - * Generate a secure key from the specified clear key. - */ --static int command_generate_clear(const char *keyfile) -+static int command_generate_clear(void) - { - int rc; - -- rc = generate_secure_key_clear(g.pkey_fd, keyfile, -+ rc = generate_secure_key_clear(g.pkey_fd, g.pos_arg, - g.keybits, g.xts, - g.clearkeyfile, - AUTOSELECT, AUTOSELECT, - g.verbose); -- if (rc != 0) -- rc = EXIT_FAILURE; -- return rc; -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } - - /* -@@ -291,29 +793,78 @@ static int command_generate_clear(const - * - * Generate a secure key by random using the pkey kernel module. - */ --static int command_generate_random(const char *keyfile) -+static int command_generate_random(void) - { - int rc; - -- rc = generate_secure_key_random(g.pkey_fd, keyfile, -+ rc = generate_secure_key_random(g.pkey_fd, g.pos_arg, - g.keybits, g.xts, - AUTOSELECT, AUTOSELECT, - g.verbose); -- if (rc != 0) -- rc = EXIT_FAILURE; - -- return rc; -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } - - /* -+ * Command handler for 'generate in repository'. -+ * -+ * Generate a secure key and store it in the repository. -+ */ -+static int command_generate_repository(void) -+{ -+ int rc; -+ -+ if (g.sector_size < 0) -+ g.sector_size = 0; -+ -+ rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes, -+ g.apqns, g.sector_size, g.keybits, g.xts, -+ g.clearkeyfile, g.pkey_fd); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+ -+/* - * Command handler for 'generate'. - * - * Generate a new secure key either by random or from the specified clear key. - */ --static int command_generate(const char *keyfile) -+static int command_generate(void) - { -- return g.clearkeyfile ? command_generate_clear(keyfile) -- : command_generate_random(keyfile); -+ if (g.pos_arg != NULL && g.name != NULL) { -+ warnx(" Option '--name|-N' is not valid for generating a key " -+ "outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.name != NULL) -+ return command_generate_repository(); -+ if (g.pos_arg != NULL) { -+ if (g.volumes != NULL) { -+ warnx("Option '--volumes|-l' is not valid for " -+ "generating a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.apqns != NULL) { -+ warnx("Option '--apqns|-a' is not valid for " -+ "generating a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.description != NULL) { -+ warnx("Option '--description|-d' is not valid for " -+ "generating a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ -+ return g.clearkeyfile ? command_generate_clear() -+ : command_generate_random(); -+ } -+ -+ return EXIT_FAILURE; - } - - -@@ -322,21 +873,52 @@ static int command_generate(const char * - * - * Re-encipher the specified secure key with the NEW or CURRENT CCA master key. - */ --static int command_reencipher(const char *keyfile) -+static int command_reencipher_file(void) - { - size_t secure_key_size; - int rc, is_old_mk; - u8 *secure_key; - -+ 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.apqns != NULL) { -+ warnx("Option '--apqns|-a' is not valid for " -+ "re-enciphering a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.inplace) { -+ warnx("Option '--in-place|-i' is not valid for " -+ "re-enciphering a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.staged) { -+ warnx("Option '--staged|-s' is not valid for " -+ "re-enciphering a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.complete) { -+ warnx("Option '--complete|-p' is not valid for " -+ "re-enciphering a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ - /* Read the secure key to be re-enciphered */ -- secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose); -+ 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, g.verbose); - if (rc != 0) { -- warnx("The secure key in file '%s' is not valid", keyfile); -+ warnx("The secure key in file '%s' is not valid", g.pos_arg); - rc = EXIT_FAILURE; - goto out; - } -@@ -401,7 +983,7 @@ static int command_reencipher(const char - pr_verbose("Secure key was re-enciphered successfully"); - - /* Write the migrated secure key */ -- rc = write_secure_key(g.outputfile ? g.outputfile : keyfile, -+ rc = write_secure_key(g.outputfile ? g.outputfile : g.pos_arg, - secure_key, secure_key_size, g.verbose); - if (rc != 0) - rc = EXIT_FAILURE; -@@ -411,11 +993,69 @@ out: - } - - /* -+ * Command handler for 'reencipher in repository'. -+ * -+ * Re-encipher the specified secure key with the NEW or CURRENT CCA master key. -+ */ -+static int command_reencipher_repository(void) -+{ -+ int rc; -+ -+ if (g.outputfile) { -+ warnx("Option '--output|-o' is not valid for " -+ "re-enciphering a key in the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.inplace && g.staged) { -+ warnx("Either '--in-place|-i' or '--staged|-s' can be " -+ "specified, but not both"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.complete) { -+ if (g.inplace) { -+ warnx("Option '--in-place|-i' is not valid together " -+ "with '--complete|-p'"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.staged) { -+ warnx("Option '--staged|-s' is not valid together " -+ "with '--complete|-p'"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ } -+ -+ 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); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'reencipher'. -+ * -+ * Re-encipher the specified secure key with the NEW or CURRENT CCA master key. -+ */ -+static int command_reencipher(void) -+{ -+ if (g.pos_arg != NULL) -+ return command_reencipher_file(); -+ else -+ return command_reencipher_repository(); -+ -+ return EXIT_FAILURE; -+} -+ -+/* - * Command handler for 'validate'. - * - * Validates the specified secure key and prints out information about it. - */ --static int command_validate(const char *keyfile) -+static int command_validate_file(void) - { - size_t secure_key_size; - size_t clear_key_size; -@@ -423,20 +1063,33 @@ static int command_validate(const char * - int is_old_mk; - int rc; - -+ if (g.name != NULL) { -+ warnx("Option '--name|-N' is not valid for " -+ "validating a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.apqns != NULL) { -+ warnx("Option '--apqns|-a' is not valid for " -+ "validating a key outside of the repository"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ - /* Read the secure key to be re-enciphered */ -- secure_key = read_secure_key(keyfile, &secure_key_size, g.verbose); -+ 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, - &clear_key_size, &is_old_mk, g.verbose); - if (rc != 0) { -- warnx("The secure key in file '%s' is not valid", keyfile); -+ warnx("The secure key in file '%s' is not valid", g.pos_arg); - rc = EXIT_FAILURE; - goto out; - } - -- printf("Validation of secure key in file '%s':\n", keyfile); -+ 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); -@@ -450,6 +1103,222 @@ out: - return rc; - } - -+/* -+ * Command handler for 'validate in repository'. -+ * -+ * Validates the specified secure key and prints out information about it. -+ */ -+static int command_validate_repository(void) -+{ -+ int rc; -+ -+ rc = keystore_validate_key(g.keystore, g.name, g.apqns, g.pkey_fd); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'validate'. -+ * -+ * Validates the specified secure key and prints out information about it. -+ */ -+static int command_validate(void) -+{ -+ if (g.pos_arg != NULL) -+ return command_validate_file(); -+ else -+ return command_validate_repository(); -+ -+ return EXIT_FAILURE; -+} -+ -+/* -+ * Command handler for 'import'. -+ * -+ * Imports a secure key from a file into the key repository. -+ */ -+static int command_import(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ -+ if (g.sector_size < 0) -+ g.sector_size = 0; -+ -+ rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes, -+ g.apqns, g.sector_size, g.pos_arg); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'export'. -+ * -+ * Exports a secure key from the repository to a file -+ */ -+static int command_export(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ -+ rc = keystore_export_key(g.keystore, g.name, g.pos_arg); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'list'. -+ * -+ * Lists keys stored in the repository -+ */ -+static int command_list(void) -+{ -+ int rc; -+ -+ rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'remove'. -+ * -+ * Remove a key from the repository -+ */ -+static int command_remove(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ -+ rc = keystore_remove_key(g.keystore, g.name, g.force); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'change'. -+ * -+ * Changes the properties of a key in the repository -+ */ -+static int command_change(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ -+ rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes, -+ g.apqns, g.sector_size); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'rname'. -+ * -+ * renames a key in the repository -+ */ -+static int command_rename(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ if (g.newname == NULL) { -+ misc_print_required_parm("--new-name/-w"); -+ return EXIT_FAILURE; -+ } -+ -+ rc = keystore_rename_key(g.keystore, g.name, g.newname); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'copy'. -+ * -+ * Copies a key in the repository -+ */ -+static int command_copy(void) -+{ -+ int rc; -+ -+ if (g.name == NULL) { -+ misc_print_required_parm("--name/-N"); -+ return EXIT_FAILURE; -+ } -+ if (g.newname == NULL) { -+ misc_print_required_parm("--new-name/-w"); -+ return EXIT_FAILURE; -+ } -+ -+ rc = keystore_copy_key(g.keystore, g.name, g.newname, g.volumes); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'crypttab'. -+ * -+ * Generates crypttab entries for selected volumes -+ */ -+static int command_crypttab(void) -+{ -+ int rc; -+ -+ rc = keystore_crypttab(g.keystore, g.volumes); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'cryptsetup'. -+ * -+ * Generates and runs cryptsetup commands for selected volumes -+ */ -+static int command_cryptsetup(void) -+{ -+ int rc; -+ -+ rc = keystore_cryptsetup(g.keystore, g.volumes, g.run); -+ -+ return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/** -+ * Opens the keystore. The keystore directory is either the -+ * default directory or as specified in an environment variable -+ */ -+static int open_keystore(void) -+{ -+ char *directory; -+ -+ directory = getenv(ENVVAR_ZKEY_REPOSITORY); -+ if (directory == NULL) -+ directory = DEFAULT_KEYSTORE; -+ -+ g.keystore = keystore_new(directory, g.verbose); -+ -+ return g.keystore == NULL ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+ - static bool is_command(struct zkey_command *command, const char *str) - { - char command_str[ZKEY_COMMAND_STR_LEN]; -@@ -484,12 +1353,34 @@ struct zkey_command *find_command(const - } - - /* -+ * Check if positional arguments are specified as needed by the command -+ */ -+static int check_positional_arg(struct zkey_command *command) -+{ -+ if (command->pos_arg_optional) { -+ if (g.pos_arg == NULL && -+ command->arg_alternate_value != NULL && -+ *command->arg_alternate_value == NULL) { -+ misc_print_required_parms(command->pos_arg, -+ command->pos_arg_alternate); -+ return EXIT_FAILURE; -+ } -+ } else { -+ if (g.pos_arg == NULL) { -+ misc_print_required_parm(command->pos_arg); -+ return EXIT_FAILURE; -+ } -+ } -+ -+ return EXIT_SUCCESS; -+} -+ -+/* - * Entry point - */ - int main(int argc, char *argv[]) - { - struct zkey_command *command = NULL; -- char *keyfile = NULL; - int arg_count = argc; - char **args = argv; - char *endp; -@@ -498,7 +1389,7 @@ int main(int argc, char *argv[]) - util_prg_init(&prg); - util_opt_init(opt_vec, NULL); - -- /* Get command if one is pspecified */ -+ /* Get command if one is specified */ - if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) { - command = find_command(argv[1]); - if (command == NULL) { -@@ -510,7 +1401,7 @@ int main(int argc, char *argv[]) - args = &argv[1]; - - if (argc >= 3 && strncmp(argv[2], "-", 1) != 0) { -- keyfile = argv[2]; -+ g.pos_arg = argv[2]; - arg_count = argc - 2; - args = &argv[2]; - } -@@ -550,6 +1441,47 @@ int main(int argc, char *argv[]) - case 'o': - g.fromold = 1; - break; -+ case 'p': -+ g.complete = 1; -+ break; -+ case 'i': -+ g.inplace = 1; -+ break; -+ case 's': -+ g.staged = 1; -+ break; -+ case 'N': -+ g.name = optarg; -+ break; -+ case 'd': -+ g.description = optarg; -+ break; -+ case 'l': -+ g.volumes = optarg; -+ break; -+ case 'a': -+ g.apqns = optarg; -+ break; -+ case 'S': -+ g.sector_size = strtol(optarg, &endp, 0); -+ if (*optarg == '\0' || *endp != '\0' || -+ g.sector_size < 0 || -+ (g.sector_size == LONG_MAX && errno == ERANGE)) { -+ warnx("Invalid value for '--sector-size'|'-S': " -+ "'%s'", optarg); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ break; -+ case 'w': -+ g.newname = optarg; -+ break; -+ case 'r': -+ g.run = 1; -+ break; -+ case 'F': -+ g.force = 1; -+ break; - case 'V': - g.verbose = 1; - break; -@@ -575,31 +1507,43 @@ int main(int argc, char *argv[]) - return EXIT_FAILURE; - } - -- if (keyfile == NULL) { -- misc_print_required_parm("SECURE-KEY-FILE"); -- return EXIT_FAILURE; -+ if (command->pos_arg != NULL) { -+ if (check_positional_arg(command) != EXIT_SUCCESS) -+ return EXIT_FAILURE; -+ } -+ -+ if (command->need_keystore || g.pos_arg == NULL) { -+ rc = open_keystore(); -+ if (rc != EXIT_SUCCESS) -+ goto out; - } - - if (command->need_cca_library) { - rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC, - g.verbose); -- if (rc != 0) -+ if (rc != 0) { -+ rc = EXIT_FAILURE; - goto out; -+ } - } - if (command->need_pkey_device) { - g.pkey_fd = open_pkey_device(g.verbose); -- if (g.pkey_fd == -1) -+ if (g.pkey_fd == -1) { -+ rc = EXIT_FAILURE; - goto out; -+ } - } - - umask(0077); - -- rc = command->function(keyfile); -+ rc = command->function(); - - out: - if (g.lib_csulcca) - dlclose(g.lib_csulcca); - if (g.pkey_fd >= 0) - close(g.pkey_fd); -+ if (g.keystore) -+ keystore_free(g.keystore); - return rc; - } diff --git a/s390-tools-sles15sp1-0007-zkey-Create-key-repository-and-group-during-make-ins.patch b/s390-tools-sles15sp1-0007-zkey-Create-key-repository-and-group-during-make-ins.patch deleted file mode 100644 index 9976f11..0000000 --- a/s390-tools-sles15sp1-0007-zkey-Create-key-repository-and-group-during-make-ins.patch +++ /dev/null @@ -1,40 +0,0 @@ -Subject: zkey: Create key repository and group during make install -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 6a2f4fd3760420e11b23db13f8b736f87764d409 -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Create key repository and group during make install - - Create the default keystore directory '/etc/zkey/repository' - and the user group 'zkeyadm' during make install. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/Makefile | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -36,6 +36,9 @@ install: all - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 -+ getent group zkeyadm >/dev/null || groupadd -r zkeyadm -+ $(INSTALL) -d -g zkeyadm -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey -+ $(INSTALL) -d -g zkeyadm -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository - - endif - diff --git a/s390-tools-sles15sp1-0008-zkey-Man-page-updates.patch b/s390-tools-sles15sp1-0008-zkey-Man-page-updates.patch deleted file mode 100644 index eabd889..0000000 --- a/s390-tools-sles15sp1-0008-zkey-Man-page-updates.patch +++ /dev/null @@ -1,1023 +0,0 @@ -Subject: zkey: Man page updates -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: f093d0bfd4242424515c6aa55c7b8ad94d233597 -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Man page updates - - Add documentation for the new keystore related zkey commands. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/zkey.1 | 870 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 811 insertions(+), 59 deletions(-) - ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -1,38 +1,17 @@ --.\" Copyright 2017 IBM Corp. -+.\" Copyright IBM Corp. 2017, 2018 - .\" s390-tools is free software; you can redistribute it and/or modify - .\" it under the terms of the MIT license. See LICENSE for details. - .\" --.TH ZKEY 1 "February 2017" "s390-tools" -+.TH ZKEY 1 "May 2018" "s390-tools" - .SH NAME --zkey \- Generates, re-enciphers, and validates secure AES keys -+zkey \- Manage secure AES keys - . - . - .SH SYNOPSIS - .B zkey --.BR generate | gen --.I secure\-key\-file --.RB [ \-\-keybits | \-k --.IB size ] --.RB [ \-\-xts | \-x ] --.RB [ \-\-clearkey | \-c --.IB clear\-key\-file ] --.RB [ \-\-verbose | \-V ] --. --.br --.B zkey --.BR validate | val --.I secure\-key\-file --.RB [ \-\-verbose | \-V ] --. --.br --.B zkey --.BR reencipher | re --.I secure\-key\-file --.RB [ \-\-to\-new | \-n ] --.RB [ \-\-from\-old | \-o ] --.RB [ \-\-output | \-f --.IB output\-file ] --.RB [ \-\-verbose | \-V ] -+.I command -+.RI [ secure\-key\-file ] -+.RB [ OPTIONS ] - . - .PP - .B zkey -@@ -44,64 +23,194 @@ zkey \- Generates, re-enciphers, and val - . - . - .SH DESCRIPTION --Use the \fBzkey\fP command to generate secure AES keys that are enciphered --with a master key of an IBM cryptographic adapter in CCA coprocessor mode. --You can also use the \fBzkey\fP command to validate and re-encipher secure -+Use the \fBzkey\fP tool to generate and manage secure AES keys that are -+enciphered with a master key of an IBM cryptographic adapter in CCA coprocessor -+mode. You can also use the \fBzkey\fP tool to validate and re-encipher secure - AES keys. - .PP -+The secure keys can either be stored in a file in the file system, or -+in the secure key repository. The default location of the secure key repository -+is \fB/etc/zkey/repository\fP. Set environment variable \fBZKEY_REPOSITORY\fP -+to point to a different location to use a different secure key repository -+location. Keys stored in a secure key repository inherit the permissions from -+the repository directory (except write access for other users, which is always -+denied). The default repository location \fB/etc/zkey/repository\fP is created -+with group \fBzkeyadm\fP as owner and mode \fB770\fP. Thus all secure keys -+created in that repository are owned by group \fBzkeyadm\fP. Anyone that -+is supposed to access secure keys in the secure key repository must be part of -+group \fBzkeyadm\fP. -+.PP -+When storing the secure key in a key repository, additional information, such as -+a textual description of the key, can be associated with a secure key. -+You can associate a secure key with one or multiple cryptographic adapters -+(APQNs) that are set up with the same CCA master key. -+You can also associate a secure key with one or multiple volumes -+(block devices), which are encrypted using dm-crypt with the secure key. The -+volume association also contains the device-mapper name, separated by a colon, -+used with dm-crypt. A specific volume can only be associated with one secure -+key. -+.PP - The generated secure key is saved in a file with a size of 64 or 128 bytes. --The file contains an AES key of 128, 192, or 256 bits enciphered with the --master key of the CCA cryptographic adapter. -+The file contains an AES key with a length of 128, 192, or 256 bits. The key is -+enciphered with the master key of the CCA cryptographic adapter. - Secure keys that are used for the XTS cipher mode can be 128 or 256 bits --in size, because XTS requires two concatenated secure keys. -+in size. -+. - . - . -+.SH COMMANDS -+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. -+When the -+.B \-\-name -+option is specified then it operates on a secure key contained in the secure -+key repository. - . --.SH USAGE -+.PP - .SS "Generating secure AES keys" -+. -+.B zkey -+.BR generate | gen -+.I secure\-key\-file -+.RB [ \-\-keybits | \-k -+.IB size ] -+.RB [ \-\-xts | \-x ] -+.RB [ \-\-clearkey | \-c -+.IB clear\-key\-file ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+.B zkey -+.BR generate | gen -+.B \-\-name | \-N -+.IB key-name -+.RB [ \-\-description | \-d -+.IB description ] -+.RB [ \-\-volumes | \-l -+.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.RB [ \-\-apqns | \-a -+.IB card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-sector-size | \-S -+.IB bytes ] -+.RB [ \-\-keybits | \-k -+.IB size ] -+.RB [ \-\-xts | \-x ] -+.RB [ \-\-clearkey | \-c -+.IB clear\-key\-file ] -+.RB [ \-\-verbose | \-V ] -+.PP - Use the - .B generate - command to generate a new secure AES key either randomly within the CCA - cryptographic adapter, or from a clear AES key specified as input. When specifying --a clear key as input, the clear key should be kept at a secure place, or be -+a clear key as input, the clear key should be kept in a secure place, or be - securely erased after creation of the secure key. The secure key itself does - not need to be kept secure, because it can only be used together with a - CCA cryptographic adapter that contains the master key with which the secure - key was generated. -+.PP -+The generated secure key can either be stored in a file in the file system, -+or in the secure key repository. To store the generated secure key in a -+file, specify the file name with option \fIsecure\-key\-file\fP. To store the -+secure key in the secure key repository, specify the name of the key using the -+.B --name -+option. When storing the secure key in a key repository, -+additional information can be associated with a secure key using the -+.B --description -+, -+.B --volumes -+, -+.B --apqns -+, or the -+.B --sector-size -+options. - . - .SS "Validating secure AES keys" -+. -+.B zkey -+.BR validate | val -+.I secure\-key\-file -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+.B zkey -+.BR validate | val -+.RB [ \-\-name | \-N -+.IB key-name ] -+.RB [ \-\-verbose | \-V ] -+.PP - Use the - .B validate - command to validate an existing secure key. --It checks if the specified file contains a valid secure key. -+It checks if the specified file or repository entry contains a valid secure key. - It also displays the attributes of the secure key, such as key sizes, whether --it is a secure key that can be used for the XTS cipher mode, and the master key --register with which the secure key is enciphered. -+it is a secure key that can be used for the XTS cipher mode, the master key -+register (CURRENT or OLD) with which the secure key is enciphered, and other key -+attributes. For further information about master key registers, see the -+\fBreencipher\fP command. -+.PP -+The secure key can either be contained in a file in the file system, or in a -+secure key repository. To validate a secure key contained in a file, specify -+the file name with option \fIsecure\-key\-file\fP. To validate secure keys -+contained in the secure key repository, specify the name of the key -+or a pattern containing wildcards using the -+.B --name -+option. When wildcards are used you must quote the value. -+If neither option \fIsecure\-key\-file\fP nor option -+.B --name -+are specified, then all secure keys contained in the key repository -+are validated. - . - .SS "Re-encipher existing AES secure keys" -+. -+.B zkey -+.BR reencipher | re -+.I secure\-key\-file -+.RB [ \-\-to\-new | \-n ] -+.RB [ \-\-from\-old | \-o ] -+.RB [ \-\-output | \-f -+.IB output\-file ] -+.RB [ \-\-verbose | \-V ] -+.PP -+.B zkey -+.BR reencipher | re -+.RB [ \-\-name | \-N -+.IB key-name ] -+.RB [ \-\-apqns | \-a -+.IB card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-to\-new | \-n ] -+.RB [ \-\-from\-old | \-o ] -+.RB [ \-\-in-place | \-i ] -+.RB [ \-\-staged | \-s ] -+.RB [ \-\-complete | \-c ] -+.RB [ \-\-verbose | \-V ] -+.PP - Use the - .B reencipher - command to re-encipher an existing secure key with a new master key. --A secure key have to be re-enciphered, when the master key of the CCA --cryptographic adapter is being changed. -+A secure key bust be re-enciphered when the master key of the CCA -+cryptographic adapter changes. - .PP --The CCA cryptographic adapter has 3 different registers to store -+The CCA cryptographic adapter has three different registers to store - master keys: - .RS 2 - .IP "\(bu" 2 --The \fPCURRENT\fP register contains the current master key. -+The \fBCURRENT\fP register contains the current master key. - . - .IP "\(bu" 2 - The \fBOLD\fP register contains the previously used master key. - Secure keys enciphered with the master key contained in the \fBOLD\fP --register canstill be used until the master key is changed again. -+register can still be used until the master key is changed again. - . - .IP "\(bu" 2 - 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. Note that a secure key can be proactively --re-enciphered with the master key in the \fBNEW\fP register before --the new master key is made the current one. -+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. Use the -+.B \-\-to-new -+option to do this. - .RE - .PP - Use the -@@ -110,13 +219,12 @@ option to re-encipher a secure key that - the master key in the \fBOLD\fP register with the master key in the - \fBCURRENT\fP register. - .PP --Use the --.B \-\-to\-new --option to proactively re-encipher a secure key that is currently --enciphered with the master key in the \fBCURRENT\fP register with --the master key in the \fBNEW\fP register. - .PP --If both options are specified, a secure key that is currently enciphered -+If both the -+.B \-\-from-old -+and -+.B \-\-to-new -+options are specified, a secure 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. - .PP -@@ -127,11 +235,310 @@ If currently enciphered with the master - 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 -+The secure key can either be contained in a file in the file system, or in a -+secure key repository. To re-encipher a secure key contained in a file, -+specify the file name with option \fIsecure\-key\-file\fP. To re-encipher -+secure keys contained in the secure key repository, specify the name of the key -+or a pattern containing wildcards using the -+.B --name -+option. When wildcards are used you must quote the value. -+You can also specify the -+.B --apqns -+option to re-encipher those secure -+keys which are associated with the specified cryptographic adapters (APQNs). -+You can use wildcards for the APQN specification. -+When wildcards are used you must quote the value. -+If both option -+.B --name -+and option -+.B --apqns -+are specified then all secure keys -+contained in the key repository that match both patterns are re-enciphered. -+If all both options are omitted, then all secure keys contained in the key -+repository are re-enciphered. -+.PP -+Re-enciphering a secure key contained in the secure key repository can be -+performed \fBin-place\fP, or in \fBstaged\fP mode. -+.PP -+\fB"In-place"\fP immediately replaces the secure key in the repository with -+the re-enciphered secure key. Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is -+performed in-place per default. You can use option \fB--in-place\fP to force an -+in-place re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that -+a secure key that was re-enciphered in-place from \fBCURRENT\fP to \fBNEW\fP -+is no longer valid, until the new CCA master key has been made the current one. -+.PP -+\fBStaged\fP mode means that the re-enciphered secure key is stored in a -+separate file in the secure key repository. Thus the current secure key is still -+valid at this point. Once the new CCA master key has been set (made active), you -+must rerun the reencipher command with option \fB--complete\fP to complete the -+staged re-enciphering. Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is -+performed in staged mode per default. You can use option \fB--staged\fP to force -+a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case. - .PP - .B Note: --The \fBreencipher\fP command requires the IBM CCA Host Library (libcsulcca.so) -+The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) - to be installed. - . -+.SS "Import existing AES secure keys into the secure key repository" -+. -+.B zkey -+.BR import | im -+.I secure\-key\-file -+.B \-\-name | \-N -+.IB key-name -+.RB [ \-\-description | \-d -+.IB description ] -+.RB [ \-\-volumes | \-l -+.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.RB [ \-\-apqns | \-a -+.IB card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-sector-size | \-S -+.IB bytes ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B import -+command to import an existing secure key contained in a file into the the -+secure key repository. When importing a secure key in a key repository, -+additional information can be associated with a secure key using the -+.B --description -+, -+.B --volumes -+, -+.B --apqns -+, or the -+.B --sector-size -+options. -+. -+.SS "Export AES secure keys from the secure key repository" -+. -+.B zkey -+.BR export | ex -+.I secure\-key\-file -+.B \-\-name | \-N -+.IB key-name -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B export -+command to export an existing secure key contained in the secure key repository -+to a file in the file system. Specify the name of the key that is to be exported -+using the -+.B --name -+option. You cannot use wildcards. -+When wildcards are used you must quote the value. -+The exported secure key also remains in the secure key repository. -+. -+.SS "List AES secure keys contained in the secure key repository" -+. -+.B zkey -+.BR list | li -+.RB [ \-\-name | \-N -+.IB key-name ] -+.RB [ \-\-volumes | \-l -+.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.RB [ \-\-apqns | \-a -+.IB card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B list -+command to display a list of secure keys contained in the secure key repository. -+You can filter the displayed list by key name, associated volumes, and -+associated cryptographic adapters (APQNs). You can use wildcards for the key -+name, associated APQNs, and associated volumes. The device-mapper name of an -+associated volume can be omitted; if it is specified then only those keys are -+listed that are associated with the specified volume and device-mapper name. -+.PP -+The -+.B list -+command displays the attributes of the secure keys, such as key sizes, -+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, and timestamps for key creation, last modification and last -+re-encipherment. -+. -+.SS "Remove existing AES secure keys from the secure key repository" -+. -+.B zkey -+.BR remove | rem -+.B \-\-name | \-N -+.IB key-name -+.RB [ \-\-force | \-F ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B remove -+command to remove an existing secure key from the secure key repository. -+Specify the name of the key that is to be removed using the -+.B --name -+option. You cannot use wildcards. The remove command prompts for -+a confirmation, unless you specify the -+.B --force -+option. -+.PP -+.B Note: -+When removing a secure key that is associated with one or multiple volumes, -+a message informs you about the associated volumes. When the secure key is -+removed, these volumes can no longer be used, unless you have a backup of the -+secure key. -+. -+.SS "Change existing AES secure keys contained the secure key repository" -+. -+.B zkey -+.BR change | ch -+.B \-\-name | \-N -+.IB key-name -+.RB [ \-\-description | \-d -+.IB description ] -+.RB [ \-\-volumes | \-l -+.IB [+|-]volume1:dmname1[,volume2:dmname2[,...]] ] -+.RB [ \-\-apqns | \-a -+.IB [+|-]card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-sector-size | \-S -+.IB bytes ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B change -+command to change the description, the associated volumes, the associated -+cryptographic adapters (APQNs), and the sector size of a secure key contained -+in the secure key repository. Specify the name of the key that is to be changed -+using the -+.B --name -+option. You cannot use wildcards. -+.PP -+You can set (replace), add, or -+remove volume and cryptographic adapters (APQN) associations. To set -+(replace) an association, specify the association with the -+.B --volumes -+or the -+.B --apqns -+options. To add an association, -+specify the new association prefixed with a \fI+\fP with the -+.B --volumes -+or the -+.B --apqns -+options. To remove an association, -+specify the association to remove prefixed with a \fI-\fP with the -+.B --volumes -+or the -+.B --apqns -+options. You cannot mix \fI+\fP and -+\fI-\fP in one specification. You can either add or remove (or set) the -+associations with one command. -+.PP -+.B Note: -+The secure key itself cannot be changed, only information about the secure -+key is changed. To rename a secure key, use the \fBrename\fP command. -+To re-encipher a secure key with a new CCA master key, use the \fBreencipher\fP -+command. -+. -+.SS "Rename existing AES secure keys in the secure key repository" -+. -+.B zkey -+.BR rename | ren -+.B \-\-name | \-N -+.IB key-name -+.B \-\-new-name | \-w -+.IB new-key-name -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B rename -+command to rename an existing secure key in the secure key repository. -+Specify the name of the key that is to be renamed using the -+.B --name -+option and the new name using the -+.B --new-name -+option. You cannot use wildcards. -+. -+.SS "Copy (duplicate) existing AES secure keys in the secure key repository" -+. -+.B zkey -+.B copy | co -+.RB \-\-name | \-N -+.IB key-name -+.B \-\-new-key-name | \-w -+.IB new-name -+.RB [ \-\-volumes | \-l -+.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B copy -+command to copy (duplicate) an existing secure key in the secure key repository. -+Specify the name of the key that is to be copied using the -+.B --name -+option and the name of the copied key using the -+.B --new-name -+option. You cannot use wildcards. -+.PP -+.B Note: -+When copying a secure key, the volume associations are not copied, because -+a specific volume can only be associated with a single secure key. Specify the -+.B --volumes -+option to associate different -+volumes with the copied secure key, or use the \fBchange\fP command to associate -+volumes afterwards. -+. -+.SS "Generate crypttab entries for volumes associated with secure AES keys" -+. -+.B zkey -+.BR crypttab | cryptt -+.RB [ \-\-volumes | \-l -+.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B crypttab -+command to generate crypttab entries using the \fBplain\fP dm-crypt mode -+for volumes that are associated with secure keys contained in the secure key -+repository. Specify the -+.B --volumes -+option to limit the list -+of volumes where crypttab entries are generated for. You can use wildcards. -+When wildcards are used you must quote the value. -+The device-mapper name of an associated volume can be omitted; if it is -+specified then only those volumes with the specified volume and device-mapper -+name are selected. -+. -+.SS "Generate cryptsetup commands for volumes associated with secure AES keys" -+. -+.B zkey -+.BR cryptsetup | crypts -+.RB [ \-\-volumes | \-l -+.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.RB [ \-\-run | \-r ] -+.RB [ \-\-verbose | \-V ] -+. -+.PP -+Use the -+.B cryptsetup -+command to generate \fBcryptsetup plainOpen\fP commands for volumes that are -+associated with secure keys contained in the secure key repository. Specify the -+.B --volumes -+option to limit the list -+of volumes where cryptsetup commands are generated for. You can use wildcards. -+When wildcards are used you must quote the value. -+The device-mapper name of an associated volume can be omitted; if it is -+specified then only those volumes with the specified volume and device-mapper -+name are selected. Specify the -+.B --run -+option to run the generated cryptsetup commands. -+. -+. - . - . - .SH OPTIONS -@@ -139,13 +546,13 @@ to be installed. - .TP - .BR \-k ", " \-\-keybits\~\fIsize\fP - Specifies the size of the AES key to be generated in bits. --Valid sizes are 128, 192, and 256 bits. Secure keys for use with the -+Valid values are 128, 192, and 256. Secure keys for use with the - XTS cipher mode can only use keys of 128 or 256 bits. - The default is 256 bits. - .TP - .BR \-x ", " \-\-xts --Generates a secure AES key for the XTS cipher mode. A secure AES key for --the XTS cipher mode consist of two concatenated secure keys. -+Generates a secure AES key for the XTS cipher mode that consist of two -+concatenated secure keys. - .TP - .BR \-c ", " \-\-clearkey\~\fIclear\-key\-file\fP - Specifies a file path that contains the clear AES key in binary form. -@@ -154,6 +561,49 @@ determines the size of the AES key. If - is specified, the size of the specified file must match the specified - key size. Valid file sizes are of 16, 24, or 32 bytes, and of 32 or 64 - bytes for keys to be used with the XTS cipher mode. -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-d ", " \-\-description\~\fIdescription\fP -+Specifies a textual description for the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP -+Specifies a comma-separated list of volumes (block devices) that are -+associated with the secure AES key in the repository. These volumes are to be -+encrypted using dm-crypt with the secure AES key. The volume association also -+contains the device-mapper name, separated by a colon, used with dm-crypt. -+A specific volume can only be associated with a single secure key. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP -+Specifies a comma-separated list of cryptographic adapters in CCA -+coprocessor mode (APQN) which are associated with the secure AES key in the -+repository. Each APQN association specifies a card and domain number separated -+by a period (like lszcrypt displays it). When at least one APQN is specified, -+then the first one is used to generate the key. If no APQNs are specified, -+then an APQN is selected automatically. All specified APQNs must be online. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-S ", " \-\-sector-size\~\fIbytes\fP -+Specifies the sector size in bytes used with dm-crypt. It must be a power of two -+and in the range 512 - 4096 bytes. If omitted, the system default sector size -+is used. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the validate command" -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key in the secure key repository. You can -+use wildcards to select multiple secure keys in the secure key repository. -+When wildcards are used you must quote the value. -+This option is only used for secure keys contained in the secure key repository. -+. -+. - . - .SS "Options for the reencipher command" - .TP -@@ -168,7 +618,256 @@ master key in the OLD register with the - .BR \-f ", " \-\-output\~\fIoutput\-file\fP - Specifies the name of the output file to which the re-enciphered secure key - is written. If this option is omitted, the re-enciphered secure key --is replaced in the file that currently contains the secure key. -+is replaced in the file that currently contains the secure key. This option is -+only used for secure keys stored in a file in the file system. It is not valid -+for keys contained in the secure key repository. -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key in the secure key repository. You can -+use wildcards to select multiple secure keys in the secure key repository. -+When wildcards are used you must quote the value. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP -+Specifies a comma-separated list of cryptographic adapters in CCA -+coprocessor mode (APQNs). You can use wildcards in the APQN specification. -+All secure keys contained in the secure key repository -+which are associated with the specified APQNs are re-enciphered. -+Each APQN specifies a card and domain number separated by a period (like -+lszcrypt displays it). -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-i ", " \-\-in-place -+Forces an in-place re-enciphering of a secure AES key contained in the secure -+key repository. "In-place" immediately replaces the secure key in the repository -+with the re-enciphered secure key. -+Re-enciphering from OLD to CURRENT is performed in-place per default. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-s ", " \-\-staged -+Forces that the re-enciphering of a secure AES key contained in the secure key -+repository is performed in staged mode. Staged mode means that the re-enciphered -+secure key is stored in a separate file in the secure key repository. Thus the -+current secure key is still valid at this point. Once the new CCA master key has -+been set (made active), you must rerun the reencipher command with option -+\fB--complete\fP to complete the staged re-enciphering. -+Re-enciphering from CURRENT to NEW is performed in staged mode per default. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-p ", " \-\-complete -+Completes a staged re-enciphering. Use this option after the new CCA master key -+has been set (made active). This option replaces the secure key by its -+re-enciphered version in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+. -+.SS "Options for the import command" -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-d ", " \-\-description\~\fIdescription\fP -+Specifies a textual description for the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with the secure AES key in the repository. These volumes are to be -+encrypted using dm-crypt with the secure AES key. The volume association also -+contains the device-mapper name, separated by a colon, used with dm-crypt. -+A specific volume can only be associated with a single secure key. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP -+Specifies a comma-separated list of cryptographic adapters in CCA -+coprocessor mode (APQN) which are associated with the secure AES key in the -+repository. Each APQN association specifies a card and domain number separated -+by a period (like lszcrypt displays it). All specified APQNs must be online. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-S ", " \-\-sector-size\~\fIbytes\fP -+Specifies the sector size in bytes used with dm-crypt. It must be a power of two -+and in the range 512 - 4096 bytes. If omitted, the system default sector size -+is used. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the export 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. -+. -+. -+. -+.SS "Options for the list command" -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key in the secure key repository. You can -+use wildcards to select multiple secure keys in the secure key repository. -+When wildcards are used you must quote the value. -+Only keys with names that match the pattern are listed. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with the secure AES key in the repository. Only those keys are -+listed, which are associated with the specified volumes. -+The volume association also contains the device-mapper name, separated by a -+colon, used with dm-crypt. You can omit the device-mapper name; if it is -+specified then only those keys are listed that are associated with the -+specified volume and device-mapper name. You can use wildcards to specify -+the volumes and device-mapper names. -+When wildcards are used you must quote the value. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP -+Specifies a comma-separated list of cryptographic adapters in CCA -+coprocessor mode (APQN) which are associated with the secure AES key in the -+repository. Only those keys are listed, which are associated with the specified -+APQNs. Each APQN association specifies a card and domain number separated -+by a period (like lszcrypt displays it). You can use wildcards in the APQN -+specification. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the remove 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 \-F ", " \-\-force\fP -+The user is prompted to confirm the removal of a secure key from the secure -+key repository. Use this option to remove a secure key without prompting for -+a confirmation. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the change 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 \-d ", " \-\-description\~\fIdescription\fP -+Specifies a textual description for the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fI[+|-]volume1:dmname1[,volume2:dmname2[,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with the secure AES key in the repository. These volumes are to be -+encrypted using dm-crypt with the secure AES key. The volume association also -+contains the device-mapper name, separated by a colon, used with dm-crypt. -+To add a volume to the associated volumes, prefix the volume with a \fI+\fP. -+To remove a volume from the associated volumes, prefix the volume with a \fI-\fP. -+To set (replace) the volume association do not specify a prefix. -+You cannot mix \fI+\fP and \fI-\fP in one specification. You can either add or -+remove (or set) the associations with one command. -+A specific volume can only be associated with a single secure key. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-a ", " \-\-apqns\~\fI[+|-]card1.domain1[,card2.domain2[,...]]\fP -+Specifies a comma-separated list of cryptographic adapters in CCA -+coprocessor mode (APQN) which are associated with the secure AES key in the -+repository. Each APQN association specifies a card and domain number separated -+by a period (like lszcrypt displays it). -+To add an APQN to the associated APQNs, prefix the APQN with a \fI+\fP. -+To remove an APQN from the associated APQNs, prefix the APQN with a \fI-\fP. -+To set (replace) the APQN association do not specify a prefix. -+You cannot mix \fI+\fP and \fI-\fP in one specification. You can either add or -+remove (or set) the associations with one command. -+All APQNs being added or set (replaced) must be online. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-S ", " \-\-sector-size\~\fIbytes\fP -+Specifies the sector size in bytes used with dm-crypt. It must be a power of two -+and in the range 512 - 4096 bytes. If omitted, the system default sector size -+is used. Specify \fI0\fP to un-set the sector size so that the system default -+is used. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the rename 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 \-w ", " \-\-new-name\~\fInew-key-name\fP -+Specifies the new name of the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the copy command" -+.TP -+.BR \-N ", " \-\-name\~\fIkey-name\fP -+Specifies the name of the secure key to be copied 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 \-w ", " \-\-new-name\~\fInew-key-name\fP -+Specifies the new name of the secure key in the secure key repository. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1,volume2:dmname2[,...]]\fP -+Volume associations are not copied, because a volume can only be associated -+with a single secure key. To associate different volumes with the copied -+secure AES key, specify a comma-separated list of volumes (block devices). -+These volumes are to be encrypted using dm-crypt with the secure AES key. The -+volume association also contains the device-mapper name, separated by a colon, -+used with dm-crypt. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the crypttab command" -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with secure AES keys in the repository. -+The volume association also contains the device-mapper name, separated by a -+colon, used with dm-crypt. You can omit the device-mapper name; if it is -+specified then only those keys are selected that are associated with the -+specified volume and device-mapper name. You can use wildcards to specify -+the volumes and device-mapper names. -+When wildcards are used you must quote the value. -+This option is only used for secure keys contained in the secure key repository. -+. -+. -+. -+.SS "Options for the cryptsetup command" -+.TP -+.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP -+Specifies a comma-separated list of volumes (block devices) which are -+associated with secure AES keys in the repository. -+The volume association also contains the device-mapper name, separated by a -+colon, used with dm-crypt. You can omit the device-mapper name; if it is -+specified then only those keys are selected that are associated with the -+specified volume and device-mapper name. You can use wildcards to specify -+the volumes and device-mapper names. -+When wildcards are used you must quote the value. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-r ", " \-\-run\fP -+Runs the generated cryptsetup commands. When an execution of a cryptsetup -+command fails, no further cryptsetup commands are executed, and zkey ends -+with an error. -+This option is only used for secure keys contained in the secure key repository. -+. -+. - . - .SS "General options" - .TP -@@ -186,16 +885,25 @@ Displays version information and exits. - .SH EXAMPLES - .TP - .B zkey generate seckey.bin --Generates a 256-bit secure AES key and stores it in file 'seckey.bin'. -+Generates a random 256-bit secure AES key and stores it in file 'seckey.bin'. - .TP - .B zkey generate seckey.bin \-\-keybits 128 \-\-xts --Generates a 128-bit secure AES key for the XTS cipher mode and stores it -+Generates a random 128-bit secure AES key for the XTS cipher mode and stores it - in file 'seckey.bin'. - .TP - .B zkey generate seckey.bin \-\-clearkey clearkey.bin - Generates a secure AES key from the clear key in file 'clearkey.bin' and - stores it in file 'seckey.bin'. - .TP -+.B zkey generate --name seckey -+Generates a random 256-bit secure AES key and stores it in the secure key -+repository under the name 'seckey'. -+.TP -+.B zkey generate --name seckey --volumes /dev/dasdc1:encvol --apqns 03.004c -+Generates a random 256-bit secure AES key and stores it in the secure key -+repository under the name 'seckey' and associates it with block -+device '/dev/dasdc1' and device-mapper name 'encvol', and APQN '03.004c'. -+.TP - .B zkey reencipher seckey.bin \-\-from\-old - Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered - with the master key in the OLD register with the master key in the CURRENT -@@ -207,5 +915,49 @@ Re-enciphers the secure key in file 'sec - with the master key in the CURRENT register with the master key in the NEW - register, and saves the re-enciphered secure key to file 'seckey2.bin'. - .TP -+.B zkey reencipher --name seckey -+Re-enciphers the secure key 'seckey' in the secure key repository. -+.TP -+.B zkey reencipher --apqns 03.004c -+Re-enciphers all secure keys contained in the secure key repository that are -+associated with APQN '03.004c'. -+.TP - .B zkey validate seckey.bin - Validates the secure key in file 'seckey.bin' and displays its attributes. -+.TP -+.B zkey validate --name seckey -+Validates the secure key 'seckey' in the secure key repository and displays its -+attributes. -+.TP -+.B zkey list -+Lists all secure keys in the secure key repository and displays its -+attributes. -+.TP -+.B zkey list --name '*key' -+Lists all secure keys in the secure key repository with names ending with 'key' -+and displays its attributes. -+.TP -+.B zkey change --name seckey --volumes +/dev/dasdc2:encvol2 -+Changes the secure key 'seckey' in the secure key repository and adds -+volume '/dev/dasdc2' with device-mapper name 'encvol2' to the list of associated -+volumes of this secure key. -+.TP -+.B zkey change --name seckey --apqns -03.004c -+Changes the secure key 'seckey' in the secure key repository and removes -+APQN '03.004c' from the list of associated APQNs of this secure key. -+.TP -+.B zkey crypttab --volumes '/dev/dasdc*' -+Generates crypttab entries for all volumes that match the pattern '/dev/dasdc*'. -+.TP -+.B zkey cryptsetup --volumes '*:enc_dasd' -+Generates cryptsetup commands for the volumes that uses the device-mapper -+name 'enc_dasd'. -+. -+.SH ENVIRONMENT -+.TP -+.BR ZKEY_REPOSITORY -+If -+.B $ZKEY_REPOSITORY -+is set, it specifies the location of the secure key repository. -+If it is not set, then the the default location of the secure key -+repository is \fB/etc/zkey/repository\fP. -\ No newline at end of file diff --git a/s390-tools-sles15sp1-0009-zkey-let-packaging-create-the-zkeyadm-group-and-perm.patch b/s390-tools-sles15sp1-0009-zkey-let-packaging-create-the-zkeyadm-group-and-perm.patch deleted file mode 100644 index 4194edf..0000000 --- a/s390-tools-sles15sp1-0009-zkey-let-packaging-create-the-zkeyadm-group-and-perm.patch +++ /dev/null @@ -1,38 +0,0 @@ -Subject: zkey: let packaging create the zkeyadm group and permission setup -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 3eb9af9c97c98e9f9665af1c5e671266400aaafc -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: let packaging create the zkeyadm group and permission setup - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - zkey/Makefile | 5 ++--- - 1 file changed, 2 insertions(+), 3 deletions(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -36,9 +36,8 @@ install: all - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 -- getent group zkeyadm >/dev/null || groupadd -r zkeyadm -- $(INSTALL) -d -g zkeyadm -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey -- $(INSTALL) -d -g zkeyadm -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository -+ $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey -+ $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository - - endif - diff --git a/s390-tools-sles15sp1-0010-zkey-Update-README-to-add-info-about-packaging-requi.patch b/s390-tools-sles15sp1-0010-zkey-Update-README-to-add-info-about-packaging-requi.patch deleted file mode 100644 index 44c0af0..0000000 --- a/s390-tools-sles15sp1-0010-zkey-Update-README-to-add-info-about-packaging-requi.patch +++ /dev/null @@ -1,34 +0,0 @@ -Subject: zkey: Update README to add info about packaging requirements -From: Philipp Rudo - -Summary: zkey: Add support of protected key crypto for dm-crypt. -Description: Support the usage of protected key crypto for dm-crypt disks in - plain format by providing a tool to manage a key repository - allowing to associate secure keys with disk partitions or logical - volumes. -Upstream-ID: 80b66da1d81793232646d2504c4d4c0ec94170f1 -Problem-ID: SEC1800 - -Upstream-Description: - - zkey: Update README to add info about packaging requirements - - Signed-off-by: Ingo Franzki - Signed-off-by: Jan Höppner - - -Signed-off-by: Philipp Rudo ---- - README.md | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/README.md -+++ b/README.md -@@ -371,3 +371,7 @@ the different tools are provided: - For building the zkey tools you need openssl version 0.9.7 or newer installed - (openssl-devel.rpm). Tip: you may skip the zkey build by adding - `HAVE_OPENSSL=0` to the make invocation. -+ A new group 'zkeyadm' needs to be created and all users intending to use the -+ tool must be added to this group. The owner of the default key repository -+ '/etc/zkey/repository' must be set to group 'zkeyadm' with write permission -+ for this group. diff --git a/s390-tools-sles15sp1-0011-zkey-Typo-in-message.patch b/s390-tools-sles15sp1-0011-zkey-Typo-in-message.patch deleted file mode 100644 index 3554ae6..0000000 --- a/s390-tools-sles15sp1-0011-zkey-Typo-in-message.patch +++ /dev/null @@ -1,34 +0,0 @@ -Subject: zkey: Typo in message -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: dec58c349e794f6333771457d9dcb9c0768fe28e -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Typo in message - - Signed-off-by: Ingo Franzki - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -2319,7 +2319,7 @@ static int _keystore_process_reencipher( - - if (params.complete) { - if (!_keystore_reencipher_key_exists(file_names)) { -- warnx("Staged re-enciphering in not pending for key " -+ warnx("Staged re-enciphering is not pending for key " - "'%s', skipping", - name); - info->num_skipped++; diff --git a/s390-tools-sles15sp1-0012-zkey-Fix-memory-leak.patch b/s390-tools-sles15sp1-0012-zkey-Fix-memory-leak.patch deleted file mode 100644 index fde16e8..0000000 --- a/s390-tools-sles15sp1-0012-zkey-Fix-memory-leak.patch +++ /dev/null @@ -1,102 +0,0 @@ -Subject: zkey: Fix memory leak -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: d6a96f07c1a0ba9b1a559561698f82f5a19829ff -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Fix memory leak - - The APQN check routine as well as the properties helper functions - do not free all memory that they allocated. - - Signed-off-by: Ingo Franzki - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 22 +++++++++++++++------- - zkey/properties.c | 5 +++++ - 2 files changed, 20 insertions(+), 7 deletions(-) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -981,25 +981,33 @@ static int _keystore_apqn_check(const ch - rc = regexec(®_buf, apqn, (size_t) 1, pmatch, 0); - if (rc != 0) { - warnx("the APQN '%s' is not valid", apqn); -- return -EINVAL; -+ rc = -EINVAL; -+ goto out; - } - -- if (sscanf(apqn, "%x.%x", &card, &domain) != 2) -- return -EINVAL; -+ if (sscanf(apqn, "%x.%x", &card, &domain) != 2) { -+ rc = -EINVAL; -+ goto out; -+ } - - util_asprintf(normalized, "%02x.%04x", card, domain); - -- if (remove) -- return 0; -+ if (remove) { -+ rc = 0; -+ goto out; -+ } - - rc = _keystore_is_apqn_online(card, domain); - if (rc != 1) { - warnx("The APQN %02x.%04x is %s", card, domain, - rc == -1 ? "not a CCA card" : "not online"); -- return -EIO; -+ rc = -EIO; -+ goto out; - } - -- return 0; -+out: -+ regfree(®_buf); -+ return rc; - } - - ---- a/zkey/properties.c -+++ b/zkey/properties.c -@@ -149,6 +149,7 @@ void properties_free(struct properties * - free(property->name); - free(property->value); - util_list_remove(&properties->list, property); -+ free(property); - } - - free(properties); -@@ -259,6 +260,7 @@ int properties_remove(struct properties - free(property->name); - free(property->value); - util_list_remove(&properties->list, property); -+ free(property); - return 0; - } - -@@ -614,10 +616,13 @@ char *str_list_remove(const char *str_li - */ - void str_list_free_string_array(char **strings) - { -+ char **list = strings; -+ - util_assert(strings != NULL, "Internal error: strings is NULL"); - - while (*strings != NULL) { - free((void *)*strings); - strings++; - } -+ free(list); - } diff --git a/s390-tools-sles15sp1-0013-zkey-Fix-APQN-validation-routine.patch b/s390-tools-sles15sp1-0013-zkey-Fix-APQN-validation-routine.patch deleted file mode 100644 index 38ab4db..0000000 --- a/s390-tools-sles15sp1-0013-zkey-Fix-APQN-validation-routine.patch +++ /dev/null @@ -1,47 +0,0 @@ -Subject: zkey: Fix APQN validation routine -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 344965bd296f434ccbd9ad5b16427590b988d480 -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Fix APQN validation routine - - When a zkey generate or change command is used to associate one - or multiple APQNs the command succeeds, but no key is generated - and no APQNs are associated, because the return code returned by - _keystore_apqn_check() is wrong. - - Signed-off-by: Ingo Franzki - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 3 +++ - 1 file changed, 3 insertions(+) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -986,6 +986,7 @@ static int _keystore_apqn_check(const ch - } - - if (sscanf(apqn, "%x.%x", &card, &domain) != 2) { -+ warnx("the APQN '%s' is not valid", apqn); - rc = -EINVAL; - goto out; - } -@@ -1003,6 +1004,8 @@ static int _keystore_apqn_check(const ch - rc == -1 ? "not a CCA card" : "not online"); - rc = -EIO; - goto out; -+ } else { -+ rc = 0; - } - - out: diff --git a/s390-tools-sles15sp1-0014-zkey-Fix-generate-and-import-leaving-key-in-an-incon.patch b/s390-tools-sles15sp1-0014-zkey-Fix-generate-and-import-leaving-key-in-an-incon.patch deleted file mode 100644 index 7698aa4..0000000 --- a/s390-tools-sles15sp1-0014-zkey-Fix-generate-and-import-leaving-key-in-an-incon.patch +++ /dev/null @@ -1,47 +0,0 @@ -Subject: zkey: Fix generate and import leaving key in an inconsistent state -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 672548ce30f61e94c8465a560a54a4a8fe568c06 -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Fix generate and import leaving key in an inconsistent state - - When a volume or APQN association is made while generating or - importing a key, and a duplicate association is detected, then - this may leave the key in an inconsistent state. - - Signed-off-by: Ingo Franzki - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -1534,7 +1534,7 @@ int keystore_generate_key(struct keystor - out_free_props: - if (key_props != NULL) - properties_free(key_props); -- if (rc != 0 && rc != -EEXIST) -+ if (rc != 0) - remove(file_names.skey_filename); - out_free_key_filenames: - _keystore_free_key_filenames(&file_names); -@@ -1617,7 +1617,7 @@ int keystore_import_key(struct keystore - out_free_props: - if (key_props != NULL) - properties_free(key_props); -- if (rc != 0 && rc != -EEXIST) -+ if (rc != 0) - remove(file_names.skey_filename); - out_free_key_filenames: - _keystore_free_key_filenames(&file_names); diff --git a/s390-tools-sles15sp1-0015-zkey-Add-zkey-cryptsetup-tool.patch b/s390-tools-sles15sp1-0015-zkey-Add-zkey-cryptsetup-tool.patch deleted file mode 100644 index c3a66bd..0000000 --- a/s390-tools-sles15sp1-0015-zkey-Add-zkey-cryptsetup-tool.patch +++ /dev/null @@ -1,2584 +0,0 @@ -Subject: zkey: Add zkey-cryptsetup tool -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 4eb80d14a0554c8a404f06beeb53522e45d5df6e -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Add zkey-cryptsetup tool - - The zkey-cryptsetup tool is used to validate and re-encipher - secure AES volume keys of volumes encrypted with LUKS2 and - the paes cipher. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/Makefile | 12 - zkey/pkey.c | 158 +++ - zkey/pkey.h | 7 - zkey/zkey-cryptsetup.c | 2270 +++++++++++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 2444 insertions(+), 3 deletions(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -18,9 +18,8 @@ check_dep: - "HAVE_OPENSSL=0") - - CPPFLAGS += -I../include --LDLIBS += -ldl -lcrypto - --all: check_dep zkey -+all: check_dep zkey zkey-cryptsetup - - libs = $(rootdir)/libutil/libutil.a - -@@ -28,12 +27,19 @@ zkey.o: zkey.c pkey.h misc.h - pkey.o: pkey.c pkey.h - properties.o: properties.c properties.h - keystore.o: keystore.c keystore.h properties.h -+zkey-cryptsetup.o: zkey-cryptsetup.c pkey.h misc.h - -+zkey: LDLIBS = -ldl -lcrypto - zkey: zkey.o pkey.o properties.o keystore.o $(libs) - -+zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c -+zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs) -+ -+ - install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR) -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey -@@ -42,6 +48,6 @@ install: all - endif - - clean: -- rm -f *.o zkey -+ rm -f *.o zkey zkey-cryptsetup - - .PHONY: all install clean ---- a/zkey/pkey.c -+++ b/zkey/pkey.c -@@ -11,11 +11,13 @@ - #include - #include - #include -+#include - #include - #include - #include - #include - #include -+#include - #include - #include - -@@ -25,6 +27,12 @@ - - #include "pkey.h" - -+#ifndef AF_ALG -+#define AF_ALG 38 -+#endif -+#ifndef SOL_ALG -+#define SOL_ALG 279 -+#endif - - #define pr_verbose(verbose, fmt...) do { \ - if (verbose) \ -@@ -34,6 +42,8 @@ - #define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? 2 * (keysize) : (keysize)) - #define HALF_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? (keysize) / 2 : (keysize)) - -+#define MAX_CIPHER_LEN 32 -+ - /* - * Definitions for the CCA library - */ -@@ -367,6 +377,8 @@ int generate_secure_key_random(int pkey_ - 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; - } - -@@ -378,6 +390,8 @@ int generate_secure_key_random(int pkey_ - 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; - } - -@@ -465,6 +479,8 @@ int generate_secure_key_clear(int pkey_f - 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"); - goto out; - } - -@@ -479,6 +495,8 @@ int generate_secure_key_clear(int pkey_f - 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"); - goto out; - } - -@@ -746,3 +764,143 @@ int validate_secure_key(int pkey_fd, - - return 0; - } -+ -+/** -+ * Generate a key verification pattern of a secure key by encrypting the all -+ * zero message with the secure key using the AF_ALG interface -+ * -+ * @param[in] key the secure key token -+ * @param[in] key_size the size of the secure key -+ * @param[in] vp buffer where the verification pattern is returned -+ * @param[in] vp_len the size of the buffer -+ * @param[in] verbose if true, verbose messages are printed -+ * -+ * @returns 0 on success, a negative errno in case of an error -+ */ -+int generate_key_verification_pattern(const char *key, size_t key_size, -+ char *vp, size_t vp_len, bool verbose) -+{ -+ int tfmfd = -1, opfd = -1, rc = 0; -+ char null_msg[ENC_ZERO_LEN]; -+ char enc_zero[ENC_ZERO_LEN]; -+ struct af_alg_iv *alg_iv; -+ struct cmsghdr *header; -+ uint32_t *type; -+ ssize_t len; -+ size_t i; -+ -+ struct sockaddr_alg sa = { -+ .salg_family = AF_ALG, -+ .salg_type = "skcipher", -+ }; -+ struct iovec iov = { -+ .iov_base = (void *)null_msg, -+ .iov_len = sizeof(null_msg), -+ }; -+ int iv_msg_size = CMSG_SPACE(sizeof(*alg_iv) + PAES_BLOCK_SIZE); -+ char buffer[CMSG_SPACE(sizeof(*type)) + iv_msg_size]; -+ struct msghdr msg = { -+ .msg_control = buffer, -+ .msg_controllen = sizeof(buffer), -+ .msg_iov = &iov, -+ .msg_iovlen = 1, -+ }; -+ -+ if (vp_len < VERIFICATION_PATTERN_LEN) { -+ rc = -EMSGSIZE; -+ goto out; -+ } -+ -+ snprintf((char *)sa.salg_name, sizeof(sa.salg_name), "%s(paes)", -+ key_size > SECURE_KEY_SIZE ? "xts" : "cbc"); -+ -+ tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0); -+ if (tfmfd < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to open an AF_ALG socket"); -+ goto out; -+ } -+ -+ if (bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to bind the AF_ALG socket, " -+ "salg_name='%s' ", sa.salg_name); -+ goto out; -+ } -+ -+ if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key, -+ key_size) < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to set the key"); -+ goto out; -+ } -+ -+ opfd = accept(tfmfd, NULL, 0); -+ if (opfd < 0) { -+ rc = -errno; -+ pr_verbose(verbose, "Failed to accept on the AF_ALG socket"); -+ goto out; -+ } -+ -+ memset(null_msg, 0, sizeof(null_msg)); -+ memset(buffer, 0, sizeof(buffer)); -+ -+ header = CMSG_FIRSTHDR(&msg); -+ if (header == NULL) { -+ pr_verbose(verbose, "Failed to obtain control message header"); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ header->cmsg_level = SOL_ALG; -+ header->cmsg_type = ALG_SET_OP; -+ header->cmsg_len = CMSG_LEN(sizeof(*type)); -+ type = (void *)CMSG_DATA(header); -+ *type = ALG_OP_ENCRYPT; -+ -+ header = CMSG_NXTHDR(&msg, header); -+ if (header == NULL) { -+ pr_verbose(verbose, "Failed to obtain control message " -+ "header"); -+ rc = -EINVAL; -+ goto out; -+ } -+ header->cmsg_level = SOL_ALG; -+ header->cmsg_type = ALG_SET_IV; -+ header->cmsg_len = iv_msg_size; -+ alg_iv = (void *)CMSG_DATA(header); -+ alg_iv->ivlen = PAES_BLOCK_SIZE; -+ memcpy(alg_iv->iv, null_msg, PAES_BLOCK_SIZE); -+ -+ len = sendmsg(opfd, &msg, 0); -+ if (len != ENC_ZERO_LEN) { -+ pr_verbose(verbose, "Failed to send to the AF_ALG socket"); -+ rc = -errno; -+ goto out; -+ } -+ -+ len = read(opfd, enc_zero, sizeof(enc_zero)); -+ if (len != ENC_ZERO_LEN) { -+ pr_verbose(verbose, "Failed to receive from the AF_ALG socket"); -+ rc = -errno; -+ goto out; -+ } -+ -+ memset(vp, 0, vp_len); -+ for (i = 0; i < sizeof(enc_zero); i++) -+ sprintf(&vp[i * 2], "%02x", enc_zero[i]); -+ -+ pr_verbose(verbose, "Key verification pattern: %s", vp); -+ -+out: -+ if (opfd != -1) -+ close(opfd); -+ if (tfmfd != -1) -+ close(tfmfd); -+ -+ if (rc != 0) -+ pr_verbose(verbose, "Failed to generate the key verification " -+ "pattern: %s", strerror(-rc)); -+ -+ return rc; -+} ---- a/zkey/pkey.h -+++ b/zkey/pkey.h -@@ -93,6 +93,10 @@ typedef void (*t_CSNBKTC)(long *return_c - 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); -@@ -122,4 +126,7 @@ int key_token_change(t_CSNBKTC dll_CSNBK - 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); -+ - #endif ---- /dev/null -+++ b/zkey/zkey-cryptsetup.c -@@ -0,0 +1,2270 @@ -+/* -+ * zkey-cryptsetup - Re-encipher or validate volume keys of volumes -+ * encrypted with LUKS2 and the paes cipher. -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * s390-tools is free software; you can redistribute it and/or modify -+ * it under the terms of the MIT license. See LICENSE for details. -+ */ -+ -+#define _LARGEFILE64_SOURCE -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+#include "lib/util_base.h" -+#include "lib/util_libc.h" -+#include "lib/util_opt.h" -+#include "lib/util_panic.h" -+#include "lib/util_prg.h" -+#include "lib/zt_common.h" -+ -+#include "misc.h" -+#include "pkey.h" -+ -+#define MAX_KEY_SIZE (8 * 1024 * 1024) -+#define MAX_PASSWORD_SIZE 512 -+#define KEYFILE_BUFLEN 4096 -+#define SEEK_BUFLEN 4096 -+ -+#define PAES_VP_TOKEN_NAME "paes-verification-pattern" -+#define PAES_VP_TOKEN_VP "verification-pattern" -+ -+#define PAES_REENC_TOKEN_NAME "paes-reencipher" -+#define PAES_REENC_TOKEN_VP "verification-pattern" -+#define PAES_REENC_TOKEN_ORG_SLOT "original-keyslot" -+#define PAES_REENC_TOKEN_UNB_SLOT "unbound-keyslot" -+ -+struct reencipher_token { -+ char verification_pattern[VERIFICATION_PATTERN_LEN]; -+ unsigned int original_keyslot; -+ unsigned int unbound_keyslot; -+}; -+ -+struct vp_token { -+ char verification_pattern[VERIFICATION_PATTERN_LEN]; -+}; -+ -+__attribute__ ((unused)) -+static void misc_print_required_parms(const char *parm_name1, -+ const char *parm_name2); -+ -+/* -+ * Program configuration -+ */ -+const struct util_prg prg = { -+ .desc = "Manage secure volume keys of volumes encrypted with LUKS2 and " -+ "the 'paes' cipher", -+ .command_args = "COMMAND DEVICE", -+ .args = "", -+ .copyright_vec = { -+ { -+ .owner = "IBM Corp.", -+ .pub_first = 2018, -+ .pub_last = 2018, -+ }, -+ UTIL_PRG_COPYRIGHT_END -+ } -+}; -+ -+/* -+ * Global variables for program options -+ */ -+static struct zkey_cryptsetup_globals { -+ char *pos_arg; -+ char *keyfile; -+ long long keyfile_offset; -+ long long keyfile_size; -+ long long tries; -+ bool complete; -+ bool inplace; -+ bool staged; -+ char *master_key_file; -+ bool debug; -+ bool verbose; -+ void *lib_csulcca; -+ t_CSNBKTC dll_CSNBKTC; -+ int pkey_fd; -+ struct crypt_device *cd; -+} g = { -+ .tries = 3, -+ .pkey_fd = -1, -+}; -+ -+/* -+ * Available commands -+ */ -+#define COMMAND_REENCIPHER "reencipher" -+#define COMMAND_VALIDATE "validate" -+#define COMMAND_SETVP "setvp" -+#define COMMAND_SETKEY "setkey" -+ -+#define ZKEY_CRYPTSETUP_COMMAND_MAX_LEN 10 -+ -+/* -+ * These options are exactly the same as for the cryptsetup tool -+ */ -+#define OPT_PASSPHRASE_ENTRY(cmd) \ -+{ \ -+ .option = {"key-file", required_argument, NULL, 'd'}, \ -+ .argument = "FILE-NAME", \ -+ .desc = "Read the passphrase from the specified file", \ -+ .command = cmd, \ -+}, \ -+{ \ -+ .option = {"keyfile-offset", required_argument, NULL, 'o'}, \ -+ .argument = "BYTES", \ -+ .desc = "Specifies the number of bytes to skip in the file " \ -+ "specified with option '--key-file'|'-d'", \ -+ .command = cmd, \ -+}, \ -+{ \ -+ .option = {"keyfile-size", required_argument, NULL, 'l'}, \ -+ .argument = "BYTES", \ -+ .desc = "Specifies the number of bytes to read from the file " \ -+ "specified with option '--key-file'|'-d'", \ -+ .command = cmd, \ -+}, \ -+{ \ -+ .option = {"tries", required_argument, NULL, 'T'}, \ -+ .argument = "NUMBER", \ -+ .desc = "Specifies how often the interactive input of the " \ -+ "passphrase can be retried", \ -+ .command = cmd, \ -+} -+ -+/* -+ * Configuration of command line options -+ */ -+static struct util_opt opt_vec[] = { -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .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", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = {"in-place", 0, NULL, 'i'}, -+ .desc = "Forces an in-place re-enciphering of a secure volume " -+ "key in the LUKS2 header", -+ .command = COMMAND_REENCIPHER, -+ }, -+ { -+ .option = {"complete", 0, NULL, 'c'}, -+ .desc = "Completes a staged re-enciphering. Use this option " -+ "after the new CCA master key has been set (made " -+ "active)", -+ .command = COMMAND_REENCIPHER, -+ }, -+ OPT_PASSPHRASE_ENTRY(COMMAND_REENCIPHER), -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_VALIDATE, -+ }, -+ OPT_PASSPHRASE_ENTRY(COMMAND_VALIDATE), -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_SETVP, -+ }, -+ OPT_PASSPHRASE_ENTRY(COMMAND_SETVP), -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "OPTIONS", -+ .command = COMMAND_SETKEY, -+ }, -+ { -+ .option = {"master-key-file", required_argument, NULL, 'm'}, -+ .argument = "FILE-NAME", -+ .desc = "Specifies the name of a file containing the secure " -+ "AES key that is set as new volume key", -+ .command = COMMAND_SETKEY, -+ }, -+ OPT_PASSPHRASE_ENTRY(COMMAND_SETKEY), -+ /***********************************************************/ -+ { -+ .flags = UTIL_OPT_FLAG_SECTION, -+ .desc = "COMMON OPTIONS" -+ }, -+ { -+ .option = {"debug", 0, NULL, 'D'}, -+ .desc = "Print additional debugging messages during " -+ "processing", -+ }, -+ { -+ .option = {"verbose", 0, NULL, 'V'}, -+ .desc = "Print additional information messages during " -+ "processing", -+ }, -+ UTIL_OPT_HELP, -+ UTIL_OPT_VERSION, -+ UTIL_OPT_END -+}; -+ -+#define ZKEY_CRYPTSETUP_COMMAND_STR_LEN 80 -+ -+/* -+ * Table of supported commands -+ */ -+struct zkey_cryptsetup_command { -+ char *command; -+ unsigned int abbrev_len; -+ int (*function)(void); -+ int need_cca_library; -+ int need_pkey_device; -+ char *short_desc; -+ char *long_desc; -+ int has_options; -+ char *pos_arg; -+ int open_device; -+}; -+ -+static int command_reencipher(void); -+static int command_validate(void); -+static int command_setvp(void); -+static int command_setkey(void); -+ -+static struct zkey_cryptsetup_command zkey_cryptsetup_commands[] = { -+ { -+ .command = COMMAND_REENCIPHER, -+ .abbrev_len = 2, -+ .function = command_reencipher, -+ .need_cca_library = 1, -+ .need_pkey_device = 1, -+ .short_desc = "Re-encipher a secure volume key", -+ .long_desc = "Re-encipher a secure volume key of a volume " -+ "encrypted with LUKS2 and the 'paes' cipher", -+ .has_options = 1, -+ .pos_arg = "DEVICE", -+ .open_device = 1, -+ }, -+ { -+ .command = COMMAND_VALIDATE, -+ .abbrev_len = 3, -+ .function = command_validate, -+ .need_pkey_device = 1, -+ .short_desc = "Validate a secure volume key", -+ .long_desc = "Validate a secure volume key of a volume " -+ "encrypted with LUKS2 and the 'paes' cipher", -+ .has_options = 1, -+ .pos_arg = "DEVICE", -+ .open_device = 1, -+ }, -+ { -+ .command = COMMAND_SETVP, -+ .abbrev_len = 4, -+ .function = command_setvp, -+ .need_pkey_device = 1, -+ .short_desc = "Set a verification pattern of the secure volume " -+ "key", -+ .long_desc = "Set a verification pattern of the secure AES " -+ "volume key of a volume encrypted with LUKS2 and " -+ "the 'paes' cipher", -+ .has_options = 1, -+ .pos_arg = "DEVICE", -+ .open_device = 1, -+ }, -+ { -+ .command = COMMAND_SETKEY, -+ .abbrev_len = 4, -+ .function = command_setkey, -+ .need_pkey_device = 1, -+ .short_desc = "Set a new secure volume key", -+ .long_desc = "Set a new secure AES volume key for a volume " -+ "encrypted with LUKS2 and the 'paes' cipher", -+ .has_options = 1, -+ .pos_arg = "DEVICE", -+ .open_device = 1, -+ }, -+ { .command = NULL } -+}; -+ -+#define pr_verbose(fmt...) do { \ -+ if (g.verbose) \ -+ warnx(fmt); \ -+ } while (0) -+ -+static volatile int quit; -+ -+/* -+ * Signal handler for SIGINT and SIGTERM -+ */ -+static void int_handler(int sig __attribute__((__unused__))) -+{ -+ quit++; -+} -+ -+/* -+ * Install signal handler for SIGINT and SIGTERM -+ */ -+static void set_int_handler(void) -+{ -+ struct sigaction sigaction_open; -+ -+ pr_verbose("Installing SIGINT/SIGTERM handler"); -+ memset(&sigaction_open, 0, sizeof(struct sigaction)); -+ sigaction_open.sa_handler = int_handler; -+ sigaction(SIGINT, &sigaction_open, 0); -+ sigaction(SIGTERM, &sigaction_open, 0); -+} -+ -+static void print_usage_command(const struct zkey_cryptsetup_command *command) -+{ -+ char command_str[ZKEY_CRYPTSETUP_COMMAND_STR_LEN]; -+ unsigned int i; -+ -+ strncpy(command_str, command->command, sizeof(command_str) - 1); -+ for (i = 0; i < command->abbrev_len; i++) -+ command_str[i] = toupper(command_str[i]); -+ -+ printf("Usage: %s %s", -+ program_invocation_short_name, command_str); -+ if (command->pos_arg != NULL) -+ printf(" %s", command->pos_arg); -+ if (command->has_options) -+ printf(" [OPTIONS]"); -+ if (prg.args) -+ printf(" %s", prg.args); -+ printf("\n\n"); -+ util_print_indented(command->long_desc, 0); -+ -+ if (command->has_options) -+ printf("\n"); -+} -+ -+static void print_usage_command_list(void) -+{ -+ struct zkey_cryptsetup_command *cmd = zkey_cryptsetup_commands; -+ char command_str[ZKEY_CRYPTSETUP_COMMAND_STR_LEN]; -+ unsigned int i; -+ -+ util_prg_print_help(); -+ -+ printf("COMMANDS\n"); -+ while (cmd->command) { -+ strcpy(command_str, cmd->command); -+ for (i = 0; i < cmd->abbrev_len; i++) -+ command_str[i] = toupper(command_str[i]); -+ printf(" %-*s %s\n", ZKEY_CRYPTSETUP_COMMAND_MAX_LEN, -+ command_str, cmd->short_desc); -+ cmd++; -+ } -+ printf("\n"); -+} -+ -+/* -+ * --help printout -+ */ -+static void print_help(const struct zkey_cryptsetup_command *command) -+{ -+ /* Print usage */ -+ if (!command) -+ print_usage_command_list(); -+ else -+ print_usage_command(command); -+ -+ /* Print parameter help */ -+ util_opt_print_help(); -+ -+ if (!command) { -+ printf("\n"); -+ printf("For more information use '%s COMMAND --help'.\n", -+ program_invocation_short_name); -+ } -+} -+ -+/* -+ * Log function called from libcryptsetup routines when debugging is enabled -+ */ -+static void cryptsetup_log(int level, const char *msg, -+ void *usrptr __attribute__((unused))) -+{ -+ switch (level) { -+ case CRYPT_LOG_NORMAL: -+ fputs(msg, stdout); -+ break; -+ case CRYPT_LOG_VERBOSE: -+ if (g.verbose) -+ fputs(msg, stdout); -+ break; -+ case CRYPT_LOG_ERROR: -+ fprintf(stderr, "%s: %s", program_invocation_short_name, msg); -+ break; -+ case CRYPT_LOG_DEBUG: -+ fprintf(stderr, "%s: # %s", program_invocation_short_name, msg); -+ break; -+ default: -+ warnx("Internal error on logging class for msg: %s", msg); -+ break; -+ } -+} -+ -+static void secure_free(void *area, size_t size) -+{ -+ if (area == NULL) -+ return; -+ -+ memset(area, 0, size); -+ free(area); -+} -+ -+/* -+ * Seek a number of bytes in a file. -+ * -+ * A simple call to lseek(3) might not be possible for some inputs (e.g. -+ * reading from a pipe), so this function instead reads of up to 4K bytes -+ * at a time until the specified number of bytes. It returns -1 on read error -+ * or when it reaches EOF before the requested number of bytes have been -+ * discarded. -+ */ -+static int keyfile_seek(int fd, size_t bytes) -+{ -+ size_t next_read; -+ ssize_t bytes_r; -+ off64_t r; -+ char *tmp; -+ -+ r = lseek64(fd, bytes, SEEK_CUR); -+ if (r > 0) -+ return 0; -+ if (r < 0 && errno != ESPIPE) -+ return -1; -+ -+ tmp = util_malloc(SEEK_BUFLEN); -+ while (bytes > 0) { -+ next_read = bytes > SEEK_BUFLEN ? SEEK_BUFLEN : (size_t)bytes; -+ -+ bytes_r = read(fd, tmp, next_read); -+ if (bytes_r < 0) { -+ if (errno == EINTR) -+ continue; -+ secure_free(tmp, SEEK_BUFLEN); -+ return -1; -+ } -+ -+ if (bytes_r == 0) -+ break; -+ -+ bytes -= bytes_r; -+ } -+ -+ secure_free(tmp, SEEK_BUFLEN); -+ return bytes == 0 ? 0 : -1; -+} -+ -+/* -+ * Read data from fd into the specified buffer -+ */ -+static ssize_t keyfile_read(int fd, void *buf, size_t length) -+{ -+ size_t read_size = 0; -+ ssize_t r; -+ -+ if (fd < 0 || buf == NULL) -+ return -EINVAL; -+ -+ do { -+ r = read(fd, buf, length - read_size); -+ if (r == -1 && errno != EINTR) -+ return r; -+ if (r == 0) -+ return (ssize_t)read_size; -+ if (r > 0) { -+ read_size += (size_t)r; -+ buf = (char *)buf + r; -+ } -+ } while (read_size != length); -+ -+ return (ssize_t)length; -+} -+ -+/* -+ * Prompt for the password -+ */ -+static int get_password_interactive(const char *prompt, char **pwd, -+ size_t *pwd_size) -+{ -+ struct termios orig, tmp; -+ int infd, outfd, rc = 0; -+ char *pass; -+ int num; -+ -+ pass = calloc(MAX_PASSWORD_SIZE + 1, 1); -+ if (pass == NULL) { -+ warnx("Out of memory while reading passphrase"); -+ return -ENOMEM; -+ } -+ -+ infd = open("/dev/tty", O_RDWR); -+ if (infd == -1) { -+ infd = STDIN_FILENO; -+ outfd = STDERR_FILENO; -+ } else { -+ outfd = infd; -+ } -+ -+ if (prompt != NULL) { -+ if (write(outfd, prompt, strlen(prompt)) < 0) { -+ rc = -errno; -+ warnx("Failed to write prompt: %s", strerror(-rc)); -+ goto out_err; -+ } -+ } -+ -+ rc = tcgetattr(infd, &orig); -+ if (rc != 0) { -+ rc = -errno; -+ warnx("Failed to get terminal attributes: %s", strerror(-rc)); -+ goto out_err; -+ } -+ -+ memcpy(&tmp, &orig, sizeof(tmp)); -+ tmp.c_lflag &= ~ECHO; -+ -+ rc = tcsetattr(infd, TCSAFLUSH, &tmp); -+ if (rc != 0) { -+ rc = -errno; -+ warnx("Failed to set terminal attributes: %s", strerror(-rc)); -+ goto out_err; -+ } -+ -+ quit = 0; -+ num = read(infd, pass, MAX_PASSWORD_SIZE); -+ if (num > 0) -+ pass[num - 1] = '\0'; -+ else if (num == 0) -+ *pass = '\0'; -+ -+ if (quit) { -+ printf("\n"); -+ num = -1; -+ pr_verbose("Password entry aborted by user"); -+ } -+ -+ rc = tcsetattr(infd, TCSAFLUSH, &orig); -+ if (rc != 0) { -+ rc = -errno; -+ warnx("Failed to set terminal attributes: %s", strerror(-rc)); -+ goto out_err; -+ } -+ -+ if (num < 0) { -+ warnx("Failed to read the password"); -+ rc = -EIO; -+ goto out_err; -+ } -+ -+ *pwd = pass; -+ *pwd_size = strlen(pass); -+ rc = 0; -+ -+out_err: -+ if (rc != 0) -+ secure_free(pass, MAX_PASSWORD_SIZE + 1); -+ else -+ write(outfd, "\n", 1); -+ -+ if (infd != STDIN_FILENO) -+ close(infd); -+ -+ return rc; -+} -+ -+/* -+ * Read the password from the key file -+ */ -+static int get_password_file(char **pwd, size_t *pwd_size, const char *key_file, -+ size_t keyfile_offset, size_t key_size, -+ int stop_at_eol) -+{ -+ int unlimited_read = 0; -+ size_t file_read_size; -+ int regular_file = 0; -+ int char_to_read = 0; -+ int fd, rc, newline; -+ char *pass = NULL; -+ int char_read = 0; -+ size_t buflen, i; -+ struct stat sb; -+ -+ fd = key_file ? open(key_file, O_RDONLY) : STDIN_FILENO; -+ if (fd < 0) { -+ rc = -errno; -+ warnx("Failed to open key file '%s': %s", key_file, -+ strerror(-rc)); -+ return rc; -+ } -+ -+ if (isatty(fd)) { -+ warnx("Cannot read key file from a terminal"); -+ rc = -EINVAL; -+ goto out_err; -+ } -+ -+ if (key_size == 0) { -+ key_size = MAX_KEY_SIZE + 1; -+ unlimited_read = 1; -+ buflen = KEYFILE_BUFLEN; -+ } else -+ buflen = key_size; -+ -+ if (key_file) { -+ rc = stat(key_file, &sb); -+ if (rc != 0) { -+ warnx("Failed to stat key file '%s': %s", key_file, -+ strerror(-rc)); -+ goto out_err; -+ } -+ if (S_ISREG(sb.st_mode)) { -+ regular_file = 1; -+ file_read_size = sb.st_size; -+ -+ if (keyfile_offset > file_read_size) { -+ warnx("Cannot seek to requested key file " -+ "offset %lu", keyfile_offset); -+ goto out_err; -+ } -+ file_read_size -= keyfile_offset; -+ -+ if (file_read_size >= key_size) -+ buflen = key_size; -+ else if (file_read_size) -+ buflen = file_read_size; -+ } -+ } -+ -+ pass = calloc(buflen, 1); -+ if (pass == NULL) { -+ warnx("Out of memory while reading passphrase"); -+ rc = -ENOMEM; -+ goto out_err; -+ } -+ -+ if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) { -+ warnx("Cannot seek to requested key file offset %lu", -+ keyfile_offset); -+ goto out_err; -+ } -+ -+ for (i = 0, newline = 0; i < key_size; i += char_read) { -+ if (i == buflen) { -+ buflen += 4096; -+ pass = realloc(pass, buflen); -+ if (pass == NULL) { -+ warnx("Out of memory while reading passphrase"); -+ rc = -ENOMEM; -+ goto out_err; -+ } -+ } -+ -+ if (stop_at_eol) -+ char_to_read = 1; -+ else -+ char_to_read = key_size < buflen ? -+ key_size - i : buflen - i; -+ -+ char_read = keyfile_read(fd, &pass[i], char_to_read); -+ if (char_read < 0) { -+ warnx("Error reading passphrase"); -+ rc = -EPIPE; -+ goto out_err; -+ } -+ -+ if (char_read == 0) -+ break; -+ -+ if (stop_at_eol && pass[i] == '\n') { -+ newline = 1; -+ pass[i] = '\0'; -+ break; -+ } -+ } -+ -+ if (!i && !regular_file && !newline) { -+ warnx("Nothing read on input"); -+ rc = -EPIPE; -+ goto out_err; -+ } -+ -+ if (unlimited_read && i == key_size) { -+ warnx("Maximum key size exceeded"); -+ rc = -EINVAL; -+ goto out_err; -+ } -+ -+ if (!unlimited_read && i != key_size) { -+ warnx("Cannot read requested amount of data"); -+ rc = -EINVAL; -+ goto out_err; -+ } -+ -+ *pwd = pass; -+ *pwd_size = i; -+ rc = 0; -+ -+out_err: -+ if (fd != STDIN_FILENO) -+ close(fd); -+ if (rc != 0) -+ secure_free(pass, buflen); -+ -+ return rc; -+} -+ -+/* -+ * Check if the specfied file name denotes stdin -+ */ -+static bool is_stdin(const char *file_name) -+{ -+ if (file_name == NULL) -+ return true; -+ -+ return strcmp(file_name, "-") ? false : true; -+} -+ -+/* -+ * Prompt for the password or read the password from the keyfile. -+ */ -+static int get_password(const char *prompt, char **pwd, size_t *pwd_size, -+ const char *key_file, size_t keyfile_offset, -+ size_t keyfile_size) -+{ -+ int rc; -+ -+ if (is_stdin(key_file)) { -+ if (isatty(STDIN_FILENO)) { -+ if (keyfile_offset) { -+ warnx("Cannot use option --keyfile-offset with " -+ "terminal input"); -+ return -EINVAL; -+ } -+ if (keyfile_size) { -+ warnx("Cannot use option --keyfile-size with " -+ "terminal input"); -+ return -EINVAL; -+ } -+ -+ rc = get_password_interactive(prompt, pwd, pwd_size); -+ } else { -+ rc = get_password_file(pwd, pwd_size, NULL, -+ keyfile_offset, keyfile_size, -+ key_file == NULL); -+ } -+ } else { -+ rc = get_password_file(pwd, pwd_size, key_file, -+ keyfile_offset, keyfile_size, 0); -+ } -+ -+ return rc; -+} -+static int ensure_is_active_keylot(int keyslot) -+{ -+ crypt_keyslot_info info; -+ -+ info = crypt_keyslot_status(g.cd, keyslot); -+ if (info != CRYPT_SLOT_ACTIVE && info != CRYPT_SLOT_ACTIVE_LAST) { -+ warnx("Keyslot %d is not a valid key slot", keyslot); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int ensure_is_unbound_keylot(int keyslot) -+{ -+ crypt_keyslot_info info; -+ -+ info = crypt_keyslot_status(g.cd, keyslot); -+ if (info != CRYPT_SLOT_UNBOUND) { -+ warnx("Key slot %d is not an unbound key slot", keyslot); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Returns the token number of the token of the specified name if found, -+ * -1 otherwise. -+ */ -+static int find_token(struct crypt_device *cd, const char *name) -+{ -+ crypt_token_info info; -+ const char *type; -+ int i; -+ -+ for (i = 0; ; i++) { -+ info = crypt_token_status(cd, i, &type); -+ if (info == CRYPT_TOKEN_INVALID) -+ break; -+ if (info == CRYPT_TOKEN_INACTIVE) -+ continue; -+ -+ if (strcmp(type, name) != 0) -+ continue; -+ -+ pr_verbose("'%s' token found at slot %d", name, i); -+ return i; -+ } -+ -+ pr_verbose("'%s' token not found", name); -+ return -1; -+} -+ -+/* -+ * Validate the reencipher token -+ */ -+static int validate_reencipher_token(struct reencipher_token *tok) -+{ -+ int rc; -+ -+ rc = ensure_is_unbound_keylot(tok->unbound_keyslot); -+ if (rc != 0) -+ return rc; -+ -+ rc = ensure_is_active_keylot(tok->original_keyslot); -+ if (rc != 0) -+ return rc; -+ -+ pr_verbose("The re-encipher token has been validated"); -+ -+ return 0; -+} -+ -+static int get_token(struct crypt_device *cd, int token, json_object **obj) -+{ -+ const char *json; -+ int rc; -+ -+ if (obj == NULL) -+ return -EINVAL; -+ -+ rc = crypt_token_json_get(cd, token, &json); -+ if (rc < 0) { -+ warnx("Failed to get re-encipher token %d: %s", token, -+ strerror(-rc)); -+ return -rc; -+ } -+ -+ *obj = json_tokener_parse(json); -+ if (*obj == NULL) { -+ warnx("Failed to parse JSON"); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Reads the re-encipher token from the LUKS2 header -+ */ -+static int get_reencipher_token(struct crypt_device *cd, int token, -+ struct reencipher_token *info, bool validate) -+{ -+ json_object *jobj_org_keyslot = NULL; -+ json_object *jobj_unb_keyslot = NULL; -+ json_object *json_token = NULL; -+ json_object *jobj_vp = NULL; -+ const char *temp; -+ int rc; -+ -+ rc = get_token(cd, token, &json_token); -+ if (rc != 0) -+ return rc; -+ -+ if (!json_object_object_get_ex(json_token, PAES_REENC_TOKEN_VP, -+ &jobj_vp)) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_VP); -+ rc = -EINVAL; -+ goto out; -+ } -+ temp = json_object_get_string(jobj_vp); -+ if (temp == NULL) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_VP); -+ rc = -EINVAL; -+ goto out; -+ } -+ strncpy(info->verification_pattern, temp, -+ sizeof(info->verification_pattern)); -+ info->verification_pattern[ -+ sizeof(info->verification_pattern) - 1] = '\0'; -+ -+ if (!json_object_object_get_ex(json_token, PAES_REENC_TOKEN_ORG_SLOT, -+ &jobj_org_keyslot)) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_ORG_SLOT); -+ rc = -EINVAL; -+ goto out; -+ } -+ errno = 0; -+ info->original_keyslot = json_object_get_int64(jobj_org_keyslot); -+ if (errno != 0) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_ORG_SLOT); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ if (!json_object_object_get_ex(json_token, PAES_REENC_TOKEN_UNB_SLOT, -+ &jobj_unb_keyslot)) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_UNB_SLOT); -+ rc = -EINVAL; -+ goto out; -+ } -+ errno = 0; -+ info->unbound_keyslot = json_object_get_int64(jobj_unb_keyslot); -+ if (errno != 0) { -+ warnx("The re-encipher token is incomplete, '%s' is missing", -+ PAES_REENC_TOKEN_UNB_SLOT); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ pr_verbose("Re-encipher token: original-keyslot: %d, unbound-keyslot: " -+ "%d, verification-pattern: %s", info->original_keyslot, -+ info->unbound_keyslot, info->verification_pattern); -+ -+ rc = 0; -+ -+ if (validate) -+ rc = validate_reencipher_token(info); -+ -+out: -+ if (json_token != NULL) -+ json_object_put(json_token); -+ -+ return rc; -+} -+ -+/* -+ * Writes the re-encipher token to the LUKS2 header -+ */ -+static int put_reencipher_token(struct crypt_device *cd, int token, -+ struct reencipher_token *info) -+{ -+ json_object *jobj, *jobj_keyslots; -+ char temp[20]; -+ int rc; -+ -+ pr_verbose("Re-encipher token: original-keyslot: %d, unbound-keyslot: " -+ "%d, verification-pattern: %s", info->original_keyslot, -+ info->unbound_keyslot, info->verification_pattern); -+ -+ jobj = json_object_new_object(); -+ json_object_object_add(jobj, "type", -+ json_object_new_string(PAES_REENC_TOKEN_NAME)); -+ -+ jobj_keyslots = json_object_new_array(); -+ sprintf(temp, "%d", info->unbound_keyslot); -+ json_object_array_add(jobj_keyslots, json_object_new_string(temp)); -+ json_object_object_add(jobj, "keyslots", jobj_keyslots); -+ -+ json_object_object_add(jobj, PAES_REENC_TOKEN_VP, -+ json_object_new_string( -+ info->verification_pattern)); -+ json_object_object_add(jobj, PAES_REENC_TOKEN_ORG_SLOT, -+ json_object_new_int64(info->original_keyslot)); -+ json_object_object_add(jobj, PAES_REENC_TOKEN_UNB_SLOT, -+ json_object_new_int64(info->unbound_keyslot)); -+ -+ rc = crypt_token_json_set(cd, token >= 0 ? token : CRYPT_ANY_TOKEN, -+ json_object_to_json_string_ext(jobj, -+ JSON_C_TO_STRING_PLAIN)); -+ -+ if (rc < 0) -+ warnx("Failed to add the re-encipher token to device " -+ "'%s': %s", g.pos_arg, strerror(-rc)); -+ else -+ pr_verbose("Re-encipher token put to token slot %d", -+ rc); -+ -+ json_object_put(jobj); -+ -+ return rc; -+} -+ -+ -+/* -+ * Reads the verification pattern token from the LUKS2 header -+ */ -+static int get_vp_token(struct crypt_device *cd, int token, -+ struct vp_token *info) -+{ -+ json_object *json_token = NULL; -+ json_object *jobj_vp = NULL; -+ const char *temp; -+ int rc; -+ -+ rc = get_token(cd, token, &json_token); -+ if (rc != 0) -+ return rc; -+ -+ if (!json_object_object_get_ex(json_token, PAES_VP_TOKEN_VP, -+ &jobj_vp)) { -+ warnx("The verification-pattern token is incomplete, '%s' is " -+ "missing", PAES_VP_TOKEN_VP); -+ rc = -EINVAL; -+ goto out; -+ } -+ temp = json_object_get_string(jobj_vp); -+ if (temp == NULL) { -+ warnx("The verification-pattern token is incomplete, '%s' is " -+ "missing", PAES_VP_TOKEN_VP); -+ rc = -EINVAL; -+ goto out; -+ } -+ strncpy(info->verification_pattern, temp, -+ sizeof(info->verification_pattern)); -+ info->verification_pattern[ -+ sizeof(info->verification_pattern) - 1] = '\0'; -+ -+ pr_verbose("Verification-pattern: %s", info->verification_pattern); -+ -+out: -+ if (json_token != NULL) -+ json_object_put(json_token); -+ -+ return rc; -+} -+ -+/* -+ * Writes the verification pattern token to the LUKS2 header -+ */ -+static int put_vp_token(struct crypt_device *cd, int token, -+ struct vp_token *info) -+{ -+ json_object *jobj, *jobj_keyslots; -+ int rc; -+ -+ pr_verbose("Verification-pattern: %s", info->verification_pattern); -+ -+ jobj = json_object_new_object(); -+ json_object_object_add(jobj, "type", -+ json_object_new_string(PAES_VP_TOKEN_NAME)); -+ -+ jobj_keyslots = json_object_new_array(); -+ json_object_object_add(jobj, "keyslots", jobj_keyslots); -+ -+ json_object_object_add(jobj, PAES_VP_TOKEN_VP, -+ json_object_new_string( -+ info->verification_pattern)); -+ -+ rc = crypt_token_json_set(cd, token >= 0 ? token : CRYPT_ANY_TOKEN, -+ json_object_to_json_string_ext(jobj, -+ JSON_C_TO_STRING_PLAIN)); -+ -+ if (rc < 0) -+ warnx("Failed to add the verification-pattern token to device " -+ "'%s': %s", g.pos_arg, strerror(-rc)); -+ else -+ pr_verbose("Verification-pattern token put to token slot %d", -+ rc); -+ -+ json_object_put(jobj); -+ -+ return rc; -+} -+ -+/* -+ * Open the LUKS2 device -+ */ -+static int open_device(const char *device, struct crypt_device **cd) -+{ -+ const struct crypt_pbkdf_type *pbkdf; -+ struct crypt_device *cdev = NULL; -+ int rc; -+ -+ rc = crypt_init(&cdev, device); -+ if (rc != 0) { -+ warnx("Failed to open device '%s': %s", device, strerror(-rc)); -+ goto out; -+ } -+ -+ crypt_set_log_callback(cdev, cryptsetup_log, NULL); -+ -+ rc = crypt_load(cdev, CRYPT_LUKS, NULL); -+ if (rc != 0) { -+ warnx("Failed to load the header from device '%s': %s", device, -+ strerror(-rc)); -+ goto out; -+ } -+ -+ if (strcmp(crypt_get_type(cdev), CRYPT_LUKS2) != 0) { -+ warnx("Device '%s' is not a LUKS2 device", device); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ if (strcmp(crypt_get_cipher(cdev), "paes") != 0) { -+ warnx("Device '%s' is not encrypted using the 'paes' cipher", -+ device); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ pbkdf = crypt_get_pbkdf_type(cdev); -+ rc = crypt_set_pbkdf_type(cdev, pbkdf); -+ if (rc != 0) { -+ warnx("Failed to set the PBKDF-type for device '%s': %s", -+ device, strerror(-rc)); -+ goto out; -+ } -+ -+ *cd = cdev; -+ -+out: -+ if (rc != 0) { -+ if (cdev != NULL) -+ crypt_free(cdev); -+ *cd = NULL; -+ } -+ -+ return rc; -+} -+ -+/* -+ * Prompts for yes or no. Returns true if 'y' or 'yes' was entered. -+ */ -+static bool prompt_for_yes(void) -+{ -+ 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("Prompt reply: '%s'", str); -+ if (strcasecmp(str, "y") == 0 || strcasecmp(str, "yes") == 0) -+ return true; -+ -+ return false; -+} -+ -+/* -+ * Cleans up a left over re-encipher token and associated unbound keyslot -+ */ -+static int cleanup_reencipher_token(int token) -+{ -+ struct reencipher_token tok; -+ int rc; -+ -+ rc = get_reencipher_token(g.cd, token, &tok, false); -+ if (rc == 0) { -+ if (ensure_is_unbound_keylot(tok.unbound_keyslot) == 0) { -+ rc = crypt_keyslot_destroy(g.cd, tok.unbound_keyslot); -+ if (rc != 0) -+ pr_verbose("Failed to destroy unbound key slot " -+ "%d: %s", tok.unbound_keyslot, -+ strerror(-rc)); -+ else -+ pr_verbose("Successfully destroyed unbound key " -+ "slot %d", tok.unbound_keyslot); -+ } else { -+ pr_verbose("Key slot %d is not in unbound state, it is " -+ "not destroyed", tok.unbound_keyslot); -+ } -+ } else { -+ pr_verbose("Failed to get re-encipher token (ignored): %s", -+ strerror(-rc)); -+ } -+ -+ rc = crypt_token_json_set(g.cd, token, NULL); -+ if (rc < 0) -+ warnx("Failed to remove the re-encipher token: %s", -+ strerror(-rc)); -+ else -+ pr_verbose("Successfully removed re-encipher token %d", token); -+ -+ return rc; -+} -+ -+/* -+ * Activates an unbound key slot and removes the previous key slots -+ */ -+static int activate_unbound_keyslot(int token, int keyslot, const char *key, -+ size_t keysize, char *password, -+ size_t password_len, char *complete_msg) -+{ -+ crypt_keyslot_info info; -+ int rc, i, n; -+ -+ rc = crypt_keyslot_add_by_key(g.cd, keyslot, key, keysize, password, -+ password_len, CRYPT_VOLUME_KEY_SET); -+ if (rc < 0) { -+ warnx("Failed to activate the unbound key slot %d: %s", keyslot, -+ strerror(-rc)); -+ return rc; -+ } -+ -+ pr_verbose("Unbound key slot %d activated, it is now key slot %d", -+ keyslot, rc); -+ keyslot = rc; -+ -+ if (token >= 0) { -+ rc = crypt_token_json_set(g.cd, token, NULL); -+ if (rc < 0) { -+ warnx("Failed remove the re-encipher token %d: %s", -+ token, strerror(-rc)); -+ return rc; -+ } -+ } -+ -+ if (complete_msg != NULL) -+ util_print_indented(complete_msg, 0); -+ util_print_indented("All key slots containing the old volume key are " -+ "now in unbound state. Do you want to remove " -+ "these key slots?", 0); -+ -+ if (!prompt_for_yes()) -+ return 0; -+ -+ for (i = 0, n = 0; ; i++) { -+ if (i == keyslot) -+ continue; -+ -+ info = crypt_keyslot_status(g.cd, i); -+ if (info == CRYPT_SLOT_INVALID) -+ break; -+ if (info <= CRYPT_SLOT_ACTIVE_LAST) -+ continue; -+ -+ pr_verbose("Removing now unbound key slot %d", i); -+ rc = crypt_keyslot_destroy(g.cd, i); -+ if (rc < 0) { -+ warnx("Failed to remove previous key slot %d: %s", i, -+ strerror(-rc)); -+ } -+ -+ n++; -+ } -+ -+ if (n > 1) { -+ util_print_indented("\nWARNING: Before re-enciphering, the " -+ "volume's LUKS header had multiple active " -+ "key slots with the same key, but different " -+ "passwords. Use 'cryptsetup luksAddKey' if " -+ "you need more than one key slot.", 0); -+ } -+ -+ return rc; -+} -+ -+static int check_keysize_and_cipher_mode(size_t keysize) -+{ -+ if (keysize == 0) { -+ warnx("Invalid volume key size"); -+ return -EINVAL; -+ } -+ -+ if (strncmp(crypt_get_cipher_mode(g.cd), "xts", 3) == 0) { -+ if (keysize != 2 * SECURE_KEY_SIZE) { -+ 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) { -+ warnx("The volume key size %lu is not valid for the " -+ "cipher mode '%s'", keysize, -+ crypt_get_cipher_mode(g.cd)); -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+/* -+ * Open a keyslot and get a secure key from a key slot. Optionally returns the -+ * key and password used to unlock the keyslot. You can either open a specific -+ * key slot, or let it choose based on the password (keyslot=CRYPT_ANY_SLOT). -+ */ -+static int open_keyslot(int keyslot, char **key, size_t *keysize, -+ char **password, size_t *password_len, -+ const char *prompt) -+{ -+ char *vkey = NULL; -+ char *pw = NULL; -+ long long tries; -+ size_t vkeysize; -+ size_t pw_len; -+ int rc; -+ -+ vkeysize = crypt_get_volume_key_size(g.cd); -+ pr_verbose("Volume key size: %lu", vkeysize); -+ -+ rc = check_keysize_and_cipher_mode(vkeysize); -+ if (rc != 0) -+ return rc; -+ -+ vkey = malloc(vkeysize); -+ if (vkey == NULL) { -+ warnx("Out of memory while allocating a buffer for the volume " -+ "key"); -+ return -ENOMEM; -+ } -+ -+ tries = (is_stdin(g.keyfile) && isatty(STDIN_FILENO)) ? g.tries : 1; -+ do { -+ if (pw != NULL) { -+ secure_free(pw, pw_len); -+ pw = NULL; -+ } -+ -+ rc = get_password(prompt, &pw, &pw_len, g.keyfile, -+ g.keyfile_offset, g.keyfile_size); -+ if (rc != 0) -+ goto out; -+ -+ rc = crypt_volume_key_get(g.cd, keyslot, vkey, &vkeysize, -+ pw, pw_len); -+ -+ if (rc == -EPERM || rc == -ENOENT) -+ warnx("No key available with this passphrase"); -+ -+ -+ } while ((rc == -EPERM || rc == -ENOENT) && (--tries > 0)); -+ -+ if (rc < 0) { -+ warnx("Failed to get volume key of device '%s': " -+ "%s", g.pos_arg, strerror(-rc)); -+ goto out; -+ } -+ -+ keyslot = rc; -+ pr_verbose("Volume key obtained from key slot %d", keyslot); -+ -+ if (key != NULL) -+ *key = vkey; -+ else -+ secure_free(vkey, vkeysize); -+ vkey = NULL; -+ if (keysize != NULL) -+ *keysize = vkeysize; -+ if (password != NULL) -+ *password = pw; -+ else -+ secure_free(pw, pw_len); -+ pw = NULL; -+ if (password_len != NULL) -+ *password_len = pw_len; -+ -+ rc = keyslot; -+ -+out: -+ secure_free(vkey, vkeysize); -+ secure_free(pw, pw_len); -+ -+ return rc; -+} -+ -+ -+/* -+ * Validate and get a secure key from a key slot. Optionally returns the key -+ * and password used to unlock the keyslot. You can either validate a specific -+ * key slot, or let it choose based on the password (keyslot=CRYPT_ANY_SLOT). -+ */ -+static int validate_keyslot(int keyslot, char **key, size_t *keysize, -+ char **password, size_t *password_len, -+ int *is_old_mk, size_t *clear_keysize, -+ const char *prompt, const char *invalid_msg) -+{ -+ size_t vkeysize = 0; -+ char *vkey = NULL; -+ int rc, is_old; -+ -+ rc = open_keyslot(keyslot, &vkey, &vkeysize, password, password_len, -+ prompt); -+ if (rc < 0) -+ return rc; -+ -+ keyslot = rc; -+ -+ rc = validate_secure_key(g.pkey_fd, (u8 *)vkey, vkeysize, clear_keysize, -+ &is_old, g.verbose); -+ if (rc != 0) { -+ if (invalid_msg != NULL) -+ warnx("%s", invalid_msg); -+ else -+ warnx("The secure volume key of device '%s' is not " -+ "valid", g.pos_arg); -+ rc = -EINVAL; -+ goto out; -+ } -+ pr_verbose("Volume key is currently enciphered with %s master key", -+ is_old ? "OLD" : "CURRENT"); -+ -+ if (key != NULL) -+ *key = vkey; -+ else -+ secure_free(vkey, vkeysize); -+ vkey = NULL; -+ if (keysize != NULL) -+ *keysize = vkeysize; -+ if (is_old_mk != NULL) -+ *is_old_mk = is_old; -+ -+ rc = keyslot; -+ -+out: -+ secure_free(vkey, vkeysize); -+ -+ return rc; -+} -+ -+/* -+ * Prepares for a re-enciphering of a secure volume key. Dependent on the -+ * options specified by the user and the state of the volume key, it starts -+ * a staged re-enciphering or performs an in-place re-enciphering. -+ */ -+static int reencipher_prepare(int token) -+{ -+ struct reencipher_token reenc_tok; -+ struct vp_token vp_tok; -+ char *password = NULL; -+ size_t password_len; -+ char *key = NULL; -+ size_t keysize; -+ int is_old_mk; -+ char *prompt; -+ char *msg; -+ int rc; -+ -+ if (token >= 0) { -+ util_asprintf(&msg, "Staged volume key re-enciphering is " -+ "already initiated for device '%s'. Do you want to " -+ "cancel the pending re-enciphering and start a " -+ "new re-enciphering process?", g.pos_arg); -+ util_print_indented(msg, 0); -+ free(msg); -+ -+ if (!prompt_for_yes()) { -+ warnx("Device '%s' is left unchanged", g.pos_arg); -+ return -ECANCELED; -+ } -+ -+ rc = cleanup_reencipher_token(token); -+ if (rc < 0) -+ return rc; -+ } -+ -+ util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg); -+ rc = validate_keyslot(CRYPT_ANY_SLOT, &key, &keysize, &password, -+ &password_len, &is_old_mk, NULL, prompt, NULL); -+ free(prompt); -+ if (rc < 0) -+ goto out; -+ -+ reenc_tok.original_keyslot = rc; -+ -+ rc = ensure_is_active_keylot(reenc_tok.original_keyslot); -+ if (rc != 0) -+ goto out; -+ -+ rc = generate_key_verification_pattern(key, keysize, -+ reenc_tok.verification_pattern, -+ sizeof(reenc_tok.verification_pattern), -+ g.verbose); -+ if (rc != 0) { -+ warnx("Failed to generate the verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ goto out; -+ } -+ -+ memcpy(vp_tok.verification_pattern, reenc_tok.verification_pattern, -+ sizeof(vp_tok.verification_pattern)); -+ token = find_token(g.cd, PAES_VP_TOKEN_NAME); -+ rc = put_vp_token(g.cd, token, &vp_tok); -+ 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); -+ -+ rc = key_token_change(g.dll_CSNBKTC, (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); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = crypt_keyslot_add_by_key(g.cd, CRYPT_ANY_SLOT, key, keysize, -+ password, password_len, -+ CRYPT_VOLUME_KEY_NO_SEGMENT); -+ if (rc < 0) { -+ warnx("Failed to add an unbound key slot to device '%s': %s", -+ g.pos_arg, strerror(-rc)); -+ goto out; -+ } -+ -+ reenc_tok.unbound_keyslot = rc; -+ pr_verbose("Re-enciphered volume key added to unbound key slot %d", -+ reenc_tok.unbound_keyslot); -+ -+ rc = ensure_is_unbound_keylot(reenc_tok.unbound_keyslot); -+ if (rc != 0) -+ goto out; -+ -+ if ((!is_old_mk && g.inplace) || -+ (is_old_mk && !g.staged)) { -+ if (!g.inplace) -+ printf("An in-place re-enciphering is performed.\n"); -+ -+ util_asprintf(&msg, "Re-enciphering has completed " -+ "successfully for device '%s'", g.pos_arg); -+ rc = activate_unbound_keyslot(-1, reenc_tok.unbound_keyslot, -+ key, keysize, password, -+ password_len, msg); -+ free(msg); -+ goto out; -+ } -+ -+ rc = put_reencipher_token(g.cd, CRYPT_ANY_TOKEN, &reenc_tok); -+ if (rc < 0) -+ goto out; -+ rc = 0; -+ -+ util_asprintf(&msg, "Staged re-enciphering is initiated for " -+ "device '%s'. After the NEW CCA master key has been set " -+ "to become the CURRENT master key, run 'zkey-cryptsetup " -+ "reencipher' with option '--complete' to complete the " -+ "re-enciphering process.", g.pos_arg, -+ program_invocation_short_name); -+ util_print_indented(msg, 0); -+ free(msg); -+ -+out: -+ secure_free(password, password_len); -+ secure_free(key, keysize); -+ -+ return rc; -+} -+ -+/* -+ * Completes a staged re-enciphering. -+ */ -+static int reencipher_complete(int token) -+{ -+ char vp[VERIFICATION_PATTERN_LEN]; -+ struct reencipher_token tok; -+ char *password = NULL; -+ size_t password_len; -+ char *key = NULL; -+ size_t keysize; -+ int is_old_mk; -+ char *prompt; -+ char *msg; -+ int rc; -+ -+ rc = get_reencipher_token(g.cd, token, &tok, true); -+ if (rc != 0) { -+ warnx("Failed to get the re-encipher token from device '%s': " -+ "%s", g.pos_arg, strerror(-rc)); -+ return rc; -+ } -+ -+ util_asprintf(&msg, "The re-enciphered secure volume key for " -+ "device '%s' is not valid.\nThe new CCA master key might " -+ "yet have to be set as the CURRENT master key.", -+ g.pos_arg); -+ util_asprintf(&prompt, "Enter passphrase for key slot %d of '%s': ", -+ tok.original_keyslot, g.pos_arg); -+ rc = validate_keyslot(tok.unbound_keyslot, &key, &keysize, &password, -+ &password_len, &is_old_mk, NULL, prompt, msg); -+ free(msg); -+ free(prompt); -+ if (rc < 0) -+ goto out; -+ -+ rc = ensure_is_unbound_keylot(rc); -+ if (rc != 0) -+ goto out; -+ -+ if (is_old_mk) { -+ util_asprintf(&msg, "The re-enciphered secure volume key " -+ "of device '%s' is enciphered with the CCA " -+ "master key from the OLD master key register. " -+ "The CCA master key might have changed again, " -+ "before the previous volume key re-enciphering " -+ "was completed.\n" -+ "Do you want to re-encipher the secure key with " -+ "the CCA master key in the CURRENT master key " -+ "register?", g.pos_arg); -+ util_print_indented(msg, 0); -+ free(msg); -+ -+ if (!prompt_for_yes()) { -+ warnx("Re-enciphering was aborted"); -+ rc = -ECANCELED; -+ goto out; -+ } -+ -+ rc = key_token_change(g.dll_CSNBKTC, (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); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = crypt_keyslot_destroy(g.cd, tok.unbound_keyslot); -+ if (rc < 0) { -+ warnx("Failed to remove unbound key slot %d: %s", -+ tok.unbound_keyslot, strerror(-rc)); -+ } -+ -+ rc = crypt_keyslot_add_by_key(g.cd, CRYPT_ANY_SLOT, key, -+ keysize, password, password_len, -+ CRYPT_VOLUME_KEY_NO_SEGMENT); -+ if (rc < 0) { -+ warnx("Failed to add an unbound key slot to device " -+ "'%s': %s", g.pos_arg, strerror(-rc)); -+ goto out; -+ } -+ -+ tok.unbound_keyslot = rc; -+ pr_verbose("Re-enciphered volume key added to unbound key " -+ "slot %d", tok.unbound_keyslot); -+ -+ } -+ -+ rc = generate_key_verification_pattern(key, keysize, vp, sizeof(vp), -+ g.verbose); -+ if (rc != 0) { -+ warnx("Failed to generate the verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ goto out; -+ } -+ -+ if (strcmp(tok.verification_pattern, vp) != 0) { -+ warnx("The verification patterns of the new and old volume " -+ "keys do not match"); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ util_asprintf(&msg, "Re-enciphering has completed successfully for " -+ "device '%s'.", g.pos_arg); -+ rc = activate_unbound_keyslot(token, tok.unbound_keyslot, key, keysize, -+ password, password_len, msg); -+ free(msg); -+ -+out: -+ secure_free(password, password_len); -+ secure_free(key, keysize); -+ -+ return rc; -+} -+ -+ -+/* -+ * Command handler for 'reencipher'. -+ * -+ * Re-encipher a volume key of a volume encrypted with LUKS2 and the -+ * 'paes' cipher -+ */ -+static int command_reencipher(void) -+{ -+ int token; -+ int rc; -+ -+ if (g.inplace && g.staged) { -+ warnx("Options '--in-place|-i' and '--staged|-s' are " -+ "mutual exclusive"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.complete) { -+ if (g.inplace) { -+ warnx("Option '--in-place|-i' is not valid together " -+ "with '--complete|-p'"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ if (g.staged) { -+ warnx("Option '--staged|-s' is not valid together " -+ "with '--complete|-p'"); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ } -+ -+ token = find_token(g.cd, PAES_REENC_TOKEN_NAME); -+ -+ if (token < 0 && g.complete) { -+ warnx("Staged volume key re-enciphering is not pending for " -+ "device '%s'", g.pos_arg); -+ return EXIT_FAILURE; -+ } -+ -+ if (token < 0 || g.staged || g.inplace) -+ rc = reencipher_prepare(token); -+ else -+ rc = reencipher_complete(token); -+ -+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+static void print_verification_pattern(const char *vp) -+{ -+ printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2, -+ vp); -+ printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2, -+ &vp[VERIFICATION_PATTERN_LEN / 2]); -+} -+ -+/* -+ * Command handler for 'validate'. -+ * -+ * Validate a volume key of a volume encrypted with LUKS2 and the -+ * 'paes' cipher -+ */ -+static int command_validate(void) -+{ -+ int reenc_pending = 0, vp_tok_avail = 0, is_valid = 0, is_old_mk = 0; -+ struct reencipher_token reenc_tok; -+ struct vp_token vp_tok; -+ size_t clear_keysize; -+ size_t keysize = 0; -+ char *key = NULL; -+ char *prompt; -+ char *msg; -+ int token; -+ int rc; -+ -+ util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg); -+ rc = open_keyslot(CRYPT_ANY_SLOT, &key, &keysize, NULL, NULL, prompt); -+ free(prompt); -+ if (rc < 0) -+ goto out; -+ -+ rc = ensure_is_active_keylot(rc); -+ if (rc != 0) -+ goto out; -+ -+ rc = validate_secure_key(g.pkey_fd, (u8 *)key, keysize, &clear_keysize, -+ &is_old_mk, g.verbose); -+ is_valid = (rc == 0); -+ -+ token = find_token(g.cd, PAES_REENC_TOKEN_NAME); -+ if (token >= 0) { -+ rc = get_reencipher_token(g.cd, token, &reenc_tok, true); -+ if (rc == 0) -+ reenc_pending = 1; -+ } -+ -+ token = find_token(g.cd, PAES_VP_TOKEN_NAME); -+ if (token >= 0) { -+ rc = get_vp_token(g.cd, token, &vp_tok); -+ if (rc == 0) -+ vp_tok_avail = 1; -+ } -+ -+ 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); -+ printf(" XTS type key: %s\n", -+ 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"); -+ } else { -+ printf(" Clear key size: (unknown)\n"); -+ printf(" Enciphered with: (unknown)\n"); -+ } -+ if (vp_tok_avail) -+ print_verification_pattern(vp_tok.verification_pattern); -+ else if (reenc_pending) -+ print_verification_pattern(reenc_tok.verification_pattern); -+ else -+ printf(" Verification pattern: Not available\n"); -+ -+ -+ if (reenc_pending) -+ printf(" Volume key re-enciphering is pending\n"); -+ -+ if (!is_valid) -+ printf("\nATTENTION: The secure volume key is not valid.\n"); -+ -+ if (is_old_mk) -+ util_print_indented("\nWARNING: The secure volume key is " -+ "currently enciphered with the OLD CCA " -+ "master key. To mitigate the danger of " -+ "data loss re-encipher the volume key with " -+ "the CURRENT CCA master key.", 0); -+ -+ if (is_valid && !vp_tok_avail) { -+ util_asprintf(&msg, "\nWARNING: The volume key cannot be " -+ "identified because the key verification pattern " -+ "token is not available in the LUKS2 header. Use " -+ "the '%s setvp' command to set the token.", -+ program_invocation_short_name); -+ util_print_indented(msg, 0); -+ free(msg); -+ } -+ -+ rc = is_valid ? 0 : -EINVAL; -+ -+out: -+ secure_free(key, keysize); -+ -+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'setvp'. -+ * -+ * Set the verification pattern token to allow identification of the key -+ */ -+static int command_setvp(void) -+{ -+ struct vp_token vp_tok; -+ size_t keysize = 0; -+ char *key = NULL; -+ char *prompt; -+ int token; -+ int rc; -+ -+ util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg); -+ rc = validate_keyslot(CRYPT_ANY_SLOT, &key, &keysize, NULL, NULL, -+ NULL, NULL, prompt, NULL); -+ free(prompt); -+ if (rc < 0) -+ goto out; -+ -+ rc = ensure_is_active_keylot(rc); -+ if (rc != 0) -+ goto out; -+ -+ token = find_token(g.cd, PAES_VP_TOKEN_NAME); -+ -+ rc = generate_key_verification_pattern(key, keysize, -+ vp_tok.verification_pattern, -+ sizeof(vp_tok.verification_pattern), -+ g.verbose); -+ if (rc != 0) { -+ warnx("Failed to generate the verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ goto out; -+ } -+ -+ rc = put_vp_token(g.cd, token, &vp_tok); -+ if (rc < 0) -+ goto out; -+ -+ rc = 0; -+ -+out: -+ secure_free(key, keysize); -+ -+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+/* -+ * Command handler for 'setkey'. -+ * -+ * Set a new volume key to allow to recover from an invalid volume key -+ */ -+static int command_setkey(void) -+{ -+ char vp[VERIFICATION_PATTERN_LEN]; -+ size_t password_len = 0; -+ struct vp_token vp_tok; -+ size_t newkey_size = 0; -+ char *password = NULL; -+ size_t keysize = 0; -+ u8 *newkey = NULL; -+ char *key = NULL; -+ int is_old_mk; -+ char *prompt; -+ int keyslot; -+ char *msg; -+ int token; -+ int rc; -+ -+ if (g.master_key_file == NULL) { -+ misc_print_required_parm("--master-key-file/-m"); -+ return EXIT_FAILURE; -+ } -+ -+ newkey = read_secure_key(g.master_key_file, &newkey_size, g.verbose); -+ if (newkey == NULL) -+ return EXIT_FAILURE; -+ -+ rc = check_keysize_and_cipher_mode(newkey_size); -+ if (rc != 0) -+ goto out; -+ -+ rc = validate_secure_key(g.pkey_fd, newkey, newkey_size, NULL, -+ &is_old_mk, g.verbose); -+ if (rc != 0) { -+ warnx("The secure key in file '%s' is not valid", -+ g.master_key_file); -+ goto out; -+ } -+ -+ if (is_old_mk) { -+ util_asprintf(&msg, "The secure key in file '%s' is " -+ "enciphered with the CCA master key in the OLD " -+ "master key register. Do you want to set this " -+ "key as the new volume key anyway?", -+ g.master_key_file); -+ util_print_indented(msg, 0); -+ free(msg); -+ -+ if (!prompt_for_yes()) { -+ rc = -EINVAL; -+ goto out; -+ } -+ } -+ -+ util_asprintf(&prompt, "Enter passphrase for '%s': ", g.pos_arg); -+ rc = open_keyslot(CRYPT_ANY_SLOT, &key, &keysize, &password, -+ &password_len, prompt); -+ free(prompt); -+ 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) { -+ warnx("The secure key in file '%s' is equal to the current " -+ "volume key, setkey is ignored", g.master_key_file); -+ rc = 0; -+ goto out; -+ } -+ -+ rc = generate_key_verification_pattern((char *)newkey, newkey_size, vp, -+ sizeof(vp), g.verbose); -+ if (rc != 0) { -+ warnx("Failed to generate the verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ goto out; -+ } -+ -+ token = find_token(g.cd, PAES_VP_TOKEN_NAME); -+ if (token >= 0) { -+ rc = get_vp_token(g.cd, token, &vp_tok); -+ if (rc < 0) { -+ warnx("Failed to get the verification pattern token: " -+ "%s", strerror(-rc)); -+ goto out; -+ } -+ -+ if (strcmp(vp_tok.verification_pattern, vp) != 0) { -+ warnx("The verification patterns of the new and old " -+ "volume keys do not match"); -+ rc = -EINVAL; -+ goto out; -+ } -+ } else { -+ util_asprintf(&msg, "ATTENTION: The key validation pattern " -+ "token is not available in the LUKS2 header. " -+ "Thus, the new volume key cannot be confirmed to " -+ "be correct. You will lose all data on the " -+ "volume if you set the wrong volume key!\n" -+ "Are you sure that the key in file '%s' is the " -+ "correct volume key for volume '%s'?", -+ g.master_key_file, g.pos_arg); -+ util_print_indented(msg, 0); -+ free(msg); -+ -+ if (!prompt_for_yes()) { -+ rc = -EINVAL; -+ goto out; -+ } -+ } -+ -+ rc = crypt_keyslot_add_by_key(g.cd, CRYPT_ANY_SLOT, (char *)newkey, -+ newkey_size, password, password_len, -+ CRYPT_VOLUME_KEY_NO_SEGMENT); -+ if (rc < 0) { -+ warnx("Failed to add an unbound key slot to device '%s': %s", -+ g.pos_arg, strerror(-rc)); -+ goto out; -+ } -+ keyslot = rc; -+ -+ rc = ensure_is_unbound_keylot(keyslot); -+ if (rc != 0) -+ goto out; -+ -+ pr_verbose("New volume key added to unbound key slot %d", keyslot); -+ -+ util_asprintf(&msg, "The volume key has been successfully set for " -+ "device '%s'", g.pos_arg); -+ rc = activate_unbound_keyslot(-1, keyslot, (char *)newkey, newkey_size, -+ password, password_len, msg); -+ free(msg); -+ if (rc < 0) -+ goto out; -+ -+ memcpy(vp_tok.verification_pattern, vp, -+ sizeof(vp_tok.verification_pattern)); -+ rc = put_vp_token(g.cd, token, &vp_tok); -+ if (rc < 0) -+ goto out; -+ -+ rc = 0; -+ -+out: -+ secure_free(password, password_len); -+ secure_free(newkey, newkey_size); -+ secure_free(key, keysize); -+ -+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -+} -+ -+ -+static bool is_command(struct zkey_cryptsetup_command *command, const char *str) -+{ -+ char command_str[ZKEY_CRYPTSETUP_COMMAND_STR_LEN]; -+ size_t str_len = strlen(str); -+ -+ util_assert(sizeof(command_str) > strlen(command->command), -+ "Buffer 'command_str' too small for %s", command->command); -+ if (str_len < command->abbrev_len) -+ return false; -+ if (str_len > strlen(command->command)) -+ return false; -+ strncpy(command_str, command->command, str_len); -+ if (strncasecmp(str, command_str, str_len) != 0) -+ return false; -+ -+ return true; -+} -+ -+/* -+ * Find the command in the command table -+ */ -+struct zkey_cryptsetup_command *find_command(const char *command) -+{ -+ struct zkey_cryptsetup_command *cmd = zkey_cryptsetup_commands; -+ -+ while (cmd->command) { -+ if (is_command(cmd, command)) -+ return cmd; -+ cmd++; -+ } -+ return NULL; -+} -+ -+/* -+ * Entry point -+ */ -+int main(int argc, char *argv[]) -+{ -+ struct zkey_cryptsetup_command *command = NULL; -+ int arg_count = argc; -+ char **args = argv; -+ char *endp; -+ int rc, c; -+ -+ util_prg_init(&prg); -+ util_opt_init(opt_vec, NULL); -+ -+ /* Get command if one is specified */ -+ if (argc >= 2 && strncmp(argv[1], "-", 1) != 0) { -+ command = find_command(argv[1]); -+ if (command == NULL) { -+ misc_print_invalid_command(argv[1]); -+ return EXIT_FAILURE; -+ } -+ -+ arg_count = argc - 1; -+ args = &argv[1]; -+ -+ if (argc >= 3 && strncmp(argv[2], "-", 1) != 0) { -+ g.pos_arg = argv[2]; -+ arg_count = argc - 2; -+ args = &argv[2]; -+ } -+ -+ } -+ -+ util_opt_set_command(command ? command->command : NULL); -+ util_prg_set_command(command ? command->command : NULL); -+ -+ while (1) { -+ c = util_opt_getopt_long(arg_count, args); -+ if (c == -1) -+ break; -+ switch (c) { -+ case 'c': -+ g.complete = 1; -+ break; -+ case 'i': -+ g.inplace = 1; -+ break; -+ case 's': -+ g.staged = 1; -+ break; -+ case 'd': -+ g.keyfile = optarg; -+ break; -+ case 'o': -+ g.keyfile_offset = strtoll(optarg, &endp, 0); -+ if (*optarg == '\0' || *endp != '\0' || -+ g.keyfile_offset < 0 || -+ (g.keyfile_offset == LLONG_MAX && -+ errno == ERANGE)) { -+ warnx("Invalid value for '--keyfile-offset'|" -+ "'-o': '%s'", optarg); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ break; -+ case 'l': -+ g.keyfile_size = strtoll(optarg, &endp, 0); -+ if (*optarg == '\0' || *endp != '\0' || -+ g.keyfile_size <= 0 || -+ (g.keyfile_size == LLONG_MAX && errno == ERANGE)) { -+ warnx("Invalid value for '--keyfile-size'|" -+ "'-l': '%s'", optarg); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ break; -+ case 'T': -+ g.tries = strtoll(optarg, &endp, 0); -+ if (*optarg == '\0' || *endp != '\0' || -+ g.tries <= 0 || -+ (g.tries == LLONG_MAX && errno == ERANGE)) { -+ warnx("Invalid value for '--tries'|'-T': '%s'", -+ optarg); -+ util_prg_print_parse_error(); -+ return EXIT_FAILURE; -+ } -+ break; -+ case 'm': -+ g.master_key_file = optarg; -+ break; -+ case 'D': -+ g.debug = true; -+ g.verbose = true; -+ break; -+ case 'V': -+ g.verbose = true; -+ break; -+ case 'h': -+ print_help(command); -+ return EXIT_SUCCESS; -+ case 'v': -+ util_prg_print_version(); -+ return EXIT_SUCCESS; -+ default: -+ util_opt_print_parse_error(c, args); -+ return EXIT_FAILURE; -+ } -+ } -+ -+ if (optind < arg_count) { -+ util_prg_print_arg_error(args[optind]); -+ return EXIT_FAILURE; -+ } -+ -+ if (command == NULL) { -+ misc_print_missing_command(); -+ return EXIT_FAILURE; -+ } -+ -+ if (command->need_cca_library) { -+ rc = load_cca_library(&g.lib_csulcca, &g.dll_CSNBKTC, -+ g.verbose); -+ if (rc != 0) { -+ rc = EXIT_FAILURE; -+ goto out; -+ } -+ } -+ if (command->need_pkey_device) { -+ g.pkey_fd = open_pkey_device(g.verbose); -+ if (g.pkey_fd == -1) { -+ rc = EXIT_FAILURE; -+ goto out; -+ } -+ } -+ -+ crypt_set_log_callback(NULL, cryptsetup_log, NULL); -+ if (g.debug) -+ crypt_set_debug_level(-1); -+ -+ if (command->open_device) { -+ if (g.pos_arg == NULL) { -+ misc_print_required_parm(command->pos_arg); -+ rc = EXIT_FAILURE; -+ goto out; -+ } -+ -+ rc = open_device(g.pos_arg, &g.cd); -+ if (rc != 0) { -+ g.cd = NULL; -+ rc = EXIT_FAILURE; -+ goto out; -+ } -+ } -+ -+ set_int_handler(); -+ -+ rc = command->function(); -+ -+out: -+ if (g.lib_csulcca) -+ dlclose(g.lib_csulcca); -+ if (g.pkey_fd >= 0) -+ close(g.pkey_fd); -+ if (g.cd) -+ crypt_free(g.cd); -+ return rc; -+} diff --git a/s390-tools-sles15sp1-0016-zkey-Add-man-page-for-zkey-cryptsetup.patch b/s390-tools-sles15sp1-0016-zkey-Add-man-page-for-zkey-cryptsetup.patch deleted file mode 100644 index 3a7f40f..0000000 --- a/s390-tools-sles15sp1-0016-zkey-Add-man-page-for-zkey-cryptsetup.patch +++ /dev/null @@ -1,443 +0,0 @@ -Subject: zkey: Add man page for zkey-cryptsetup -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 5e65df7375aec81d9348a57cdcbccb89a65422c3 -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Add man page for zkey-cryptsetup - - Add documentation for the new zkey-cryptsetup tool - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/Makefile | 1 - zkey/zkey-cryptsetup.1 | 403 +++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 404 insertions(+) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -42,6 +42,7 @@ install: all - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 -+ $(INSTALL) -m 644 -c zkey-cryptsetup.1 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey - $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository - ---- /dev/null -+++ b/zkey/zkey-cryptsetup.1 -@@ -0,0 +1,403 @@ -+.\" Copyright IBM Corp. 2018 -+.\" s390-tools is free software; you can redistribute it and/or modify -+.\" it under the terms of the MIT license. See LICENSE for details. -+.\" -+.TH ZKEY\-CRYPTSETUP 1 "May 2018" "s390-tools" -+.SH NAME -+zkey\-cryptsetup \- Manage secure AES volume keys of volumes encrypted with -+\fBLUKS2\fP and the \fBpaes\fP cipher -+. -+. -+.SH SYNOPSIS -+.B zkey\-cryptsetup -+.I command -+.I device -+.RI [ OPTIONS ] -+. -+.PP -+.B zkey\-cryptsetup -+.RI [ command ] -+.BR \-\-help | \-h -+.br -+.B zkey\-cryptsetup -+.BR \-\-version | \-v -+. -+. -+. -+.SH DESCRIPTION -+Use \fBzkey\-cryptsetup\fP to validate and re-encipher secure AES -+volume keys of volumes encrypted with \fBLUKS2\fP and the \fBpaes\fP cipher. -+These secure AES volume keys are enciphered with a master key of an IBM -+cryptographic adapter in CCA coprocessor mode. -+.PP -+To encrypt a volume using \fBLUKS2\fP and the \fBpaes\fP cipher, generate a -+secure AES key using \fBzkey\fP: \fB'zkey generate luks.key --xts'\fP. -+Then format the device with \fBcryptsetup\fP using the just generated secure -+AES key from file luks.key: \fB'cryptsetup luksFormat --type luks2 -+--cipher paes-xts-plain64 --master-key-file luks.key --key-size 1024'\fP. For -+more details about \fBzkey\fP or \fBcryptsetup\fP see the -+corresponding man pages. -+. -+. -+. -+.SH COMMANDS -+. -+. -+.SS "Validate secure AES volume keys" -+. -+.B zkey\-cryptsetup -+.BR validate | val -+.I device -+.RB [ \-\-key\-file | \-d -+.IR file-name ] -+.RB [ \-\-keyfile\-offset | \-o -+.IR bytes ] -+.RB [ \-\-keyfile\-size | \-l -+.IR bytes ] -+.RB [ \-\-tries | \-T -+.IR number ] -+.RB [ \-\-verbose | \-V ] -+.RB [ \-\-debug | \-D ] -+.PP -+Use the -+.B validate -+command to validate a secure AES volume key of a volume encrypted with -+\fBLUKS2\fP and the \fBpaes\fP cipher. -+It checks if the LUKS2 header of the volume contains a valid secure key. -+It also displays the attributes of the secure key, such as key size, whether -+it is a secure key that can be used for the XTS cipher mode, and the master key -+register (CURRENT or OLD) with which the secure key is enciphered. -+For further information about master key registers, see the -+\fBreencipher\fP command. -+.PP -+To open a key slot contained in the LUKS2 header of the volume, a passphrase is -+required. You are prompted for the passphrase, unless option -+.B \-\-key\-file -+is specified. Option -+.B \-\-tries -+specifies how often a passphrase can be re-entered. When option -+.B \-\-key\-file -+is specified, the passphrase is read from the specified file. You can specify -+options -+.B \-\-keyfile\-offset -+and -+.B \-\-keyfile\-size -+to control which part of the key file is used as passphrase. These options -+behave in the same way as with \fBcryptsetup\fP. -+. -+.SS "Re-encipher secure AES volume keys" -+. -+.PP -+.B zkey\-cryptsetup -+.BR reencipher | re -+.I device -+.RB [ \-\-staged | \-s ] -+.RB [ \-\-in\-place | \-i ] -+.RB [ \-\-complete | \-c ] -+.RB [ \-\-key\-file | \-d -+.IR file-name ] -+.RB [ \-\-keyfile\-offset | \-o -+.IR bytes ] -+.RB [ \-\-keyfile\-size | \-l -+.IR bytes ] -+.RB [ \-\-tries | \-T -+.IR number ] -+.RB [ \-\-verbose | \-V ] -+.RB [ \-\-debug | \-D ] -+.PP -+Use the -+.B reencipher -+command to re-encipher a secure AES volume key of a volume encrypted with -+\fBLUKS2\fP and the \fBpaes\fP cipher. A secure AES volume key must be -+re-enciphered when the master key of the cryptographic adapter in CCA -+coprocessor mode changes. -+.PP -+The cryptographic adapter in CCA coprocessor mode has three different registers -+to store master keys: -+.RS 2 -+.IP "\(bu" 2 -+The \fBCURRENT\fP register contains the current master key. -+. -+.IP "\(bu" 2 -+The \fBOLD\fP register contains the previously used master key. -+Secure keys enciphered with the master key contained in the \fBOLD\fP -+register can still be used until the master key is changed again. -+. -+.IP "\(bu" 2 -+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. -+.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. -+.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 -+\fBstaged\fP mode. -+.PP -+\fB"In-place"\fP immediately replaces the secure volume key in the LUKS2 -+header of the encrypted volume with the re-enciphered secure volume key. -+Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is performed in-place per -+default. You can use option \fB--in-place\fP to force an in-place -+re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that -+an encrypted volume with a secure volume key that was re-enciphered in-place -+from \fBCURRENT\fP to \fBNEW\fP is no longer usable, until the new CCA master -+key has been made the current one. -+.PP -+\fBStaged\fP mode means that the re-enciphered secure volume key is stored in a -+separate (unbound) key slot in the LUKS2 header of the encrypted volume. Thus -+all key slots containing the current secure volume key are still valid at this -+point. Once the new CCA master key has been set (made active), you must rerun -+the reencipher command with option \fB--complete\fP to complete the staged -+re-enciphering. When completing the staged re-enciphering, the (unbound) key -+slot containing the re-enciphered secure volume key becomes the active -+key slot and, optionally, all key slots containing the old secure volume key -+are removed. -+Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is performed in staged mode per -+default. You can use option \fB--staged\fP to force a staged re-enciphering for -+the \fBOLD\fP to \fBCURRENT\fP case. -+.PP -+To open a key slot contained in the LUKS2 header of the volume, a passphrase is -+required. You are prompted for the passphrase, unless option -+.B \-\-key\-file -+is specified. Option -+.B \-\-tries -+specifies how often a passphrase can be re-entered. When option -+.B \-\-key\-file -+is specified, the passphrase is read from the specified file. You can specify -+options -+.B \-\-keyfile\-offset -+and -+.B \-\-keyfile\-size -+to control which part of the key file is used as passphrase. These options -+behave in the same way as with \fBcryptsetup\fP. -+.PP -+.B Note: -+The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) -+to be installed. -+. -+. -+. -+.SS "Set a verification pattern of the secure AES volume key" -+. -+.B zkey\-cryptsetup -+.BR setvp | setv -+.I device -+.RB [ \-\-key\-file | \-d -+.IR file-name ] -+.RB [ \-\-keyfile\-offset | \-o -+.IR bytes ] -+.RB [ \-\-keyfile\-size | \-l -+.IR bytes ] -+.RB [ \-\-tries | \-T -+.IR number ] -+.RB [ \-\-verbose | \-V ] -+.RB [ \-\-debug | \-D ] -+.PP -+Use the -+.B setvp -+command to set a verification pattern of the secure AES volume key of a volume -+encrypted with \fBLUKS2\fP and the \fBpaes\fP cipher. The verification pattern -+identifies the effective key used to encrypt the volume's data. -+The verification pattern is stored in a token named -+\fBpaes-verification-pattern\fP in the LUKS2 header. -+.PP -+.B Note: -+Set the verification pattern right after formatting the volume using -+\fB'cryptsetup luksFormat'\fP. -+.PP -+To open a key slot contained in the LUKS2 header of the volume, a passphrase is -+required. You are prompted for the passphrase, unless option -+.B \-\-key\-file -+is specified. Option -+.B \-\-tries -+specifies how often a passphrase can be re-entered. When option -+.B \-\-key\-file -+is specified, the passphrase is read from the specified file. You can specify -+options -+.B \-\-keyfile\-offset -+and -+.B \-\-keyfile\-size -+to control which part of the key file is used as passphrase. These options -+behave in the same way as with \fBcryptsetup\fP. -+. -+. -+. -+.SS "Set a new secure AES volume key for a volume" -+. -+.B zkey\-cryptsetup -+.BR setkey | setk -+.I device -+.BR \-\-master\-key\-file | \-m -+.IR file-name -+.RB [ \-\-key\-file | \-d -+.IR file-name ] -+.RB [ \-\-keyfile\-offset | \-o -+.IR bytes ] -+.RB [ \-\-keyfile\-size | \-l -+.IR bytes ] -+.RB [ \-\-tries | \-T -+.IR number ] -+.RB [ \-\-verbose | \-V ] -+.RB [ \-\-debug | \-D ] -+.PP -+Use the -+.B setkey -+command to set a new secure AES volume key for a volume encrypted with -+\fBLUKS2\fP and the \fBpaes\fP cipher. Use this command to recover from an -+invalid secure AES volume key contained in the LUKS2 header. -+A secure AES volume key contained in the LUKS2 header can become invalid when -+the CCA master key is changed without re-enciphering the secure volume key. -+.PP -+You can recover the secure volume key only if you have a copy of the secure key -+in a file, and this copy was re-enciphered when the CCA master key has been -+changed. Thus, the copy of the secure key must be currently enciphered with the -+CCA master key in the CURRENT or OLD master key register. -+Specify the secure key file with option -+.B \-\-master\-key\-file -+to set this secure key as the new volume key. -+.PP -+In case the LUKS2 header of the volume contains a verification pattern token, -+it is used to ensure that the new volume key contains the same effective key. -+If no verification pattern token is available, then you are prompted to confirm -+that the specified secure key is the correct one. -+.B ATTENTION: -+If you set a wrong secure key you will loose all the data on the encrypted -+volume! -+.PP -+To open a key slot contained in the LUKS2 header of the volume, a passphrase is -+required. You are prompted for the passphrase, unless option -+.B \-\-key\-file -+is specified. Option -+.B \-\-tries -+specifies how often a passphrase can be re-entered. When option -+.B \-\-key\-file -+is specified, the passphrase is read from the specified file. You can specify -+options -+.B \-\-keyfile\-offset -+and -+.B \-\-keyfile\-size -+to control which part of the key file is used as passphrase. These options -+behave in the same way the same as with \fBcryptsetup\fP. -+. -+. -+. -+. -+.SH OPTIONS -+. -+.SS "Options for the reencipher command" -+.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 -+header of the encrypted volume with the re-enciphered secure volume key. -+Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is performed in-place per -+default. -+.TP -+.BR \-s ", " \-\-staged -+Forces that the re-enciphering of a secure volume key in the LUKS2 -+header is performed in staged mode. Staged mode means that the re-enciphered -+secure volume key is stored in a separate (unbound) key slot in the LUKS2 -+header of the encrypted volume. Thus all key slots containing the current -+secure volume key are still valid at this point. Once the new CCA master key -+has been set (made active), you must rerun the reencipher command with option -+\fB--complete\fP to complete the staged re-enciphering. Re-enciphering from -+\fBCURRENT\fP to \fBNEW\fP is performed in staged mode per default. -+.TP -+.BR \-p ", " \-\-complete -+Completes a staged re-enciphering. Use this option after the new CCA master key -+has been set (made active). When completing the staged re-enciphering, the -+(unbound) key slot containing the re-enciphered secure volume key becomes -+the active key slot and, optionally, all key slots containing the old secure -+volume key are removed. -+. -+. -+. -+.SS "Options for the setkey command" -+.TP -+.BR \-m ", " \-\-master\-key\-file\~\fIfile\-name\fP -+Specifies the name of a file containing the secure AES key that is set as the -+new volume key. -+. -+. -+. -+.SS "Options for supplying the passphrase" -+.TP -+.BR \-d ", " \-\-key\-file\~\fIfile\-name\fP -+Reads the passphrase from the specified file. If this option is omitted, -+or if the file\-name is \fI-\fP (a dash), then you are prompted to enter the -+passphrase interactively. -+.TP -+.BR \-o ", " \-\-keyfile\-offset\~\fIbytes\fP -+Specifies the number of bytes to skip before starting to read in the file -+specified with option \fB\-\-key\-file\fP. If omitted, the file is read -+from the beginning. When option \fB\-\-key\-file\fP is not specified, this -+option is ignored. -+.TP -+.BR \-l ", " \-\-keyfile\-size\~\fIbytes\fP -+Specifies the number of bytes to be read from the beginning of the file -+specified with option \fB\-\-key\-file\fP. If omitted, the file is read -+until the end. When \fB\-\-keyfile\-offset\fP is also specified, reading starts -+at the offset. When option \fB\-\-key\-file\fP is not specified, this option is -+ignored. -+.TP -+.BR \-T ", " \-\-tries\~\fInumber\fP -+Specifies how often the interactive input of the passphrase can be re-entered. -+The default is 3 times. When option \fB\-\-key\-file\fP is specified, this -+option is ignored, and the passphrase is read only once from the file. -+. -+. -+. -+.SS "General options" -+.TP -+.BR \-V ", " \-\-verbose -+Displays additional information messages during processing. -+.TP -+.BR \-D ", " \-\-debug -+Displays additional debugging messages during processing. This option also -+implies \fB\-\-verbose\fP. -+.TP -+.BR \-h ", " \-\-help -+Displays help text and exits. -+.TP -+.BR \-v ", " \-\-version -+Displays version information and exits. -+. -+. -+. -+.SH EXAMPLES -+.TP -+.B zkey-cryptsetup reencipher /dev/dasdd1 -+Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1. -+.TP -+.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-staged -+Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1 in -+staged mode. -+.TP -+.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-complete -+Completes re-enciphers the secure volume key of the encrypted -+volume /dev/dasdd1. -+.TP -+.B zkey-cryptsetup reencipher /dev/dasdd1 \-\-in\-place -+Re-enciphers the secure volume key of the encrypted volume /dev/dasdd1 in -+in-place mode. -+.TP -+.B zkey-cryptsetup validate /dev/dasdd1 -+Validates the secure volume key of the encrypted volume /dev/dasdd1 and -+displays its attributes. -+.TP -+.B zkey-cryptsetup setvp /dev/dasdd1 -+Sets the verification pattern of the secure volume key of the encrypted -+volume /dev/dasdd1. -+.TP -+.B zkey-cryptsetup setkey /dev/dasdd1 --master-key-file seckey.key -+Sets the secure key contained in file seckey.key as the new volume key -+for the encrypted volume /dev/dasdd1. diff --git a/s390-tools-sles15sp1-0017-zkey-Add-build-dependency-for-libcryptsetup-and-json.patch b/s390-tools-sles15sp1-0017-zkey-Add-build-dependency-for-libcryptsetup-and-json.patch deleted file mode 100644 index 9c5d252..0000000 --- a/s390-tools-sles15sp1-0017-zkey-Add-build-dependency-for-libcryptsetup-and-json.patch +++ /dev/null @@ -1,188 +0,0 @@ -Subject: zkey: Add build dependency for libcryptsetup and json-c -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 818ffbc4b05783851cc12682d3d8ad6b99312d63 -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Add build dependency for libcryptsetup and json-c - - The zkey-cryptsetup tool has a build dependency to - libcryptsetup version 2.0.3 or later, and json-c. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - README.md | 9 ++++-- - common.mak | 3 +- - zkey/Makefile | 84 +++++++++++++++++++++++++++++++++++++++++++--------------- - 3 files changed, 72 insertions(+), 24 deletions(-) - ---- a/README.md -+++ b/README.md -@@ -264,6 +264,8 @@ build options: - | pfm | `HAVE_PFM` | cpacfstats | - | net-snmp | `HAVE_SNMP` | osasnmpd | - | openssl | `HAVE_OPENSSL` | zkey | -+| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup | -+| json-c | `HAVE_JSONC` | zkey-cryptsetup | - - This table lists additional build or install options: - -@@ -369,8 +371,11 @@ the different tools are provided: - - * zkey: - For building the zkey tools you need openssl version 0.9.7 or newer installed -- (openssl-devel.rpm). Tip: you may skip the zkey build by adding -- `HAVE_OPENSSL=0` to the make invocation. -+ (openssl-devel.rpm). Also required are cryptsetup version 2.0.3 or newer -+ (cryptsetup-devel.rpm), and json-c version 0.12 or newer (json-c-devel.rpm). -+ Tip: you may skip the zkey build by adding `HAVE_OPENSSL=0`, and you may -+ may skip the zkey-cryptsetup build by adding `HAVE_CRYPTSETUP2=0`, or -+ `HAVE_JSONC=0` to the make invocation. - A new group 'zkeyadm' needs to be created and all users intending to use the - tool must be added to this group. The owner of the default key repository - '/etc/zkey/repository' must be set to group 'zkeyadm' with write permission ---- a/common.mak -+++ b/common.mak -@@ -113,9 +113,10 @@ DEFAULT_LDFLAGS = -rdynamic - # $2: Name of include file to check - # $3: Name of required devel package - # $4: Option to skip build (e.g. HAVE_FUSE=0) -+# $5: Additional compiler & linker options (optional) - # - check_dep=\ --printf "\#include <%s>" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) -c -o /dev/null -xc - ) > /dev/null 2>&1; \ -+printf "\#include <%s>\n int main(void) {return 0;}" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -xc - ) > /dev/null 2>&1; \ - if [ $$? != 0 ]; \ - then \ - printf " REQCHK %s (%s)\n" $1 $2; \ ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -1,54 +1,96 @@ - include ../common.mak - --ifeq (${HAVE_OPENSSL},0) -+ifneq (${HAVE_OPENSSL},0) -+ BUILD_TARGETS += zkey -+ INSTALL_TARGETS += install-zkey -+else -+ BUILD_TARGETS += zkey-skip -+ INSTALL_TARGETS += zkey-skip -+endif - --all: -- $(SKIP) HAVE_OPENSSL=0 -+ifneq (${HAVE_CRYPTSETUP2},0) -+ ifneq (${HAVE_JSONC},0) -+ BUILD_TARGETS += zkey-cryptsetup -+ INSTALL_TARGETS += install-zkey-cryptsetup -+ else -+ BUILD_TARGETS += zkey-cryptsetup-skip-jsonc -+ INSTALL_TARGETS += zkey-cryptsetup-skip-jsonc -+ endif -+else -+ BUILD_TARGETS += zkey-cryptsetup-skip-cryptsetup2 -+ INSTALL_TARGETS += zkey-cryptsetup-skip-cryptsetup2 -+endif - --install: -- $(SKIP) HAVE_OPENSSL=0 -+CPPFLAGS += -I../include -+LIBS = $(rootdir)/libutil/libutil.a - --else -+detect-libcryptsetup.h: -+ echo "#include " > detect-libcryptsetup.h -+ echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.h -+ echo " #error libcryptsetup version 2.0.3 is required" >> detect-libcryptsetup.h -+ echo "#endif" >> detect-libcryptsetup.h -+ echo "int i = CRYPT_SLOT_UNBOUND;" >> detect-libcryptsetup.h - --check_dep: -+check-dep-zkey: - $(call check_dep, \ - "zkey", \ - "openssl/evp.h", \ - "openssl-devel", \ - "HAVE_OPENSSL=0") - --CPPFLAGS += -I../include -+check-dep-zkey-cryptsetup: detect-libcryptsetup.h -+ $(call check_dep, \ -+ "zkey-cryptsetup", \ -+ "detect-libcryptsetup.h", \ -+ "cryptsetup-devel version 2.0.3", \ -+ "HAVE_CRYPTSETUP2=0", \ -+ "-I.") -+ $(call check_dep, \ -+ "zkey-cryptsetup", \ -+ "json-c/json.h", \ -+ "json-c-devel", \ -+ "HAVE_JSONC=0") -+ -+zkey-skip: -+ echo " SKIP zkey due to HAVE_OPENSSL=0" -+ -+zkey-cryptsetup-skip-cryptsetup2: -+ echo " SKIP zkey-cryptsetup due to HAVE_CRYPTSETUP2=0" - --all: check_dep zkey zkey-cryptsetup -+zkey-cryptsetup-skip-jsonc: -+ echo " SKIP zkey-cryptsetup due to HAVE_JSONC=0" - --libs = $(rootdir)/libutil/libutil.a -+all: $(BUILD_TARGETS) - - zkey.o: zkey.c pkey.h misc.h - pkey.o: pkey.c pkey.h --properties.o: properties.c properties.h -+properties.o: check-dep-zkey properties.c properties.h - keystore.o: keystore.c keystore.h properties.h --zkey-cryptsetup.o: zkey-cryptsetup.c pkey.h misc.h -+zkey-cryptsetup.o: check-dep-zkey-cryptsetup zkey-cryptsetup.c pkey.h misc.h - - zkey: LDLIBS = -ldl -lcrypto --zkey: zkey.o pkey.o properties.o keystore.o $(libs) -+zkey: zkey.o pkey.o properties.o keystore.o $(LIBS) - - zkey-cryptsetup: LDLIBS = -ldl -lcryptsetup -ljson-c --zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(libs) -+zkey-cryptsetup: zkey-cryptsetup.o pkey.o $(LIBS) - -- --install: all -+install-common: - $(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR) -- $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR) -- $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1 -+ -+install-zkey: -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR) - $(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1 -- $(INSTALL) -m 644 -c zkey-cryptsetup.1 $(DESTDIR)$(MANDIR)/man1 - $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey - $(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository - --endif -+install-zkey-cryptsetup: -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey-cryptsetup $(DESTDIR)$(USRBINDIR) -+ $(INSTALL) -m 644 -c zkey-cryptsetup.1 $(DESTDIR)$(MANDIR)/man1 -+ -+install: all install-common $(INSTALL_TARGETS) - - clean: -- rm -f *.o zkey zkey-cryptsetup -+ rm -f *.o zkey zkey-cryptsetup detect-libcryptsetup.h - - .PHONY: all install clean diff --git a/s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch b/s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch deleted file mode 100644 index 71e0760..0000000 --- a/s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch +++ /dev/null @@ -1,349 +0,0 @@ -Subject: zkey: Add key verification pattern property -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 512b47c0042a3cdedafce8d46dcc76053298116c -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Add key verification pattern property - - Store a verification pattern in the properties file along - with the secure key. The verification pattern allows to identify - the inner key even when the secure key is no longer valid. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++----- - zkey/zkey.1 | 4 - - zkey/zkey.c | 27 +++++++++-- - 3 files changed, 145 insertions(+), 18 deletions(-) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -58,6 +58,7 @@ struct key_filenames { - #define PROP_NAME_CREATION_TIME "creation-time" - #define PROP_NAME_CHANGE_TIME "update-time" - #define PROP_NAME_REENC_TIME "reencipher-time" -+#define PROP_NAME_KEY_VP "verification-pattern" - - #define IS_XTS(secure_key_size) (secure_key_size > SECURE_KEY_SIZE ? 1 : 0) - -@@ -75,6 +76,7 @@ struct key_filenames { - #define REC_CREATION_TIME "Created" - #define REC_CHANGE_TIME "Changed" - #define REC_REENC_TIME "Re-enciphered" -+#define REC_KEY_VP "Verification pattern" - - #define pr_verbose(keystore, fmt...) do { \ - if (keystore->verbose) \ -@@ -1270,6 +1272,77 @@ struct keystore *keystore_new(const char - } - - /** -+ * Generate the key verification pattern from the specified secure key file -+ * -+ * @param[in] keystore the key store -+ * @param[in} keyfile the key file -+ * @param[in] vp buffer filled with the verification pattern -+ * @param[in] vp_len length of the buffer. Must be at -+ * least VERIFICATION_PATTERN_LEN bytes in size. -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+static int _keystore_generate_verification_pattern(struct keystore *keystore, -+ const char *keyfile, -+ char *vp, size_t vp_len) -+{ -+ size_t key_size; -+ u8 *key; -+ int rc; -+ -+ util_assert(keystore != NULL, "Internal error: keystore is NULL"); -+ util_assert(keyfile != NULL, "Internal error: keyfile is NULL"); -+ util_assert(vp != NULL, "Internal error: vp is NULL"); -+ -+ key = read_secure_key(keyfile, &key_size, keystore->verbose); -+ if (key == NULL) -+ return -EIO; -+ -+ rc = generate_key_verification_pattern((const char *)key, key_size, -+ vp, vp_len, keystore->verbose); -+ -+ free(key); -+ return rc; -+} -+ -+/** -+ * Checks if the key verification pattern property exists. If not, then it is -+ * created from the secure key. -+ * -+ * @param[in] keystore the key store -+ * @param[in] file_names the file names of the key -+ * @param[in] key_props the properties of the key -+ * -+ * @returns 0 for success or a negative errno in case of an error -+ */ -+static int _keystore_ensure_vp_exists(struct keystore *keystore, -+ const struct key_filenames *file_names, -+ struct properties *key_props) -+{ -+ char vp[VERIFICATION_PATTERN_LEN]; -+ char *temp; -+ int rc; -+ -+ temp = properties_get(key_props, PROP_NAME_KEY_VP); -+ if (temp != NULL) { -+ free(temp); -+ return 0; -+ } -+ -+ rc = _keystore_generate_verification_pattern(keystore, -+ file_names->skey_filename, -+ vp, sizeof(vp)); -+ if (rc != 0) -+ return rc; -+ -+ rc = properties_set(key_props, PROP_NAME_KEY_VP, vp); -+ if (rc != 0) -+ return rc; -+ -+ return 0; -+} -+ -+/** - * Sets a timestamp to be used as creation/update/reencipher time into - * the specified property - * -@@ -1348,7 +1421,7 @@ static int _keystore_set_default_propert - */ - static int _keystore_create_info_file(struct keystore *keystore, - const char *name, -- const char *info_filename, -+ const struct key_filenames *filenames, - const char *description, - const char *volumes, const char *apqns, - size_t sector_size) -@@ -1396,17 +1469,26 @@ static int _keystore_create_info_file(st - goto out; - } - -- rc = properties_save(key_props, info_filename, 1); -+ rc = _keystore_ensure_vp_exists(keystore, filenames, key_props); -+ if (rc != 0) { -+ warnx("Failed to generate the key verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ return rc; -+ } -+ -+ rc = properties_save(key_props, filenames->info_filename, 1); - if (rc != 0) { - pr_verbose(keystore, - "Key info file '%s' could not be written: %s", -- info_filename, strerror(-rc)); -+ filenames->info_filename, strerror(-rc)); - goto out; - } - -- rc = _keystore_set_file_permission(keystore, info_filename); -+ rc = _keystore_set_file_permission(keystore, filenames->info_filename); - if (rc != 0) { -- remove(info_filename); -+ remove(filenames->info_filename); - goto out; - } - -@@ -1519,8 +1601,7 @@ int keystore_generate_key(struct keystor - if (rc != 0) - goto out_free_props; - -- rc = _keystore_create_info_file(keystore, name, -- file_names.info_filename, -+ rc = _keystore_create_info_file(keystore, name, &file_names, - description, volumes, apqns, - sector_size); - if (rc != 0) -@@ -1603,8 +1684,7 @@ int keystore_import_key(struct keystore - if (rc != 0) - goto out_free_props; - -- rc = _keystore_create_info_file(keystore, name, -- file_names.info_filename, -+ rc = _keystore_create_info_file(keystore, name, &file_names, - description, volumes, apqns, - sector_size); - if (rc != 0) -@@ -1723,6 +1803,9 @@ int keystore_change_key(struct keystore - } - } - -+ rc = _keystore_ensure_vp_exists(keystore, &file_names, key_props); -+ /* ignore return code, vp generation might fail if key is not valid */ -+ - rc = _keystore_set_timestamp_property(key_props, PROP_NAME_CHANGE_TIME); - if (rc != 0) - goto out; -@@ -1838,7 +1921,7 @@ static struct util_rec *_keystore_setup_ - { - struct util_rec *rec; - -- rec = util_rec_new_long("-", ":", REC_KEY, 23, 54); -+ rec = util_rec_new_long("-", ":", REC_KEY, 28, 54); - util_rec_def(rec, REC_KEY, UTIL_REC_ALIGN_LEFT, 54, REC_KEY); - if (validation) - util_rec_def(rec, REC_STATUS, UTIL_REC_ALIGN_LEFT, 54, -@@ -1858,6 +1941,7 @@ static struct util_rec *_keystore_setup_ - util_rec_def(rec, REC_KEY_FILE, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_FILE); - util_rec_def(rec, REC_SECTOR_SIZE, UTIL_REC_ALIGN_LEFT, 54, - REC_SECTOR_SIZE); -+ util_rec_def(rec, REC_KEY_VP, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_VP); - util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54, - REC_CREATION_TIME); - util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54, -@@ -1876,6 +1960,7 @@ static void _keystore_print_record(struc - size_t clear_key_bitsize, bool valid, - bool is_old_mk, bool reenc_pending) - { -+ char temp_vp[VERIFICATION_PATTERN_LEN + 2]; - char *volumes_argz = NULL; - size_t volumes_argz_len; - char *apqns_argz = NULL; -@@ -1888,6 +1973,8 @@ static void _keystore_print_record(struc - char *change; - char *apqns; - char *temp; -+ char *vp; -+ int len; - - description = properties_get(properties, PROP_NAME_DESCRIPTION); - volumes = properties_get(properties, PROP_NAME_VOLUMES); -@@ -1913,6 +2000,7 @@ static void _keystore_print_record(struc - creation = properties_get(properties, PROP_NAME_CREATION_TIME); - change = properties_get(properties, PROP_NAME_CHANGE_TIME); - reencipher = properties_get(properties, PROP_NAME_REENC_TIME); -+ vp = properties_get(properties, PROP_NAME_KEY_VP); - - util_rec_set(rec, REC_KEY, name); - if (validation) -@@ -1951,6 +2039,15 @@ static void _keystore_print_record(struc - else - util_rec_set(rec, REC_SECTOR_SIZE, "%lu bytes", - sector_size); -+ if (vp != NULL) { -+ len = sprintf(temp_vp, "%.*s%c%.*s", -+ VERIFICATION_PATTERN_LEN / 2, vp, -+ '\0', VERIFICATION_PATTERN_LEN / 2, -+ &vp[VERIFICATION_PATTERN_LEN / 2]); -+ util_rec_set_argz(rec, REC_KEY_VP, temp_vp, len + 1); -+ } else { -+ util_rec_set(rec, REC_KEY_VP, "(not available)"); -+ } - util_rec_set(rec, REC_CREATION_TIME, creation); - util_rec_set(rec, REC_CHANGE_TIME, - change != NULL ? change : "(never)"); -@@ -1976,6 +2073,8 @@ static void _keystore_print_record(struc - free(change); - if (reencipher != NULL) - free(reencipher); -+ if (vp != NULL) -+ free(vp); - } - - struct validate_info { -@@ -2404,6 +2503,17 @@ static int _keystore_process_reencipher( - if (rc != 0) - goto out; - -+ rc = _keystore_ensure_vp_exists(keystore, file_names, -+ properties); -+ if (rc != 0) { -+ warnx("Failed to generate the key verification pattern " -+ "for key '%s': %s", file_names->skey_filename, -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ goto out; -+ } -+ - rc = properties_save(properties, file_names->info_filename, 1); - if (rc != 0) { - pr_verbose(keystore, -@@ -3040,7 +3150,7 @@ static int _keystore_process_crypttab(st - "At the time this utility was developed, systemd's " - "support of crypttab did not support to specify a " - "sector size with plain dm-crypt devices. The generated " -- "crypttab entry may or may not work, and may need " -+ "crypttab entry might or might not work, and might need " - "manual adoptions.", volume, sector_size); - util_print_indented(temp, 0); - } ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -361,8 +361,8 @@ The - command displays the attributes of the secure keys, such as key sizes, - 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, and timestamps for key creation, last modification and last --re-encipherment. -+sector size, the key verification pattern, and timestamps for key creation, last -+modification and last re-encipherment. - . - .SS "Remove existing AES secure keys from the secure key repository" - . ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -1057,6 +1057,7 @@ static int command_reencipher(void) - */ - static int command_validate_file(void) - { -+ char vp[VERIFICATION_PATTERN_LEN]; - size_t secure_key_size; - size_t clear_key_size; - u8 *secure_key; -@@ -1089,14 +1090,30 @@ static int command_validate_file(void) - goto out; - } - -+ rc = generate_key_verification_pattern((char *)secure_key, -+ secure_key_size, vp, sizeof(vp), -+ g.verbose); -+ if (rc != 0) { -+ warnx("Failed to generate the verification pattern: %s", -+ strerror(-rc)); -+ warnx("Make sure that kernel module 'paes_s390' is loaded and " -+ "that the 'paes' cipher is available"); -+ 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", -+ 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(" Encrypted with: %s CCA master key\n", -+ printf(" Enciphered with: %s CCA master key\n", - is_old_mk ? "OLD" : "CURRENT"); -+ printf(" Verification pattern: %.*s\n", VERIFICATION_PATTERN_LEN / 2, -+ vp); -+ printf(" %.*s\n", VERIFICATION_PATTERN_LEN / 2, -+ &vp[VERIFICATION_PATTERN_LEN / 2]); - - out: - free(secure_key); diff --git a/s390-tools-sles15sp1-0019-zkey-Add-volume-type-property-to-support-LUKS2-volum.patch b/s390-tools-sles15sp1-0019-zkey-Add-volume-type-property-to-support-LUKS2-volum.patch deleted file mode 100644 index fa876db..0000000 --- a/s390-tools-sles15sp1-0019-zkey-Add-volume-type-property-to-support-LUKS2-volum.patch +++ /dev/null @@ -1,1803 +0,0 @@ -Subject: zkey: Add volume-type property to support LUKS2 volumes -From: Ingo Franzki - -Summary: zkey: Support CCA master key change with LUKS2 volumes using paes -Description: Support the usage of protected key crypto for dm-crypt disks in - LUKS2 format by providing a tool allowing to re-encipher a - secure LUKS2 volume key when the CCA master key is changed -Upstream-ID: 1f07a41d5a408c1650d20a688cf10bd02a8e7dd7 -Problem-ID: SEC1424.1 - -Upstream-Description: - - zkey: Add volume-type property to support LUKS2 volumes - - Allow to specify a volume-type for a key. This applies to all - associated volumes. The volume type can be either 'plain' or - 'luks2'. New keys created will default to 'luks2', but existing - keys that do not have a volume-type property default to 'plain' - for compatibility reasons. - - The volume type 'luks2' is only available when the define - HAVE_LUKS2_SUPPORT is set in the makefile. This is set only - when libcryptsetup version 2.0.3 or newer is available - at build time. If the define is not set, the volume-type - option is not available to the user, and the volume-type of - a key defaults to 'plain'. - - Signed-off-by: Ingo Franzki - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Ingo Franzki ---- - zkey/Makefile | 1 - zkey/keystore.c | 423 +++++++++++++++++++++++++++++++++++++++++++++----------- - zkey/keystore.h | 15 + - zkey/zkey.1 | 292 ++++++++++++++++++++++++-------------- - zkey/zkey.c | 100 +++++++++++-- - 5 files changed, 627 insertions(+), 204 deletions(-) - ---- a/zkey/Makefile -+++ b/zkey/Makefile -@@ -12,6 +12,7 @@ ifneq (${HAVE_CRYPTSETUP2},0) - ifneq (${HAVE_JSONC},0) - BUILD_TARGETS += zkey-cryptsetup - INSTALL_TARGETS += install-zkey-cryptsetup -+ CPPFLAGS += -DHAVE_LUKS2_SUPPORT - else - BUILD_TARGETS += zkey-cryptsetup-skip-jsonc - INSTALL_TARGETS += zkey-cryptsetup-skip-jsonc ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -59,6 +59,15 @@ struct key_filenames { - #define PROP_NAME_CHANGE_TIME "update-time" - #define PROP_NAME_REENC_TIME "reencipher-time" - #define PROP_NAME_KEY_VP "verification-pattern" -+#define PROP_NAME_VOLUME_TYPE "volume-type" -+ -+#define VOLUME_TYPE_PLAIN "plain" -+#define VOLUME_TYPE_LUKS2 "luks2" -+#ifdef HAVE_LUKS2_SUPPORT -+ #define DEFAULT_VOLUME_TYPE VOLUME_TYPE_LUKS2 -+#else -+ #define DEFAULT_VOLUME_TYPE VOLUME_TYPE_PLAIN -+#endif - - #define IS_XTS(secure_key_size) (secure_key_size > SECURE_KEY_SIZE ? 1 : 0) - -@@ -72,11 +81,12 @@ struct key_filenames { - #define REC_KEY_FILE "Key file name" - #define REC_SECTOR_SIZE "Sector size" - #define REC_STATUS "Status" --#define REC_MASTERKEY "Encrypted with" -+#define REC_MASTERKEY "Enciphered with" - #define REC_CREATION_TIME "Created" - #define REC_CHANGE_TIME "Changed" - #define REC_REENC_TIME "Re-enciphered" - #define REC_KEY_VP "Verification pattern" -+#define REC_VOLUME_TYPE "Volume type" - - #define pr_verbose(keystore, fmt...) do { \ - if (keystore->verbose) \ -@@ -280,6 +290,85 @@ static int _keystore_valid_sector_size(s - return 1; - } - -+/** -+ * Checks if the volume type is supported. -+ * -+ * @param[in] volume_type the volume type -+ * -+ * @returns 1 if the volume type is valid, 0 otherwise -+ */ -+static int _keystore_valid_volume_type(const char *volume_type) -+{ -+ if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) -+ return 1; -+#ifdef HAVE_LUKS2_SUPPORT -+ if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) -+ return 1; -+#endif -+ return 0; -+} -+ -+/** -+ * Returns the volume type contained in the properties. If no volume type -+ * property is contained, then 'plain' is assumed (for backward comatibility). -+ * -+ * @returns a string containing the volume type. Must be freed by the caller. -+ */ -+static char *_keystore_get_volume_type(struct properties *properties) -+{ -+ char *type; -+ -+ type = properties_get(properties, PROP_NAME_VOLUME_TYPE); -+ if (type == NULL) -+ type = util_strdup(VOLUME_TYPE_PLAIN); -+ -+ return type; -+} -+ -+/** -+ * Prints a message followed by a list of associated volumes, if volumes are -+ * associated and the volume-type matches (if specified) -+ * -+ * @param[in] msg the message to display -+ * @param[in] properties the properties -+ * @param[in] volume_type the volume type to display the message for (or NULL) -+ * -+ * @returns always zero -+ */ -+static int _keystore_msg_for_volumes(const char *msg, -+ struct properties *properties, -+ const char *volume_type) -+{ -+ char *volumes = NULL; -+ char **volume_list; -+ char *type = NULL; -+ int i; -+ -+ if (volume_type != NULL) { -+ type = _keystore_get_volume_type(properties); -+ if (strcasecmp(type, volume_type) != 0) -+ goto out; -+ } -+ -+ volumes = properties_get(properties, PROP_NAME_VOLUMES); -+ if (volumes != NULL && strlen(volumes) > 0) { -+ volume_list = str_list_split(volumes); -+ -+ util_print_indented(msg, 0); -+ for (i = 0; volume_list[i] != NULL; i++) -+ printf(" %s\n", volume_list[i]); -+ str_list_free_string_array(volume_list); -+ } -+ -+out: -+ if (volumes != NULL) -+ free(volumes); -+ if (type != NULL) -+ free(type); -+ -+ return 0; -+} -+ - typedef int (*check_association_t)(const char *value, bool remove, - char **normalized, void *private); - -@@ -712,6 +801,35 @@ static int _keystore_match_filter_proper - } - - /** -+ * Checks if the volume type property matches the specified volume type. -+ * If the properties do not contain a volume type property, then the default -+ * volume type is assumed. -+ * -+ * @param[in] properties a properties object -+ * @param[in] volume_type the volume 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_volume_type_property(struct properties *properties, -+ const char *volume_type) -+{ -+ char *type; -+ int rc = 0; -+ -+ if (volume_type == NULL) -+ return 1; -+ -+ type = _keystore_get_volume_type(properties); -+ if (strcasecmp(type, volume_type) == 0) -+ rc = 1; -+ -+ free(type); -+ return rc; -+} -+ -+ -+/** - * Checks if a key name matches a name filter - * - * @param[in] name the name to check -@@ -774,6 +892,7 @@ typedef int (*process_key_t)(struct keys - * @param[in] apqn_filter the APQN filter. Can contain wild cards, and - * mutliple APQN filters separated by commas. - * NULL means no APQN filter. -+ * @param[in] volume_type If not NULL, specifies the volume type. - * @param[in] process_func the callback function called for a matching key - * @param[in/out] process_private private data passed to the process_func - * -@@ -785,6 +904,7 @@ static int _keystore_process_filtered(st - const char *name_filter, - const char *volume_filter, - const char *apqn_filter, -+ const char *volume_type, - process_key_t process_func, - void *process_private) - { -@@ -867,6 +987,15 @@ static int _keystore_process_filtered(st - goto free_prop; - } - -+ rc = _keystore_match_volume_type_property(key_props, -+ volume_type); -+ if (rc == 0) { -+ pr_verbose(keystore, -+ "Key '%s' filtered out due to volume type", -+ name); -+ goto free_prop; -+ } -+ - rc = process_func(keystore, name, key_props, &file_names, - process_private); - if (rc != 0) { -@@ -1122,8 +1251,8 @@ static int _keystore_volume_check(const - } - - rc = _keystore_process_filtered(info->keystore, NULL, info->volume, -- NULL, _keystore_volume_check_process, -- info); -+ NULL, NULL, -+ _keystore_volume_check_process, info); - out: - free((void *)info->volume); - info->volume = NULL; -@@ -1418,13 +1547,15 @@ static int _keystore_set_default_propert - * of two and in range 512 - 4096 bytes. 0 means that - * the sector size is not specified and the system - * default is used. -+ * @param[in] volume_type the type of volume - */ - static int _keystore_create_info_file(struct keystore *keystore, - const char *name, - const struct key_filenames *filenames, - const char *description, - const char *volumes, const char *apqns, -- size_t sector_size) -+ size_t sector_size, -+ const char *volume_type) - { - struct volume_check vol_check = { .keystore = keystore, .name = name }; - struct properties *key_props; -@@ -1469,6 +1600,19 @@ static int _keystore_create_info_file(st - goto out; - } - -+ if (volume_type == NULL) -+ volume_type = DEFAULT_VOLUME_TYPE; -+ if (!_keystore_valid_volume_type(volume_type)) { -+ warnx("Invalid volume-type specified"); -+ rc = -EINVAL; -+ goto out; -+ } -+ rc = properties_set(key_props, PROP_NAME_VOLUME_TYPE, volume_type); -+ if (rc != 0) { -+ warnx("Invalid characters in volume-type"); -+ goto out; -+ } -+ - rc = _keystore_ensure_vp_exists(keystore, filenames, key_props); - if (rc != 0) { - warnx("Failed to generate the key verification pattern: %s", -@@ -1553,6 +1697,7 @@ out: - * @param[in] clear_key_file if not NULL the secure key is generated from the - * 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] pkey_fd the file descriptor of /dev/pkey - * - * @returns 0 for success or a negative errno in case of an error -@@ -1561,7 +1706,7 @@ int keystore_generate_key(struct keystor - const char *description, const char *volumes, - const char *apqns, size_t sector_size, - size_t keybits, bool xts, const char *clear_key_file, -- int pkey_fd) -+ const char *volume_type, int pkey_fd) - { - struct key_filenames file_names = { NULL, NULL, NULL }; - struct properties *key_props = NULL; -@@ -1603,7 +1748,7 @@ int keystore_generate_key(struct keystor - - rc = _keystore_create_info_file(keystore, name, &file_names, - description, volumes, apqns, -- sector_size); -+ sector_size, volume_type); - if (rc != 0) - goto out_free_props; - -@@ -1640,14 +1785,15 @@ out_free_key_filenames: - * of two and in range 512 - 4096 bytes. 0 means that - * the sector size is not specified and the system - * default is used. -- * @param[in] import_file The name of a secure key containing the kley to import -+ * @param[in] import_file The name of a secure key containing the key to import -+ * @param[in] volume_type the type of volume - * - * @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, size_t sector_size, -- const char *import_file) -+ const char *import_file, const char *volume_type) - { - struct key_filenames file_names = { NULL, NULL, NULL }; - struct properties *key_props = NULL; -@@ -1686,7 +1832,7 @@ int keystore_import_key(struct keystore - - rc = _keystore_create_info_file(keystore, name, &file_names, - description, volumes, apqns, -- sector_size); -+ sector_size, volume_type); - if (rc != 0) - goto out_free_props; - -@@ -1722,25 +1868,28 @@ out_free_key_filenames: - * volumes are not changed. - * @param[in] apqns a comma separated list of APQNs associated with this - * key, or an APQN prefixed with '+' or '-' to add or -- * remove that APQN respectively. IfNULL then the APQNs -+ * remove that APQN respectively. If NULL then the APQNs - * are not changed. - * @param[in] sector_size the sector size to use with dm-crypt. It must be power - * of two and in range 512 - 4096 bytes. 0 means that - * the sector size is not specified and the system - * default is used. Specify -1 if this property should - * not be changed. -- * -+ * @param[in] volume_type the type of volume. If NULL then the volume type is -+ * not changed. -+ * * - * @returns 0 for success or a negative errno in case of an error - * - */ - int keystore_change_key(struct keystore *keystore, const char *name, - const char *description, const char *volumes, -- const char *apqns, long int sector_size) -+ const char *apqns, long int sector_size, -+ const char *volume_type) - { - struct volume_check vol_check = { .keystore = keystore, .name = name }; - struct key_filenames file_names = { NULL, NULL, NULL }; - struct properties *key_props = NULL; -- char temp[10]; -+ char temp[30]; - int rc; - - util_assert(keystore != NULL, "Internal error: keystore is NULL"); -@@ -1803,6 +1952,21 @@ int keystore_change_key(struct keystore - } - } - -+ if (volume_type != NULL) { -+ if (!_keystore_valid_volume_type(volume_type)) { -+ warnx("Invalid volume-type specified"); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ rc = properties_set(key_props, PROP_NAME_VOLUME_TYPE, -+ volume_type); -+ if (rc != 0) { -+ warnx("Invalid characters in volume-type"); -+ goto out; -+ } -+ } -+ - rc = _keystore_ensure_vp_exists(keystore, &file_names, key_props); - /* ignore return code, vp generation might fail if key is not valid */ - -@@ -1849,6 +2013,8 @@ int keystore_rename_key(struct keystore - { - struct key_filenames file_names = { NULL, NULL, NULL }; - struct key_filenames new_names = { NULL, NULL, NULL }; -+ struct properties *key_props = NULL; -+ char *msg; - int rc; - - util_assert(keystore != NULL, "Internal error: keystore is NULL"); -@@ -1896,12 +2062,28 @@ int keystore_rename_key(struct keystore - } - } - -+ key_props = properties_new(); -+ rc = properties_load(key_props, new_names.info_filename, 1); -+ if (rc != 0) { -+ warnx("Key '%s' does not exist or is invalid", newname); -+ goto out; -+ } -+ -+ util_asprintf(&msg, "The following volumes are associated with the " -+ "renamed key '%s'. You should adjust the corresponding " -+ "crypttab entries and 'cryptsetup plainOpen' commands to " -+ "use the new name.", newname); -+ _keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_PLAIN); -+ free(msg); -+ - pr_verbose(keystore, "Successfully renamed key '%s' to '%s'", name, - newname); - - out: - _keystore_free_key_filenames(&file_names); - _keystore_free_key_filenames(&new_names); -+ if (key_props != NULL) -+ properties_free(key_props); - - if (rc != 0) - pr_verbose(keystore, "Failed to rename key '%s'to '%s': %s", -@@ -1941,6 +2123,8 @@ static struct util_rec *_keystore_setup_ - util_rec_def(rec, REC_KEY_FILE, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_FILE); - util_rec_def(rec, REC_SECTOR_SIZE, UTIL_REC_ALIGN_LEFT, 54, - REC_SECTOR_SIZE); -+ util_rec_def(rec, REC_VOLUME_TYPE, UTIL_REC_ALIGN_LEFT, 54, -+ REC_VOLUME_TYPE); - util_rec_def(rec, REC_KEY_VP, UTIL_REC_ALIGN_LEFT, 54, REC_KEY_VP); - util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54, - REC_CREATION_TIME); -@@ -1967,6 +2151,7 @@ static void _keystore_print_record(struc - size_t sector_size = 0; - size_t apqns_argz_len; - char *description; -+ char *volume_type; - char *reencipher; - char *creation; - char *volumes; -@@ -2001,6 +2186,7 @@ static void _keystore_print_record(struc - change = properties_get(properties, PROP_NAME_CHANGE_TIME); - reencipher = properties_get(properties, PROP_NAME_REENC_TIME); - vp = properties_get(properties, PROP_NAME_KEY_VP); -+ volume_type = _keystore_get_volume_type(properties); - - util_rec_set(rec, REC_KEY, name); - if (validation) -@@ -2039,6 +2225,7 @@ static void _keystore_print_record(struc - else - util_rec_set(rec, REC_SECTOR_SIZE, "%lu bytes", - sector_size); -+ util_rec_set(rec, REC_VOLUME_TYPE, volume_type); - if (vp != NULL) { - len = sprintf(temp_vp, "%.*s%c%.*s", - VERIFICATION_PATTERN_LEN / 2, vp, -@@ -2075,6 +2262,8 @@ static void _keystore_print_record(struc - free(reencipher); - if (vp != NULL) - free(vp); -+ if (volume_type != NULL) -+ free(volume_type); - } - - struct validate_info { -@@ -2227,10 +2416,10 @@ static int _keystore_process_validate(st - - if (valid && is_old_mk) { - util_print_indented("WARNING: The secure key is currently " -- "enciphered with the OLD CCA master key " -- "and should be re-enciphered with the " -- "CURRENT CCA master key as soon as " -- "possible to avoid data loss\n", 0); -+ "enciphered with the OLD CCA master key. " -+ "To mitigate the danger of data loss " -+ "re-encipher it with the CURRENT CCA " -+ "master key\n", 0); - info->num_warnings++; - } - if (_keystore_display_apqn_status(properties, name) != 0) -@@ -2271,7 +2460,7 @@ int keystore_validate_key(struct keystor - info.num_warnings = 0; - - rc = _keystore_process_filtered(keystore, name_filter, NULL, -- apqn_filter, -+ apqn_filter, NULL, - _keystore_process_validate, &info); - - util_rec_free(rec); -@@ -2458,7 +2647,8 @@ static int _keystore_process_reencipher( - if (params.complete) { - warnx("Key '%s' is not valid, re-enciphering is not " - "completed", name); -- warnx("Possibly the CCA master key not yet been set?"); -+ warnx("The new CCA master key might yet have to be set " -+ "as the CURRENT master key."); - } else { - warnx("Key '%s' is not valid, it is not re-enciphered", - name); -@@ -2526,6 +2716,14 @@ static int _keystore_process_reencipher( - file_names->info_filename); - if (rc != 0) - goto out; -+ -+ util_asprintf(&temp, "The following LUKS2 volumes are " -+ "encrypted with key '%s'. You should also " -+ "re-encipher the volume key of those volumes " -+ "using command 'zkey-cryptsetup reencipher " -+ "':", name); -+ _keystore_msg_for_volumes(temp, properties, VOLUME_TYPE_LUKS2); -+ free(temp); - } - - if (params.complete || -@@ -2539,12 +2737,11 @@ static int _keystore_process_reencipher( - } - - if (params.inplace != 1) { -- util_asprintf(&temp, "Staged re-enciphering has completed for " -- "key '%s'. Run 'zkey reencipher' with option " -- "'--complete' when the NEW CCA master key has " -- "been set (moved to the CURRENT master key " -- "register) to complete the re-enciphering " -- "process", name); -+ util_asprintf(&temp, "Staged re-enciphering is initiated for " -+ "key '%s'. After the NEW CCA master key has been " -+ "set to become the CURRENT master key run " -+ "'zkey reencipher' with option '--complete' to " -+ "complete the re-enciphering process", name); - util_print_indented(temp, 0); - free(temp); - } -@@ -2613,7 +2810,7 @@ int keystore_reencipher_key(struct keyst - info.num_skipped = 0; - - rc = _keystore_process_filtered(keystore, name_filter, NULL, -- apqn_filter, -+ apqn_filter, NULL, - _keystore_process_reencipher, &info); - - if (rc != 0) { -@@ -2833,10 +3030,9 @@ static int _keystore_propmp_for_remove(s - struct key_filenames *file_names) - { - struct properties *key_prop; -- char *volumes = NULL; -- char **volume_list = NULL; - char str[20]; -- int rc, i; -+ char *msg; -+ int rc; - - key_prop = properties_new(); - rc = properties_load(key_prop, file_names->info_filename, 1); -@@ -2845,15 +3041,10 @@ static int _keystore_propmp_for_remove(s - goto out; - } - -- volumes = properties_get(key_prop, PROP_NAME_VOLUMES); -- if (volumes != NULL && strlen(volumes) > 0) { -- volume_list = str_list_split(volumes); -- -- warnx("When you remove key '%s' the following volumes will " -- "no longer be usable:", name); -- for (i = 0; volume_list[i] != NULL; i++) -- fprintf(stderr, "%s\n", volume_list[i]); -- } -+ util_asprintf(&msg, "When you remove key '%s' the following volumes " -+ "will no longer be usable:", name); -+ _keystore_msg_for_volumes(msg, key_prop, VOLUME_TYPE_PLAIN); -+ free(msg); - - printf("%s: Remove key '%s'? ", program_invocation_short_name, name); - if (fgets(str, sizeof(str), stdin) == NULL) { -@@ -2870,9 +3061,6 @@ static int _keystore_propmp_for_remove(s - - out: - properties_free(key_prop); -- if (volume_list != NULL) -- str_list_free_string_array(volume_list); -- - return rc; - } - -@@ -3000,22 +3188,30 @@ out: - * @param[in] apqn_filter the APQN filter. Can contain wild cards, and - * mutliple APQN filters separated by commas. - * NULL means no APQN filter. -+ * @param[in] volume_type The volume type. NULL means no volume 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_filter, const char *apqn_filter, -+ const char *volume_type) - { - struct util_rec *rec; - int rc; - - util_assert(keystore != NULL, "Internal error: keystore is NULL"); - -+ if (volume_type != NULL && -+ !_keystore_valid_volume_type(volume_type)) { -+ warnx("Invalid volume-type specified"); -+ return -EINVAL; -+ } -+ - rec = _keystore_setup_record(0); - - rc = _keystore_process_filtered(keystore, name_filter, volume_filter, -- apqn_filter, _keystore_display_key, -- rec); -+ apqn_filter, volume_type, -+ _keystore_display_key, rec); - util_rec_free(rec); - - if (rc != 0) -@@ -3067,6 +3263,7 @@ struct crypt_info { - const char *key_file_name, - size_t key_file_size, - size_t sector_size, -+ const char *volume_type, - struct crypt_info *info); - }; - -@@ -3080,7 +3277,8 @@ struct crypt_info { - * @param[in] cipher_spec the cipher specification - * @param[in] key_file_name the key file name - * @param[in] key_file_size the size of the key file in bytes -- * @param sector_size the sector size in bytes or 0 if not specified -+ * @param[in] sector_size the sector size in bytes or 0 if not specified -+ * @param[in] volume_type the volume type - * @param[in] info processing info - * - * @returns 0 if successful, a negative errno value otherwise -@@ -3092,6 +3290,7 @@ static int _keystore_process_cryptsetup( - const char *key_file_name, - size_t key_file_size, - size_t sector_size, -+ const char *volume_type, - struct crypt_info *info) - { - char temp[100]; -@@ -3099,18 +3298,53 @@ static int _keystore_process_cryptsetup( - char *cmd; - - sprintf(temp, "--sector-size %lu ", sector_size); -- util_asprintf(&cmd, -- "cryptsetup plainOpen %s--key-file '%s' --key-size %lu " -- "--cipher %s %s%s %s", -- keystore->verbose ? "-v " : "", key_file_name, -- key_file_size * 8, cipher_spec, -- sector_size > 0 ? temp : "", volume, dmname); -- -- if (info->execute) { -- printf("Executing: %s\n", cmd); -- rc = _keystore_execute_cmd(cmd, "cryptsetup"); -+ -+ if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) { -+ util_asprintf(&cmd, -+ "cryptsetup plainOpen %s--key-file '%s' " -+ "--key-size %lu --cipher %s %s%s %s", -+ keystore->verbose ? "-v " : "", key_file_name, -+ key_file_size * 8, cipher_spec, -+ sector_size > 0 ? temp : "", volume, dmname); -+ -+ if (info->execute) { -+ printf("Executing: %s\n", cmd); -+ rc = _keystore_execute_cmd(cmd, "cryptsetup"); -+ } else { -+ printf("%s\n", cmd); -+ } -+ } else if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) { -+ util_asprintf(&cmd, -+ "cryptsetup luksFormat %s--type luks2 " -+ "--master-key-file '%s' --key-size %lu " -+ "--cipher %s %s%s", -+ keystore->verbose ? "-v " : "", key_file_name, -+ key_file_size * 8, cipher_spec, -+ sector_size > 0 ? temp : "", volume); -+ -+ if (info->execute) { -+ printf("Executing: %s\n", cmd); -+ rc = _keystore_execute_cmd(cmd, "cryptsetup"); -+ } else { -+ printf("%s\n", cmd); -+ } -+ -+ free(cmd); -+ if (rc != 0) -+ return rc; -+ -+ util_asprintf(&cmd, -+ "zkey-cryptsetup setvp %s%s", volume, -+ keystore->verbose ? " -V " : ""); -+ -+ if (info->execute) { -+ printf("Executing: %s\n", cmd); -+ rc = _keystore_execute_cmd(cmd, "zkey-cryptsetup"); -+ } else { -+ printf("%s\n", cmd); -+ } - } else { -- printf("%s\n", cmd); -+ return -EINVAL; - } - - free(cmd); -@@ -3127,7 +3361,8 @@ static int _keystore_process_cryptsetup( - * @param[in] cipher_spec the cipher specification - * @param[in] key_file_name the key file name - * @param[in] key_file_size the size of the key file in bytes -- * @param sector_size the sector size in bytes or 0 if not specified -+ * @param[in] sector_size the sector size in bytes or 0 if not specified -+ * @param[in] volume_type the volume type - * @param[in] info processing info (not used here) - * - * @returns 0 if successful, a negative errno value otherwise -@@ -3140,26 +3375,35 @@ static int _keystore_process_crypttab(st - const char *key_file_name, - size_t key_file_size, - size_t sector_size, -+ const char *volume_type, - struct crypt_info *UNUSED(info)) - { - char temp[1000]; - -- if (sector_size > 0) { -- sprintf(temp, -- "WARNING: volume '%s' is using a sector size of %lu. " -- "At the time this utility was developed, systemd's " -- "support of crypttab did not support to specify a " -- "sector size with plain dm-crypt devices. The generated " -- "crypttab entry might or might not work, and might need " -- "manual adoptions.", volume, sector_size); -- util_print_indented(temp, 0); -+ if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) { -+ if (sector_size > 0) { -+ sprintf(temp, -+ "WARNING: volume '%s' is using a sector size " -+ "of %lu. At the time this utility was " -+ "developed, systemd's support of crypttab did " -+ "not support to specify a sector size with " -+ "plain dm-crypt devices. The generated " -+ "crypttab entry might or might not work, and " -+ "might need manual adoptions.", volume, -+ sector_size); -+ util_print_indented(temp, 0); -+ } -+ -+ sprintf(temp, ",sector-size=%lu", sector_size); -+ printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu,hash=plain%s\n", -+ dmname, volume, key_file_name, cipher_spec, -+ key_file_size * 8, sector_size > 0 ? temp : ""); -+ } else if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) { -+ printf("%s\t%s\n", dmname, volume); -+ } else { -+ return -EINVAL; - } - -- sprintf(temp, ",sector-size=%lu", sector_size); -- printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu,hash=plain%s\n", -- dmname, volume, key_file_name, cipher_spec, key_file_size * 8, -- sector_size > 0 ? temp : ""); -- - return 0; - } - -@@ -3251,6 +3495,7 @@ static int _keystore_process_crypt(struc - struct crypt_info *info = (struct crypt_info *)private; - char **volume_list = NULL; - char *cipher_spec = NULL; -+ char *volume_type = NULL; - size_t secure_key_size; - size_t sector_size = 0; - char *volumes = NULL; -@@ -3290,6 +3535,8 @@ static int _keystore_process_crypt(struc - free(temp); - } - -+ volume_type = _keystore_get_volume_type(properties); -+ - for (i = 0; volume_list[i] != NULL && rc == 0; i++) { - vol = volume_list[i]; - if (_keystore_match_filter(vol, info->volume_filter, -@@ -3306,7 +3553,8 @@ static int _keystore_process_crypt(struc - - rc = info->process_func(keystore, vol, dmname, - cipher_spec, file_names->skey_filename, -- secure_key_size, sector_size, info); -+ secure_key_size, sector_size, -+ volume_type, info); - if (rc != 0) - break; - } -@@ -3319,6 +3567,8 @@ out: - str_list_free_string_array(volume_list); - if (cipher_spec != NULL) - free(cipher_spec); -+ if (volume_type != NULL) -+ free(volume_type); - return rc; - } - -@@ -3333,11 +3583,12 @@ out: - * checks the volume part only. - * @param[in] execute If TRUE the cryptsetup command is executed, - * otherwise it is printed to stdout -- * -+ * @param[in] volume_type the type of volume to generate cryptsetup cmds for -+ * * - * @returns 0 for success or a negative errno in case of an error - */ - int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, -- bool execute) -+ bool execute, const char *volume_type) - { - struct crypt_info info = { 0 }; - int rc; -@@ -3346,12 +3597,20 @@ int keystore_cryptsetup(struct keystore - - if (volume_filter == NULL) - volume_filter = "*"; -+ -+ if (volume_type != NULL && -+ !_keystore_valid_volume_type(volume_type)) { -+ warnx("Invalid volume-type specified"); -+ return -EINVAL; -+ } -+ - info.execute = execute; - info.volume_filter = str_list_split(volume_filter); - info.process_func = _keystore_process_cryptsetup; - - rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, -- _keystore_process_crypt, &info); -+ volume_type, _keystore_process_crypt, -+ &info); - - str_list_free_string_array(info.volume_filter); - -@@ -3376,10 +3635,12 @@ int keystore_cryptsetup(struct keystore - * The ':dm-name' part of the volume is optional - * for the volume filter. If not specified, the filter - * checks the volume part only. -+ * @param[in] volume_type the type of volume to generate crypttab entries for - * - * @returns 0 for success or a negative errno in case of an error - */ --int keystore_crypttab(struct keystore *keystore, const char *volume_filter) -+int keystore_crypttab(struct keystore *keystore, const char *volume_filter, -+ const char *volume_type) - { - struct crypt_info info = { 0 }; - int rc; -@@ -3388,11 +3649,19 @@ int keystore_crypttab(struct keystore *k - - if (volume_filter == NULL) - volume_filter = "*"; -+ -+ if (volume_type != NULL && -+ !_keystore_valid_volume_type(volume_type)) { -+ warnx("Invalid volume-type specified"); -+ return -EINVAL; -+ } -+ - info.volume_filter = str_list_split(volume_filter); - info.process_func = _keystore_process_crypttab; - - rc = _keystore_process_filtered(keystore, NULL, volume_filter, NULL, -- _keystore_process_crypt, &info); -+ volume_type, _keystore_process_crypt, -+ &info); - - str_list_free_string_array(info.volume_filter); - ---- a/zkey/keystore.h -+++ b/zkey/keystore.h -@@ -30,16 +30,17 @@ int keystore_generate_key(struct keystor - const char *description, const char *volumes, - const char *apqns, size_t sector_size, - size_t keybits, bool xts, const char *clear_key_file, -- int pkey_fd); -+ const char *volume_type, int pkey_fd); - - int keystore_import_key(struct keystore *keystore, const char *name, - const char *description, const char *volumes, - const char *apqns, size_t sector_size, -- const char *import_file); -+ const char *import_file, const char *volume_type); - - int keystore_change_key(struct keystore *keystore, const char *name, - const char *description, const char *volumes, -- const char *apqns, long int sector_size); -+ const char *apqns, long int sector_size, -+ const char *volume_type); - - int keystore_rename_key(struct keystore *keystore, const char *name, - const char *newname); -@@ -63,12 +64,14 @@ int keystore_remove_key(struct keystore - bool quiet); - - int keystore_list_keys(struct keystore *keystore, const char *name_filter, -- const char *volume_filter, const char *apqn_filter); -+ const char *volume_filter, const char *apqn_filter, -+ const char *volume_type); - - int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter, -- bool execute); -+ bool execute, const char *volume_type); - --int keystore_crypttab(struct keystore *keystore, const char *volume_filter); -+int keystore_crypttab(struct keystore *keystore, const char *volume_filter, -+ const char *volume_type); - - void keystore_free(struct keystore *keystore); - ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -75,30 +75,32 @@ key repository. - .BR generate | gen - .I secure\-key\-file - .RB [ \-\-keybits | \-k --.IB size ] -+.IR size ] - .RB [ \-\-xts | \-x ] - .RB [ \-\-clearkey | \-c --.IB clear\-key\-file ] -+.IR clear\-key\-file ] - .RB [ \-\-verbose | \-V ] - . - .PP - .B zkey - .BR generate | gen - .B \-\-name | \-N --.IB key-name -+.IR key-name - .RB [ \-\-description | \-d --.IB description ] -+.IR description ] - .RB [ \-\-volumes | \-l --.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.IR volume1:dmname1[,volume2:dmname2[,...]] ] - .RB [ \-\-apqns | \-a --.IB card1.domain1[,card2.domain2[,...]] ] -+.IR card1.domain1[,card2.domain2[,...]] ] - .RB [ \-\-sector-size | \-S --.IB bytes ] -+.IR bytes ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-keybits | \-k --.IB size ] -+.IR size ] - .RB [ \-\-xts | \-x ] - .RB [ \-\-clearkey | \-c --.IB clear\-key\-file ] -+.IR clear\-key\-file ] - .RB [ \-\-verbose | \-V ] - .PP - Use the -@@ -115,16 +117,16 @@ The generated secure key can either be s - or in the secure key repository. To store the generated secure key in a - file, specify the file name with option \fIsecure\-key\-file\fP. To store the - secure key in the secure key repository, specify the name of the key using the --.B --name -+.B \-\-name - option. When storing the secure key in a key repository, - additional information can be associated with a secure key using the --.B --description -+.B \-\-description - , --.B --volumes -+.B \-\-volumes - , --.B --apqns -+.B \-\-apqns - , or the --.B --sector-size -+.B \-\-sector-size - options. - . - .SS "Validating secure AES keys" -@@ -138,7 +140,7 @@ options. - .B zkey - .BR validate | val - .RB [ \-\-name | \-N --.IB key-name ] -+.IR key-name ] - .RB [ \-\-verbose | \-V ] - .PP - Use the -@@ -156,10 +158,10 @@ secure key repository. To validate a sec - the file name with option \fIsecure\-key\-file\fP. To validate secure keys - contained in the secure key repository, specify the name of the key - or a pattern containing wildcards using the --.B --name -+.B \-\-name - option. When wildcards are used you must quote the value. - If neither option \fIsecure\-key\-file\fP nor option --.B --name -+.B \-\-name - are specified, then all secure keys contained in the key repository - are validated. - . -@@ -171,15 +173,15 @@ are validated. - .RB [ \-\-to\-new | \-n ] - .RB [ \-\-from\-old | \-o ] - .RB [ \-\-output | \-f --.IB output\-file ] -+.IR output\-file ] - .RB [ \-\-verbose | \-V ] - .PP - .B zkey - .BR reencipher | re - .RB [ \-\-name | \-N --.IB key-name ] -+.IR key-name ] - .RB [ \-\-apqns | \-a --.IB card1.domain1[,card2.domain2[,...]] ] -+.IR card1.domain1[,card2.domain2[,...]] ] - .RB [ \-\-to\-new | \-n ] - .RB [ \-\-from\-old | \-o ] - .RB [ \-\-in-place | \-i ] -@@ -190,7 +192,7 @@ are validated. - Use the - .B reencipher - command to re-encipher an existing secure key with a new master key. --A secure key bust be re-enciphered when the master key of the CCA -+A secure key must be re-enciphered when the master key of the CCA - cryptographic adapter changes. - .PP - The CCA cryptographic adapter has three different registers to store -@@ -243,18 +245,18 @@ secure key repository. To re-encipher a - specify the file name with option \fIsecure\-key\-file\fP. To re-encipher - secure keys contained in the secure key repository, specify the name of the key - or a pattern containing wildcards using the --.B --name -+.B \-\-name - option. When wildcards are used you must quote the value. - You can also specify the --.B --apqns -+.B \-\-apqns - option to re-encipher those secure - keys which are associated with the specified cryptographic adapters (APQNs). - You can use wildcards for the APQN specification. - When wildcards are used you must quote the value. - If both option --.B --name -+.B \-\-name - and option --.B --apqns -+.B \-\-apqns - are specified then all secure keys - contained in the key repository that match both patterns are re-enciphered. - If all both options are omitted, then all secure keys contained in the key -@@ -265,7 +267,7 @@ performed \fBin-place\fP, or in \fBstage - .PP - \fB"In-place"\fP immediately replaces the secure key in the repository with - the re-enciphered secure key. Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is --performed in-place per default. You can use option \fB--in-place\fP to force an -+performed in-place per default. You can use option \fB\-\-in-place\fP to force an - in-place re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that - a secure key that was re-enciphered in-place from \fBCURRENT\fP to \fBNEW\fP - is no longer valid, until the new CCA master key has been made the current one. -@@ -273,9 +275,9 @@ is no longer valid, until the new CCA ma - \fBStaged\fP mode means that the re-enciphered secure key is stored in a - separate file in the secure key repository. Thus the current secure key is still - valid at this point. Once the new CCA master key has been set (made active), you --must rerun the reencipher command with option \fB--complete\fP to complete the -+must rerun the reencipher command with option \fB\-\-complete\fP to complete the - staged re-enciphering. Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is --performed in staged mode per default. You can use option \fB--staged\fP to force -+performed in staged mode per default. You can use option \fB\-\-staged\fP to force - a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case. - .PP - .B Note: -@@ -288,15 +290,17 @@ to be installed. - .BR import | im - .I secure\-key\-file - .B \-\-name | \-N --.IB key-name -+.IR key-name - .RB [ \-\-description | \-d --.IB description ] -+.IR description ] - .RB [ \-\-volumes | \-l --.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.IR volume1:dmname1[,volume2:dmname2[,...]] ] - .RB [ \-\-apqns | \-a --.IB card1.domain1[,card2.domain2[,...]] ] -+.IR card1.domain1[,card2.domain2[,...]] ] - .RB [ \-\-sector-size | \-S --.IB bytes ] -+.IR bytes ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-verbose | \-V ] - . - .PP -@@ -305,13 +309,13 @@ Use the - command to import an existing secure key contained in a file into the the - secure key repository. When importing a secure key in a key repository, - additional information can be associated with a secure key using the --.B --description -+.B \-\-description - , --.B --volumes -+.B \-\-volumes - , --.B --apqns -+.B \-\-apqns - , or the --.B --sector-size -+.B \-\-sector-size - options. - . - .SS "Export AES secure keys from the secure key repository" -@@ -320,7 +324,7 @@ options. - .BR export | ex - .I secure\-key\-file - .B \-\-name | \-N --.IB key-name -+.IR key-name - .RB [ \-\-verbose | \-V ] - . - .PP -@@ -329,7 +333,7 @@ Use the - command to export an existing secure key contained in the secure key repository - to a file in the file system. Specify the name of the key that is to be exported - using the --.B --name -+.B \-\-name - option. You cannot use wildcards. - When wildcards are used you must quote the value. - The exported secure key also remains in the secure key repository. -@@ -339,20 +343,22 @@ The exported secure key also remains in - .B zkey - .BR list | li - .RB [ \-\-name | \-N --.IB key-name ] -+.IR key-name ] - .RB [ \-\-volumes | \-l --.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.IR volume1[:dmname1][,volume2[:dmname2][,...]] ] - .RB [ \-\-apqns | \-a --.IB card1.domain1[,card2.domain2[,...]] ] -+.IR card1.domain1[,card2.domain2[,...]] ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-verbose | \-V ] - . - .PP - Use the - .B list - command to display a list of secure keys contained in the secure key repository. --You can filter the displayed list by key name, associated volumes, and --associated cryptographic adapters (APQNs). You can use wildcards for the key --name, associated APQNs, and associated volumes. The device-mapper name of an -+You can filter the displayed list by key name, associated volumes, associated -+cryptographic adapters (APQNs), and volume type. You can use wildcards for the -+key name, associated APQNs, and associated volumes. The device-mapper name of an - associated volume can be omitted; if it is specified then only those keys are - listed that are associated with the specified volume and device-mapper name. - .PP -@@ -369,7 +375,7 @@ modification and last re-encipherment. - .B zkey - .BR remove | rem - .B \-\-name | \-N --.IB key-name -+.IR key-name - .RB [ \-\-force | \-F ] - .RB [ \-\-verbose | \-V ] - . -@@ -378,10 +384,10 @@ Use the - .B remove - command to remove an existing secure key from the secure key repository. - Specify the name of the key that is to be removed using the --.B --name -+.B \-\-name - option. You cannot use wildcards. The remove command prompts for - a confirmation, unless you specify the --.B --force -+.B \-\-force - option. - .PP - .B Note: -@@ -395,43 +401,45 @@ secure key. - .B zkey - .BR change | ch - .B \-\-name | \-N --.IB key-name -+.IR key-name - .RB [ \-\-description | \-d --.IB description ] -+.IR description ] - .RB [ \-\-volumes | \-l --.IB [+|-]volume1:dmname1[,volume2:dmname2[,...]] ] -+.IR [+|-]volume1:dmname1[,volume2:dmname2[,...]] ] - .RB [ \-\-apqns | \-a --.IB [+|-]card1.domain1[,card2.domain2[,...]] ] -+.IR [+|-]card1.domain1[,card2.domain2[,...]] ] - .RB [ \-\-sector-size | \-S --.IB bytes ] -+.IR bytes ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-verbose | \-V ] - . - .PP - Use the - .B change - command to change the description, the associated volumes, the associated --cryptographic adapters (APQNs), and the sector size of a secure key contained --in the secure key repository. Specify the name of the key that is to be changed --using the --.B --name -+cryptographic adapters (APQNs), the sector size, and the volume type of a secure -+key contained in the secure key repository. Specify the name of the key that is -+to be changed using the -+.B \-\-name - option. You cannot use wildcards. - .PP - You can set (replace), add, or - remove volume and cryptographic adapters (APQN) associations. To set - (replace) an association, specify the association with the --.B --volumes -+.B \-\-volumes - or the --.B --apqns -+.B \-\-apqns - options. To add an association, - specify the new association prefixed with a \fI+\fP with the --.B --volumes -+.B \-\-volumes - or the --.B --apqns -+.B \-\-apqns - options. To remove an association, - specify the association to remove prefixed with a \fI-\fP with the --.B --volumes -+.B \-\-volumes - or the --.B --apqns -+.B \-\-apqns - options. You cannot mix \fI+\fP and - \fI-\fP in one specification. You can either add or remove (or set) the - associations with one command. -@@ -447,9 +455,9 @@ command. - .B zkey - .BR rename | ren - .B \-\-name | \-N --.IB key-name -+.IR key-name - .B \-\-new-name | \-w --.IB new-key-name -+.IR new-key-name - .RB [ \-\-verbose | \-V ] - . - .PP -@@ -457,9 +465,9 @@ Use the - .B rename - command to rename an existing secure key in the secure key repository. - Specify the name of the key that is to be renamed using the --.B --name -+.B \-\-name - option and the new name using the --.B --new-name -+.B \-\-new-name - option. You cannot use wildcards. - . - .SS "Copy (duplicate) existing AES secure keys in the secure key repository" -@@ -467,11 +475,11 @@ option. You cannot use wildcards. - .B zkey - .B copy | co - .RB \-\-name | \-N --.IB key-name -+.IR key-name - .B \-\-new-key-name | \-w --.IB new-name -+.IR new-name - .RB [ \-\-volumes | \-l --.IB volume1:dmname1[,volume2:dmname2[,...]] ] -+.IR volume1:dmname1[,volume2:dmname2[,...]] ] - .RB [ \-\-verbose | \-V ] - . - .PP -@@ -479,15 +487,15 @@ Use the - .B copy - command to copy (duplicate) an existing secure key in the secure key repository. - Specify the name of the key that is to be copied using the --.B --name -+.B \-\-name - option and the name of the copied key using the --.B --new-name -+.B \-\-new-name - option. You cannot use wildcards. - .PP - .B Note: - When copying a secure key, the volume associations are not copied, because - a specific volume can only be associated with a single secure key. Specify the --.B --volumes -+.B \-\-volumes - option to associate different - volumes with the copied secure key, or use the \fBchange\fP command to associate - volumes afterwards. -@@ -497,45 +505,56 @@ volumes afterwards. - .B zkey - .BR crypttab | cryptt - .RB [ \-\-volumes | \-l --.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.IR volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-verbose | \-V ] - . - .PP - Use the - .B crypttab --command to generate crypttab entries using the \fBplain\fP dm-crypt mode --for volumes that are associated with secure keys contained in the secure key --repository. Specify the --.B --volumes -+command to generate crypttab entries using the \fBplain\fP or \fBLUKS2\fP -+dm-crypt mode for volumes that are associated with secure keys contained in the -+secure key repository. Specify the -+.B \-\-volumes - option to limit the list - of volumes where crypttab entries are generated for. You can use wildcards. - When wildcards are used you must quote the value. - The device-mapper name of an associated volume can be omitted; if it is - specified then only those volumes with the specified volume and device-mapper - name are selected. -+Specify the -+.B \-\-volume-type -+option to generate crypttab entries for the specified volume type only. - . - .SS "Generate cryptsetup commands for volumes associated with secure AES keys" - . - .B zkey - .BR cryptsetup | crypts - .RB [ \-\-volumes | \-l --.IB volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.IR volume1[:dmname1][,volume2[:dmname2][,...]] ] -+.RB [ \-\-volume-type | \-t -+.IR type ] - .RB [ \-\-run | \-r ] - .RB [ \-\-verbose | \-V ] - . - .PP - Use the - .B cryptsetup --command to generate \fBcryptsetup plainOpen\fP commands for volumes that are --associated with secure keys contained in the secure key repository. Specify the --.B --volumes -+command to generate \fBcryptsetup plainOpen\fP or \fBcryptsetup luksFormat\fP -+commands for volumes that are associated with secure keys contained in the -+secure key repository. Specify the -+.B \-\-volumes - option to limit the list - of volumes where cryptsetup commands are generated for. You can use wildcards. - When wildcards are used you must quote the value. - The device-mapper name of an associated volume can be omitted; if it is - specified then only those volumes with the specified volume and device-mapper - name are selected. Specify the --.B --run -+.B \-\-volume-type -+option to generate cryptsetup commands for the specified volume type only. -+Specify the -+.B \-\-run - option to run the generated cryptsetup commands. - . - . -@@ -589,8 +608,17 @@ This option is only used for secure keys - .TP - .BR \-S ", " \-\-sector-size\~\fIbytes\fP - Specifies the sector size in bytes used with dm-crypt. It must be a power of two --and in the range 512 - 4096 bytes. If omitted, the system default sector size --is used. -+and in the range of 512 to 4096 bytes. If omitted, the system default sector -+size is used. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is used. -+This option is only available if -+.B zkey -+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. - . - . -@@ -650,7 +678,7 @@ repository is performed in staged mode. - secure key is stored in a separate file in the secure key repository. Thus the - current secure key is still valid at this point. Once the new CCA master key has - been set (made active), you must rerun the reencipher command with option --\fB--complete\fP to complete the staged re-enciphering. -+\fB\-\-complete\fP to complete the staged re-enciphering. - Re-enciphering from CURRENT to NEW is performed in staged mode per default. - This option is only used for secure keys contained in the secure key repository. - .TP -@@ -690,8 +718,17 @@ This option is only used for secure keys - .TP - .BR \-S ", " \-\-sector-size\~\fIbytes\fP - Specifies the sector size in bytes used with dm-crypt. It must be a power of two --and in the range 512 - 4096 bytes. If omitted, the system default sector size --is used. -+and in the range of 512 to 4096 bytes. If omitted, the system default sector -+size is used. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. If omitted, \fBluks2\fP is used. -+This option is only available if -+.B zkey -+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. - . - . -@@ -734,6 +771,15 @@ APQNs. Each APQN association specifies a - by a period (like lszcrypt displays it). You can use wildcards in the APQN - specification. - This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume -+type are listed. -+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. - . - . - . -@@ -791,9 +837,16 @@ This option is only used for secure keys - .TP - .BR \-S ", " \-\-sector-size\~\fIbytes\fP - Specifies the sector size in bytes used with dm-crypt. It must be a power of two --and in the range 512 - 4096 bytes. If omitted, the system default sector size --is used. Specify \fI0\fP to un-set the sector size so that the system default --is used. -+and in the range of 512 to 4096 bytes. Specify \fI0\fP to set the sector size -+to the system default. -+This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. -+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. - . - . -@@ -845,6 +898,15 @@ specified volume and device-mapper name. - the volumes and device-mapper names. - When wildcards are used you must quote the value. - This option is only used for secure keys contained in the secure key repository. -+.TP -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume -+type are selected to generate crypttab entries for. -+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. - . - . - . -@@ -861,10 +923,18 @@ the volumes and device-mapper names. - When wildcards are used you must quote the value. - This option is only used for secure keys contained in the secure key repository. - .TP --.BR \-r ", " \-\-run\fP --Runs the generated cryptsetup commands. When an execution of a cryptsetup --command fails, no further cryptsetup commands are executed, and zkey ends --with an error. -+.BR \-t ", " \-\-volume-type\~\fItype\fP -+Specifies the volume type of the associated volumes used with dm-crypt. Possible -+values are \fBplain\fP and \fBluks2\fP. Only keys with the specified volume -+type are selected to generate cryptsetup commands for. -+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 \-r ", " \-\-run -+Runs the generated cryptsetup commands. When one of the cryptsetup command fail, -+no further cryptsetup commands are run, and zkey ends with an error. - This option is only used for secure keys contained in the secure key repository. - . - . -@@ -895,15 +965,20 @@ in file 'seckey.bin'. - Generates a secure AES key from the clear key in file 'clearkey.bin' and - stores it in file 'seckey.bin'. - .TP --.B zkey generate --name seckey -+.B zkey generate \-\-name seckey - Generates a random 256-bit secure AES key and stores it in the secure key --repository under the name 'seckey'. -+repository using the name 'seckey'. - .TP --.B zkey generate --name seckey --volumes /dev/dasdc1:encvol --apqns 03.004c -+.B zkey generate \-\-name seckey \-\-volumes /dev/dasdc1:encvol \-\-apqns 03.004c - Generates a random 256-bit secure AES key and stores it in the secure key --repository under the name 'seckey' and associates it with block -+repository using the name 'seckey' and associates it with block - device '/dev/dasdc1' and device-mapper name 'encvol', and APQN '03.004c'. - .TP -+.B zkey generate \-\-name seckey \-\-volumes /dev/dasdc1:encvol \-\-volume-type luks2 -+Generates a random 256-bit secure AES key and stores it in the secure key -+repository using the name 'seckey' and associates it with block -+device '/dev/dasdc1' and device-mapper name 'encvol', and a volume type of luks2. -+.TP - .B zkey reencipher seckey.bin \-\-from\-old - Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered - with the master key in the OLD register with the master key in the CURRENT -@@ -915,17 +990,17 @@ Re-enciphers the secure key in file 'sec - with the master key in the CURRENT register with the master key in the NEW - register, and saves the re-enciphered secure key to file 'seckey2.bin'. - .TP --.B zkey reencipher --name seckey -+.B zkey reencipher \-\-name seckey - Re-enciphers the secure key 'seckey' in the secure key repository. - .TP --.B zkey reencipher --apqns 03.004c -+.B zkey reencipher \-\-apqns 03.004c - Re-enciphers all secure keys contained in the secure key repository that are - associated with APQN '03.004c'. - .TP - .B zkey validate seckey.bin - Validates the secure key in file 'seckey.bin' and displays its attributes. - .TP --.B zkey validate --name seckey -+.B zkey validate \-\-name seckey - Validates the secure key 'seckey' in the secure key repository and displays its - attributes. - .TP -@@ -933,25 +1008,28 @@ attributes. - Lists all secure keys in the secure key repository and displays its - attributes. - .TP --.B zkey list --name '*key' -+.B zkey list \-\-name '*key' - Lists all secure keys in the secure key repository with names ending with 'key' - and displays its attributes. - .TP --.B zkey change --name seckey --volumes +/dev/dasdc2:encvol2 -+.B zkey change \-\-name seckey \-\-volumes +/dev/dasdc2:encvol2 - Changes the secure key 'seckey' in the secure key repository and adds - volume '/dev/dasdc2' with device-mapper name 'encvol2' to the list of associated - volumes of this secure key. - .TP --.B zkey change --name seckey --apqns -03.004c -+.B zkey change \-\-name seckey \-\-apqns -03.004c - Changes the secure key 'seckey' in the secure key repository and removes - APQN '03.004c' from the list of associated APQNs of this secure key. - .TP --.B zkey crypttab --volumes '/dev/dasdc*' -+.B zkey crypttab \-\-volumes '/dev/dasdc*' - Generates crypttab entries for all volumes that match the pattern '/dev/dasdc*'. - .TP --.B zkey cryptsetup --volumes '*:enc_dasd' -+.B zkey cryptsetup \-\-volumes '*:enc_dasd' - Generates cryptsetup commands for the volumes that uses the device-mapper - name 'enc_dasd'. -+.TP -+.B zkey cryptsetup \-\-volume-type luks2 -+Generates cryptsetup commands for all volumes of type luks2. - . - .SH ENVIRONMENT - .TP ---- a/zkey/zkey.c -+++ b/zkey/zkey.c -@@ -68,6 +68,7 @@ static struct zkey_globals { - char *volumes; - char *apqns; - long int sector_size; -+ char *volume_type; - char *newname; - bool run; - bool force; -@@ -180,6 +181,16 @@ static struct util_opt opt_vec[] = { - "used", - .command = COMMAND_GENERATE, - }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. When this option is omitted, " -+ "the default is 'luks2'", -+ .command = COMMAND_GENERATE, -+ }, -+#endif - /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, -@@ -211,19 +222,23 @@ static struct util_opt opt_vec[] = { - }, - { - .option = {"complete", 0, NULL, 'p'}, -- .desc = "Completes a pending re-enciphering of a secure AES " -- "key that was re-enciphered with the master key in the " -- "NEW register", -+ .desc = "Completes a staged re-enciphering. Use this option " -+ "after the new CCA master key has been set (made " -+ "active)", - .command = COMMAND_REENCIPHER, - }, - { - .option = {"in-place", 0, NULL, 'i'}, -- .desc = "Forces an in-place re-enchipering of a secure AES key", -+ .desc = "Forces an in-place re-enchipering of a secure AES " -+ "key. Re-enciphering from OLD to CURRENT is performed " -+ "in-place per default", - .command = COMMAND_REENCIPHER, - }, - { - .option = {"staged", 0, NULL, 's'}, -- .desc = "Forces a staged re-enchipering of a secure AES key", -+ .desc = "Forces that the re-enciphering of a secure AES key is " -+ "performed in staged mode. Re-enciphering from CURRENT " -+ "to NEW is performed in staged mode per default", - .command = COMMAND_REENCIPHER, - }, - { -@@ -310,6 +325,16 @@ static struct util_opt opt_vec[] = { - "used", - .command = COMMAND_IMPORT, - }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. When this option is omitted, " -+ "the default is 'luks2'", -+ .command = COMMAND_IMPORT, -+ }, -+#endif - /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, -@@ -358,6 +383,16 @@ static struct util_opt opt_vec[] = { - "associated with specific crypto cards", - .command = COMMAND_LIST, - }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. Use this option to list all " -+ "keys with the specified volumes type.", -+ .command = COMMAND_LIST, -+ }, -+#endif - /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, -@@ -422,11 +457,19 @@ static struct util_opt opt_vec[] = { - .option = { "sector-size", required_argument, NULL, 'S'}, - .argument = "0|512|4096", - .desc = "The sector size used with dm-crypt. It must be power " -- "of two and in range 512 - 4096 bytes. If this option " -- "is omitted, the system default sector size (512) is " -- "used", -+ "of two and in range 512 - 4096 bytes. Specify 0 to " -+ "use the system default sector size (512)", -+ .command = COMMAND_CHANGE, -+ }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'", - .command = COMMAND_CHANGE, - }, -+#endif - /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, -@@ -494,6 +537,17 @@ static struct util_opt opt_vec[] = { - "volume and the device-mapper name matches", - .command = COMMAND_CRYPTTAB, - }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. Use this option to select " -+ "the keys by its volume type for which a crypttab " -+ "entry is to be generated", -+ .command = COMMAND_CRYPTTAB, -+ }, -+#endif - /***********************************************************/ - { - .flags = UTIL_OPT_FLAG_SECTION, -@@ -512,6 +566,17 @@ static struct util_opt opt_vec[] = { - "both, the volume and the device-mapper name matches", - .command = COMMAND_CRYPTSETUP, - }, -+#ifdef HAVE_LUKS2_SUPPORT -+ { -+ .option = { "volume-type", required_argument, NULL, 't'}, -+ .argument = "type", -+ .desc = "The type of the associated volume(s). Possible values " -+ "are 'plain' and 'luks2'. Use this option to select " -+ "the keys by its volume type for which a crypttab " -+ "entry is to be generated", -+ .command = COMMAND_CRYPTSETUP, -+ }, -+#endif - { - .option = {"run", 0, NULL, 'r'}, - .desc = "Runs the generated cryptsetup command", -@@ -819,7 +884,7 @@ static int command_generate_repository(v - - rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes, - g.apqns, g.sector_size, g.keybits, g.xts, -- g.clearkeyfile, g.pkey_fd); -+ g.clearkeyfile, g.volume_type, g.pkey_fd); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1167,7 +1232,8 @@ static int command_import(void) - g.sector_size = 0; - - rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes, -- g.apqns, g.sector_size, g.pos_arg); -+ g.apqns, g.sector_size, g.pos_arg, -+ g.volume_type); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1200,7 +1266,8 @@ static int command_list(void) - { - int rc; - -- rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns); -+ rc = keystore_list_keys(g.keystore, g.name, g.volumes, g.apqns, -+ g.volume_type); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1239,7 +1306,7 @@ static int command_change(void) - } - - rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes, -- g.apqns, g.sector_size); -+ g.apqns, g.sector_size, g.volume_type); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1299,7 +1366,7 @@ static int command_crypttab(void) - { - int rc; - -- rc = keystore_crypttab(g.keystore, g.volumes); -+ rc = keystore_crypttab(g.keystore, g.volumes, g.volume_type); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1313,7 +1380,7 @@ static int command_cryptsetup(void) - { - int rc; - -- rc = keystore_cryptsetup(g.keystore, g.volumes, g.run); -+ rc = keystore_cryptsetup(g.keystore, g.volumes, g.run, g.volume_type); - - return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -1490,6 +1557,11 @@ int main(int argc, char *argv[]) - return EXIT_FAILURE; - } - break; -+#ifdef HAVE_LUKS2_SUPPORT -+ case 't': -+ g.volume_type = optarg; -+ break; -+#endif - case 'w': - g.newname = optarg; - break; diff --git a/s390-tools-sles15sp1-01-chzcrypt-Corrections-at-the-chzcrypt-man-page.patch b/s390-tools-sles15sp1-01-chzcrypt-Corrections-at-the-chzcrypt-man-page.patch deleted file mode 100644 index 9f7a67f..0000000 --- a/s390-tools-sles15sp1-01-chzcrypt-Corrections-at-the-chzcrypt-man-page.patch +++ /dev/null @@ -1,54 +0,0 @@ -Subject: zcrypt: Corrections at the chzcrypt man page. -From: Harald Freudenberger - -Summary: lszcrypt: support for alternate zcrypt device drivers -Description: With kernel 4.19 there comes an extension to the - existing AP bus which supports alternate zcrypt - drivers. For details about this see kernel patch - "s390/zcrypt: AP bus support for alternate - driver(s)". So now lszcrypt displays the driver name - in verbose mode. As some of the information - displayed by lszcrypt was based on sysfs attributes, - which are only available when the default zcrypt - driver is bound to the device, this also needed some - rework. If a sysfs attribute is not available - because of an alternate driver binding (or no - driver) a question mark is printed into the field. -Upstream-ID: 13648dd6f424bdbf855cd756e3039c8d4e9fd944 -Problem-ID: SEC1806 - -Upstream-Description: - - zcrypt: Corrections at the chzcrypt man page. - - Fixed typo and added one sentence to explain more details - about online switching of queue devices. - - Signed-off-by: Harald Freudenberger - Signed-off-by: Jan Höppner - - -Signed-off-by: Harald Freudenberger ---- - zconf/zcrypt/chzcrypt.8 | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - ---- a/zconf/zcrypt/chzcrypt.8 -+++ b/zconf/zcrypt/chzcrypt.8 -@@ -57,6 +57,7 @@ Set all available cryptographic device(s - .B - Specifies a cryptographic device which will be set either online or offline. - The device can either be a card device or a queue device. -+A queue device can only get switched online when the providing card is online. - - Please note that the card device and queue device representation are both - in hexadecimal notation. -@@ -95,7 +96,7 @@ Print version information and exit. - .B chzcrypt -e 0 1 12 - Will set the cryptographic card devices 0, 1 and 12 online. - .TP --.B chzcrypt -e 01.0038 -+.B chzcrypt -e 10.0038 - Will set the cryptographic device '10.0038' respectively card id 16 - (0x10) with domain 56 (0x38) online. - .TP diff --git a/s390-tools-sles15sp1-01-cpumf-Add-extended-counter-defintion-files-for-IBM-z.patch b/s390-tools-sles15sp1-01-cpumf-Add-extended-counter-defintion-files-for-IBM-z.patch deleted file mode 100644 index cf3a362..0000000 --- a/s390-tools-sles15sp1-01-cpumf-Add-extended-counter-defintion-files-for-IBM-z.patch +++ /dev/null @@ -1,361 +0,0 @@ -Subject: cpumf: Add extended counter defintion files for IBM z14 -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: 57f18c5f59766832822a74cc029a8d3b60e3ba0f -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf: Add extended counter defintion files for IBM z14 - - Signed-off-by: Martin Schwidefsky - [brueckner: Prefer plural for counter names] - Signed-off-by: Hendrik Brueckner - Signed-off-by: Stefan Haberland - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/Makefile | 2 - cpumf/bin/cpumf_helper.in | 1 - cpumf/data/cpum-cf-extended-z14.ctr | 303 ++++++++++++++++++++++++++++++++++++ - cpumf/data/cpum-cf-hw-counter.map | 1 - 4 files changed, 306 insertions(+), 1 deletion(-) - ---- a/cpumf/Makefile -+++ b/cpumf/Makefile -@@ -7,7 +7,7 @@ CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf - DATA_FILES = cpum-cf-hw-counter.map cpum-cf-generic.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-z13.ctr cpum-cf-extended-z14.ctr - LIB_FILES = bin/cpumf_helper - USRBIN_SCRIPTS = bin/lscpumf - USRSBIN_SCRIPTS = bin/chcpumf ---- a/cpumf/bin/cpumf_helper.in -+++ b/cpumf/bin/cpumf_helper.in -@@ -210,6 +210,7 @@ my $system_z_hwtype_map = { - 2828 => 'IBM zEnterprise BC12', - 2964 => 'IBM z13', - 2965 => 'IBM z13s', -+ 3906 => 'IBM z14', - }; - - sub get_hardware_type() ---- /dev/null -+++ b/cpumf/data/cpum-cf-extended-z14.ctr -@@ -0,0 +1,303 @@ -+# 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_WRITES_RO_EXCL -+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 -+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 -+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 -+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 or a -+Last Host Translation was done -+. -+Counter:132 Name:DTLB2_GPAGE_WRITES -+Description: -+A translation entry for a two-gigabyte page was written into the -+Level-2 TLB -+. -+Counter:133 Name: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 -+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 -+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 -+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 -+Description: -+A translation entry was written into the Page Table Entry array in the -+Level-2 TLB -+. -+Counter:138 Name: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 -+Description: -+The number of Level-2 TLB translation engines busy in a cycle -+. -+Counter:140 Name:TX_C_TEND -+Description: -+A TEND instruction has completed in a constrained transactional-execution -+mode -+. -+Counter:141 Name:TX_NC_TEND -+Description: -+A TEND instruction has completed in a non-constrained -+transactional-execution mode -+. -+Counter:143 Name: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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+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 -+Description: -+Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED, -+EDMK, MP, SRP, SP, ZAP -+. -+Counter:233 Name:LAST_HOST_TRANSLATIONS -+Description: -+Last Host Translation done -+. -+Counter:243 Name:TX_NC_TABORT -+Description: -+A transaction abort has occurred in a non-constrained -+transactional-execution mode -+. -+Counter:244 Name:TX_C_TABORT_NO_SPECIAL -+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 -+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 -+. -+# -+# MT-diagnostic counter set -+# --------------------------------------------------------------------- -+Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE -+Description: -+Cycle count with one thread active -+. -+Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE -+Description: -+Cycle count with two threads active -+. ---- a/cpumf/data/cpum-cf-hw-counter.map -+++ b/cpumf/data/cpum-cf-hw-counter.map -@@ -14,4 +14,5 @@ - 2828 => 'cpum-cf-extended-zEC12.ctr', - 2964 => 'cpum-cf-extended-z13.ctr', - 2965 => 'cpum-cf-extended-z13.ctr', -+ 3906 => 'cpum-cf-extended-z14.ctr', - }; diff --git a/s390-tools-sles15sp1-01-lszcrypt-CEX6S-exploitation.patch b/s390-tools-sles15sp1-01-lszcrypt-CEX6S-exploitation.patch deleted file mode 100644 index f2f281c..0000000 --- a/s390-tools-sles15sp1-01-lszcrypt-CEX6S-exploitation.patch +++ /dev/null @@ -1,124 +0,0 @@ -Subject: lszcrypt: CEX6S exploitation -From: Harald Freudenberger - -Summary: s390-tools: Exploitation Support for CEX6S -Description: Exploitation Support for CEX6S -Upstream-ID: 31866fbfa4bd89606af2a313427ca06d230e20dc -Problem-ID: SEC1519 - -Upstream-Description: - - lszcrypt: CEX6S exploitation - - With z14 there comes a new crypto card 'CEX6S'. - - This patch introduces the s390-tools changes needed - to list the new card and show the capabilities correctly. - - Signed-off-by: Harald Freudenberger - Signed-off-by: Michael Holzheu - - -Signed-off-by: Harald Freudenberger ---- - zconf/zcrypt/lszcrypt.8 | 6 ++++++ - zconf/zcrypt/lszcrypt.c | 37 ++++++++++++++++++++++++++++--------- - 2 files changed, 34 insertions(+), 9 deletions(-) - ---- a/zconf/zcrypt/lszcrypt.8 -+++ b/zconf/zcrypt/lszcrypt.8 -@@ -85,6 +85,12 @@ EP11 Secure Key - .IP "o" - Long RNG - .RE -+ -+.RS 8 -+The CCA Secure Key capability may be limited by a hypervisor -+layer. The remarks 'full function set' or 'restricted function set' may -+reflect this. For details about these limitations please check the -+hypervisor documentation. - .TP 8 - .B -d, --domains - Shows the usage and control domains of the cryptographic devices. ---- a/zconf/zcrypt/lszcrypt.c -+++ b/zconf/zcrypt/lszcrypt.c -@@ -42,11 +42,19 @@ struct lszcrypt_l *lszcrypt_l = &l; - /* - * Card types - */ --#define MASK_APSC 0x80000000 --#define MASK_RSA4K 0x60000000 --#define MASK_COPRO 0x10000000 --#define MASK_ACCEL 0x08000000 --#define MASK_EP11 0x04000000 -+#define MASK_APSC 0x80000000 -+#define MASK_RSA4K 0x60000000 -+#define MASK_COPRO 0x10000000 -+#define MASK_ACCEL 0x08000000 -+#define MASK_EP11 0x04000000 -+ -+/* -+ * Classification -+ */ -+#define MASK_CLASS_FULL 0x00800000 -+#define CLASS_FULL "full function set" -+#define MASK_CLASS_STATELESS 0x00400000 -+#define CLASS_STATELESS "restricted function set" - - /* - * Program configuration -@@ -226,7 +234,7 @@ static void show_capability(const char * - { - unsigned long func_val; - long hwtype, id; -- char *p, *ap, *dev, card[16]; -+ char *p, *ap, *dev, card[16], cbuf[256]; - - /* check if ap driver is available */ - ap = util_path_sysfs("bus/ap"); -@@ -250,6 +258,11 @@ static void show_capability(const char * - printf("Detailed capability information for %s (hardware type %ld) is not available.\n", card, hwtype); - return; - } -+ cbuf[0] = '\0'; -+ if (func_val & MASK_CLASS_FULL) -+ snprintf(cbuf, sizeof(cbuf), "%s", CLASS_FULL); -+ else if (func_val & MASK_CLASS_STATELESS) -+ snprintf(cbuf, sizeof(cbuf), "%s", CLASS_STATELESS); - printf("%s provides capability for:\n", card); - switch (hwtype) { - case 6: -@@ -262,11 +275,15 @@ static void show_capability(const char * - case 7: - case 9: - printf("%s\n", CAP_RSA4K); -- printf("%s\n", CAP_CCA); -+ if (cbuf[0]) -+ printf("%s (%s)\n", CAP_CCA, cbuf); -+ else -+ printf("%s\n", CAP_CCA); - printf("%s", CAP_RNG); - break; - case 10: - case 11: -+ case 12: - if (func_val & MASK_ACCEL) { - if (func_val & MASK_RSA4K) - printf("%s", CAP_RSA4K); -@@ -274,12 +291,14 @@ static void show_capability(const char * - printf("%s", CAP_RSA2K); - } else if (func_val & MASK_COPRO) { - printf("%s\n", CAP_RSA4K); -- printf("%s\n", CAP_CCA); -+ if (cbuf[0]) -+ printf("%s (%s)\n", CAP_CCA, cbuf); -+ else -+ printf("%s\n", CAP_CCA); - printf("%s", CAP_RNG); - } else if (func_val & MASK_EP11) { - printf("%s", CAP_EP11); - } else { -- - printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype); - } - break; diff --git a/s390-tools-sles15sp1-01-util_path-add-function-to-check-if-a-path-exists.patch b/s390-tools-sles15sp1-01-util_path-add-function-to-check-if-a-path-exists.patch deleted file mode 100644 index 74785a4..0000000 --- a/s390-tools-sles15sp1-01-util_path-add-function-to-check-if-a-path-exists.patch +++ /dev/null @@ -1,55 +0,0 @@ -Subject: util_path: add function to check if a path exists -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: df133846b5889a7698ac09f00284c1be54926b59 -Problem-ID: RAS1703 - -Upstream-Description: - - util_path: add function to check if a path exists - - GitHub-ID: #20 - - Signed-off-by: Rafael Fonseca - Acked-by: Michael Holzheu - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jan Hoeppner ---- - include/lib/util_path.h | 1 + - libutil/util_path.c | 12 ++++++++++++ - 2 files changed, 13 insertions(+) - ---- a/include/lib/util_path.h -+++ b/include/lib/util_path.h -@@ -20,5 +20,6 @@ bool util_path_is_readable(const char *f - bool util_path_is_writable(const char *fmt, ...); - bool util_path_is_dir(const char *fmt, ...); - bool util_path_is_reg_file(const char *fmt, ...); -+bool util_path_exists(const char *fmt, ...); - - #endif /** LIB_UTIL_PATH_H @} */ ---- a/libutil/util_path.c -+++ b/libutil/util_path.c -@@ -194,3 +194,15 @@ free_str: - free(path); - return rc; - } -+ -+bool util_path_exists(const char *fmt, ...) -+{ -+ va_list ap; -+ char *path; -+ bool rc; -+ -+ UTIL_VASPRINTF(&path, fmt, ap); -+ rc = access(path, F_OK) == 0; -+ free(path); -+ return rc; -+} diff --git a/s390-tools-sles15sp1-01-zcryptctl-new-tool-zcryptctl-for-multiple-zcrypt-node.patch b/s390-tools-sles15sp1-01-zcryptctl-new-tool-zcryptctl-for-multiple-zcrypt-node.patch deleted file mode 100644 index 59febf8..0000000 --- a/s390-tools-sles15sp1-01-zcryptctl-new-tool-zcryptctl-for-multiple-zcrypt-node.patch +++ /dev/null @@ -1,1246 +0,0 @@ -Subject: zcryptctl: new tool zcryptctl for multiple zcrypt node management -From: Harald Freudenberger - -Summary: zcryptctl: new tool zcryptctl for multiple zcrypt node -Description: There is a new zcrypt kernel feature which provides - multiple customizable device nodes for the zcrypt - device driver. Here is the userspace part of this - which adds a new application zcryptctl for user - friendly management of this feature. -Upstream-ID: f05f7d656b13c3904f0c55e86ebe9e9b19fcd222 -Problem-ID: SEC1710 - -Upstream-Description: - - zcryptctl: new tool zcryptctl for multiple zcrypt node management - - With the latest kernel comes an extension for the zcrypt - device driver to support multiple zcrypt device nodes. - - Here is the userspace part of this which adds a new - application zcryptctl for user friendly management of - this feature. - - Signed-off-by: Harald Freudenberger - Signed-off-by: Jan Höppner - - -Signed-off-by: Harald Freudenberger ---- - zconf/zcrypt/Makefile | 7 - zconf/zcrypt/zcryptctl.8 | 147 ++++++ - zconf/zcrypt/zcryptctl.c | 1030 +++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 1182 insertions(+), 2 deletions(-) - ---- a/zconf/zcrypt/Makefile -+++ b/zconf/zcrypt/Makefile -@@ -1,21 +1,24 @@ - include ../../common.mak - --all: chzcrypt lszcrypt -+all: chzcrypt lszcrypt zcryptctl - - libs = $(rootdir)/libutil/libutil.a - - chzcrypt: chzcrypt.o misc.o $(libs) - lszcrypt: lszcrypt.o misc.o $(libs) -+zcryptctl: zcryptctl.o misc.o $(libs) - - install: all - $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 chzcrypt $(DESTDIR)$(BINDIR) - $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 lszcrypt $(DESTDIR)$(BINDIR) -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zcryptctl $(DESTDIR)$(BINDIR) - $(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8 - $(INSTALL) -m 644 -c chzcrypt.8 $(DESTDIR)$(MANDIR)/man8 - $(INSTALL) -m 644 -c lszcrypt.8 $(DESTDIR)$(MANDIR)/man8 -+ $(INSTALL) -m 644 -c zcryptctl.8 $(DESTDIR)$(MANDIR)/man8 - - clean: -- rm -f *.o chzcrypt lszcrypt -+ rm -f *.o chzcrypt lszcrypt zcryptctl - - .PHONY: all install clean ---- /dev/null -+++ b/zconf/zcrypt/zcryptctl.8 -@@ -0,0 +1,147 @@ -+.\" zcryptctl.8 -+.\" -+.\" Copyright 2018 IBM Corp. -+.\" s390-tools is free software; you can redistribute it and/or modify -+.\" it under the terms of the MIT license. See LICENSE for details. -+.\" -+.\" use -+.\" groff -man -Tutf8 zcryptctl.8 -+.\" or -+.\" nroff -man zcryptctl.8 -+.\" to process this source -+.\" -+.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools" -+.SH NAME -+zcryptctl \- display information and administrate zcrypt multiple device nodes -+.SH SYNOPSIS -+.TP 8 -+.B zcryptctl list -+.TP -+.B zcryptctl create -+.R [ -+.I node-name -+.R ] -+.TP -+.B zcryptctl destroy -+.I node-name -+.TP -+.B zcryptctl addap -+.R | -+.B delap -+.I node-name adapter-nr -+.TP -+.B zcryptctl adddom -+.R | -+.B deldom -+.I node-name domain-nr -+.TP -+.B zcryptctl addioctl -+.R | -+.B delioctl -+.I node-name ioctl-term -+.TP -+.B zcryptctl config -+.I config-file -+.TP -+.B zcryptctl listconfig -+.SH DESCRIPTION -+The -+.B zcryptctl -+command displays information and maintains the multi device node -+extension for the zcrypt device driver. -+.P -+With the multi device node extension you can create and configure -+additional zcrypt device nodes which can be used as alternate device -+nodes to access the crypto hardware provided by the zcrypt device -+driver. Each zcrypt device node can be restricted in terms of crypto -+cards, domains, and available ioctls. Such a device node can be used -+as a base for container solutions like Docker to control and restrict -+the access to crypto resources. -+.SH COMMANDS -+.TP 8 -+.B zcryptctl list -+Show all the additional device nodes that are currently active. -+.TP -+.B zcryptctl create -+.R [ -+.I node-name -+.R ] -+Create a new zcrypt device node. The \fInode-name\fP might be given -+and needs to be unique and not in use. If there is no node name -+provided, the zcrypt device driver will create a new one with pattern -+zcrypt_\fIx\fP, with \fIx\fP being the next free number. Up to 256 -+additional device nodes can be created. The newly created additional -+device node appears in /dev and has read and write permissions enabled -+only for root. By default all adapters, domains and ioctls are -+initially disabled on this new device node. -+.TP -+.B zcryptctl destroy -+.I node-name -+Destroy an additional zcrypt device node. The device node is only -+marked for disposal and destroyed when it is no longer used. -+.TP -+.B zcryptctl addap -+.R | -+.B delap -+.I node-name adapter-nr -+Update the filter for the specified zcrypt device node and add or -+delete a crypto adapter to be accessible via this node. The symbol -+\fBALL\fP can be used to enable or disable all adapters. -+.TP -+.B zcryptctl adddom -+.R | -+.B deldom -+.I node-name domain-nr -+Update the filter for the specified zcrypt device node and add or -+delete a domain to be accessible through this node. The symbol -+\fBALL\fP can be used to enable or disable all domains. -+.TP -+.B zcryptctl addioctl -+.R | -+.B delioctl -+.I node-name ioctl-term -+Update the filter for the specified zcrypt device node and add or -+delete an ioctl. The ioctl might be specified as symbolic string (one -+of \fBICARSAMODEXPO\fP, \fBICARSACRT\fP, \fBZSECSENDCPRB\fP, -+\fBZSENDEP11CPRB\fP, \fBZCRYPT_DEVICE_STATUS\fP, -+\fBZCRYPT_STATUS_MASK\fP, \fBZCRYPT_QDEPTH_MASK\fP, -+\fBZCRYPT_PERDEV_REQCNT\fP) or numeric value in the range 0-255 and -+the symbol \fBALL\fP can be used to include all ioctls. -+.TP -+.B zcryptctl config -+.I config-file -+Process a config file. The given configuration file is read line by -+line and the settings are applied. Syntax is simple: -+.RS -+.IP "node=" -+.IP "aps=" -+.IP "doms=" -+.IP "ioctls=" -+.LP -+Empty lines are ignored and the '#' marks the rest of the -+line as comment. -+.LP -+The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP, -+\fBdoms=\fP and \fBioctls=\fP lines customize the previously created -+node. The symbol \fBALL\fP is also recognized for aps, doms, and -+ioctls. -+.LP -+Each action must fit into one line, spreading over multiple lines is -+not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP -+and \fBioctls=\fP lines to customize the very same node. -+.LP -+Processing stops when a line cannot be parsed or the current action -+fails. In this case the exit status is non zero but the successful -+actions until the failure occurs are not rolled back. -+.RE -+.TP -+.B zcryptctl listconfig -+List the current configuration in a form suitable for input to the -+\fBzcryptctl config\fP command. -+.LP -+.SH EXIT STATUS -+On successful completion of the command the exit status is 0. A non -+zero return code (and some kind of failure message) is emitted if the -+processing could not complete successful. -+.SH SEE ALSO -+\fBlszcrypt\fR(8) ---- /dev/null -+++ b/zconf/zcrypt/zcryptctl.c -@@ -0,0 +1,1030 @@ -+/* -+ * zcryptctl - Maintain zcrypt multi device nodes. -+ * -+ * by Harald Freudenberger -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "lib/util_base.h" -+#include "lib/util_file.h" -+#include "lib/util_opt.h" -+#include "lib/util_panic.h" -+#include "lib/util_path.h" -+#include "lib/util_prg.h" -+#include "lib/util_proc.h" -+#include "lib/util_rec.h" -+#include "lib/util_scandir.h" -+#include "lib/zt_common.h" -+ -+#define MAX_ZDEV_IOCTLS 256 -+#define ZCRYPT_NAME "zcrypt" -+#define MAX_ZDEV_CARDIDS_EXT 256 -+#define MAX_ZDEV_DOMAINS_EXT 256 -+#define ZCRYPTDEVICE "/dev/z90crypt" -+#define _UNUSED_ __attribute__((unused)) -+ -+/* -+ * Currently known commands -+ */ -+#define CMD_LIST 0x0001 -+#define CMD_CREATE 0x0002 -+#define CMD_DESTROY 0x0003 -+#define CMD_ADD_AP 0x0004 -+#define CMD_DEL_AP 0x0005 -+#define CMD_ADD_DOM 0x0006 -+#define CMD_DEL_DOM 0x0007 -+#define CMD_ADD_IOCTL 0x0008 -+#define CMD_DEL_IOCTL 0x0009 -+#define CMD_CONFIG 0x000A -+#define CMD_LISTCONFIG 0x000B -+ -+/* -+ * Program configuration -+ */ -+static const struct util_prg prg = { -+ .args = "", -+ .command_args = "COMMAND [COMMAND-PARAMS]", -+ .desc = "Display and administrate zcrypt multiple device nodes.", -+ .copyright_vec = { -+ { -+ .owner = "IBM Corp.", -+ .pub_first = 2018, -+ .pub_last = 2018, -+ }, -+ UTIL_PRG_COPYRIGHT_END -+ } -+}; -+ -+static struct util_opt opt_vec[] = { -+ UTIL_OPT_HELP, -+ UTIL_OPT_VERSION, -+ UTIL_OPT_END -+}; -+ -+/* -+ * List of currently known and supported ioctls -+ */ -+static struct zcryptctl_ioctls_s { -+ int nr; -+ const char *name; -+} zcryptctl_ioctls[] = { -+ { -+ .name = "ICARSAMODEXPO", -+ .nr = 0x05, -+ }, -+ { -+ .name = "ICARSACRT", -+ .nr = 0x06, -+ }, -+ { -+ .name = "ZSECSENDCPRB", -+ .nr = 0x81, -+ }, -+ { -+ .name = "ZSENDEP11CPRB", -+ .nr = 0x04, -+ }, -+ { -+ .name = "ZCRYPT_DEVICE_STATUS", -+ .nr = 0x5f, -+ }, -+ { -+ .name = "ZCRYPT_STATUS_MASK", -+ .nr = 0x58, -+ }, -+ { -+ .name = "ZCRYPT_QDEPTH_MASK", -+ .nr = 0x59, -+ }, -+ { -+ .name = "ZCRYPT_PERDEV_REQCNT", -+ .nr = 0x5a, -+ }, -+ { -+ .name = NULL, -+ .nr = 0, -+ }, -+}; -+ -+static int ioctlstr2value(const char *str) -+{ -+ int i; -+ -+ for (i = 0; zcryptctl_ioctls[i].name; i++) -+ if (strcasecmp(str, zcryptctl_ioctls[i].name) == 0) -+ return zcryptctl_ioctls[i].nr; -+ -+ return -1; -+} -+ -+static const char *value2ioctlstr(int value) -+{ -+ int i; -+ -+ for (i = 0; zcryptctl_ioctls[i].name; i++) -+ if (value == zcryptctl_ioctls[i].nr) -+ return zcryptctl_ioctls[i].name; -+ -+ return NULL; -+} -+ -+static int check_nodename(const char *nodename) -+{ -+ struct stat sb; -+ const char *node; -+ char pathname[PATH_MAX]; -+ -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ snprintf(pathname, sizeof(pathname), "/dev/%s", node); -+ pathname[sizeof(pathname) - 1] = '\0'; -+ if (stat(pathname, &sb) != 0) -+ return -1; -+ if (!S_ISCHR(sb.st_mode)) -+ return -2; -+ -+ return 0; -+} -+ -+static int check_zcrypt_class_dir(void) -+{ -+ int rc = 0; -+ char *afile; -+ -+ afile = util_path_sysfs("class/%s", ZCRYPT_NAME); -+ if (!util_path_is_dir(afile)) -+ rc = -1; -+ -+ free(afile); -+ return rc; -+} -+ -+static int fetch_major_minor(const char *nodename, int *major, int *minor) -+{ -+ FILE *f; -+ int rc = 0; -+ char *afile; -+ const char *node; -+ -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ afile = util_path_sysfs("class/%s/%s/dev", ZCRYPT_NAME, node); -+ f = fopen(afile, "r"); -+ if (!f) { -+ rc = -1; -+ goto out; -+ } -+ if (fscanf(f, "%i:%i", major, minor) != 2) { -+ fclose(f); -+ rc = -2; -+ goto out; -+ } -+ fclose(f); -+ -+out: -+ free(afile); -+ return rc; -+} -+ -+static int write_dn_attr(const char *nodename, const char *attr, -+ const char *value) -+{ -+ FILE *f; -+ int rc = 0; -+ char *afile; -+ const char *node; -+ -+ if (nodename) { -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ afile = util_path_sysfs("class/%s/%s/%s", -+ ZCRYPT_NAME, node, attr); -+ } else -+ afile = util_path_sysfs("class/%s/%s", ZCRYPT_NAME, attr); -+ f = fopen(afile, "w"); -+ if (!f) { -+ rc = -1; -+ goto out; -+ } -+ if (fprintf(f, "%s\n", value) < 0) { -+ fclose(f); -+ rc = -2; -+ goto out; -+ } -+ fflush(f); -+ if (ferror(f)) { -+ fclose(f); -+ rc = -2; -+ goto out; -+ } -+ -+ fclose(f); -+ -+out: -+ free(afile); -+ return rc; -+} -+ -+static int read_dn_attr(const char *nodename, const char *attr, -+ char *value, int valuelen) -+{ -+ int rc; -+ FILE *f; -+ char *afile; -+ const char *node; -+ -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ afile = util_path_sysfs("class/%s/%s/%s", ZCRYPT_NAME, node, attr); -+ f = fopen(afile, "r"); -+ if (!f) { -+ rc = -1; -+ goto out; -+ } -+ value = fgets(value, valuelen, f); -+ fclose(f); -+ rc = value ? 0 : -2; -+ -+out: -+ free(afile); -+ return rc; -+} -+ -+static int test_bit(int n, const char *hexbytestr) -+{ -+ char c; -+ int v, i = 0; -+ -+ if (strncmp(hexbytestr, "0x", 2) == 0) -+ i += 2; -+ c = hexbytestr[i + n / 4]; -+ if (c >= '0' && c <= '9') -+ v = c - '0'; -+ else if (c >= 'a' && c <= 'f') -+ v = 10 + c - 'a'; -+ else if (c >= 'A' && c <= 'F') -+ v = 10 + c - 'A'; -+ else -+ errx(EXIT_FAILURE, -+ "Could not parse hex digit '%c'", c); -+ -+ return v & (1 << (3 - (n % 4))); -+} -+ -+static int cmd_list(int cmd, -+ const char *node _UNUSED_, -+ const char *arg _UNUSED_) -+{ -+ DIR *dir; -+ char *dirname; -+ const char *p; -+ struct dirent *de; -+ int i, n, major, minor, count = 0; -+ char buf[80], tab = (cmd == CMD_LISTCONFIG ? ' ' : '\t'); -+ -+ dirname = util_path_sysfs("class/%s", ZCRYPT_NAME); -+ dir = opendir(dirname); -+ if (!dir) -+ errx(EXIT_FAILURE, -+ "Could not read directory '%s' errno=%d (%s)", -+ dirname, errno, strerror(errno)); -+ while ((de = readdir(dir)) != NULL) { -+ if (de->d_name[0] == '.' || de->d_type == DT_REG) -+ continue; -+ if (fetch_major_minor(de->d_name, &major, &minor) != 0) -+ errx(EXIT_FAILURE, -+ "Could not fetch major/minor from sysfs for zcrypt node '%s'", -+ de->d_name); -+ if (cmd == CMD_LISTCONFIG) { -+ printf("node = %s\n", de->d_name); -+ printf(" aps ="); -+ } else { -+ printf("zcrypt node name:\t%s\n", de->d_name); -+ printf(" device node:\t/dev/%s\n", de->d_name); -+ printf(" major:minor:\t%d:%d\n", major, minor); -+ printf(" adapter:"); -+ } -+ if (read_dn_attr(de->d_name, "apmask", buf, sizeof(buf)) != 0) -+ errx(EXIT_FAILURE, -+ "Could not fetch apmask attribute from sysfs for zcrypt node '%s'", -+ de->d_name); -+ for (i = n = 0; i < MAX_ZDEV_CARDIDS_EXT; i++) -+ if (test_bit(i, buf)) -+ printf("%c%d", n++ == 0 ? tab : ',', i); -+ putchar('\n'); -+ if (cmd == CMD_LISTCONFIG) -+ printf(" doms ="); -+ else -+ printf(" domains:"); -+ if (read_dn_attr(de->d_name, "aqmask", buf, sizeof(buf)) != 0) -+ errx(EXIT_FAILURE, -+ "Could not fetch aqmask attribute from sysfs for zcrypt node '%s'", -+ de->d_name); -+ for (i = n = 0; i < MAX_ZDEV_DOMAINS_EXT; i++) -+ if (test_bit(i, buf)) -+ printf("%c%d", n++ == 0 ? tab : ',', i); -+ putchar('\n'); -+ if (cmd == CMD_LISTCONFIG) -+ printf(" ioctls ="); -+ else -+ printf(" ioctls:"); -+ if (read_dn_attr(de->d_name, "ioctlmask", -+ buf, sizeof(buf)) != 0) -+ errx(EXIT_FAILURE, -+ "Could not fetch ioctlmask attribute from sysfs for zcrypt node '%s'", -+ de->d_name); -+ for (i = n = 0; i < MAX_ZDEV_IOCTLS; i++) { -+ if (test_bit(i, buf)) { -+ p = value2ioctlstr(i); -+ if (p) -+ printf("%c%s", -+ n++ == 0 ? tab : ',', p); -+ else -+ printf("%c%d", -+ n++ == 0 ? tab : ',', i); -+ } -+ } -+ putchar('\n'); -+ count++; -+ } -+ closedir(dir); -+ -+ if (count == 0) -+ printf("No additional zcrypt device nodes defined\n"); -+ -+ return 0; -+} -+ -+static int cmd_create(int cmd _UNUSED_, -+ const char *nodename, -+ const char *arg _UNUSED_) -+{ -+ int rc; -+ const char *node; -+ char buf[PATH_MAX]; -+ -+ if (nodename) { -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ strncpy(buf, node, sizeof(buf) - 1); -+ } else -+ strncpy(buf, "\n", sizeof(buf) - 1); -+ buf[sizeof(buf) - 1] = 0; -+ -+ rc = write_dn_attr(NULL, "create", buf); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not write into sysfs entry to create zdev node"); -+ -+ printf("Device node created\n"); -+ -+ return 0; -+} -+ -+static int cmd_destroy(int cmd _UNUSED_, -+ const char *nodename, -+ const char *arg _UNUSED_) -+{ -+ int rc; -+ struct stat sb; -+ const char *node; -+ char pathname[PATH_MAX]; -+ -+ node = strrchr(nodename, '/'); -+ node = node ? node + 1 : nodename; -+ snprintf(pathname, sizeof(pathname), "/dev/%s", node); -+ pathname[sizeof(pathname) - 1] = '\0'; -+ rc = stat(pathname, &sb); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not check status for '%s'", pathname); -+ if (!S_ISCHR(sb.st_mode)) -+ errx(EXIT_FAILURE, -+ "File '%s' is not a character device node", pathname); -+ -+ rc = write_dn_attr(NULL, "destroy", node); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not write into sysfs entry to destroy zdev node '%s'", -+ node); -+ -+ printf("Device node '%s' marked for destruction\n", node); -+ -+ return 0; -+} -+ -+static void add_del_ap(int cmd, const char *node, int ap) -+{ -+ int rc; -+ char buf[PATH_MAX]; -+ -+ if (cmd == CMD_ADD_AP) -+ sprintf(buf, "+%d", ap); -+ else -+ sprintf(buf, "-%d", ap); -+ rc = write_dn_attr(node, "apmask", buf); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not write into sysfs entry to %s adapter %d for zdev node '%s'", -+ cmd == CMD_ADD_AP ? "add" : "remove", ap, node); -+} -+ -+static int cmd_add_del_ap(int cmd, const char *node, const char *arg) -+{ -+ int ap, all = 0; -+ -+ if (strcasecmp(arg, "ALL") == 0) { -+ all = 1; -+ } else { -+ if (sscanf(arg, "%i", &ap) != 1) -+ errx(EXIT_FAILURE, -+ "Invalid adapter argument '%s'", arg); -+ if (ap < 0 || ap >= MAX_ZDEV_CARDIDS_EXT) -+ errx(EXIT_FAILURE, -+ "Adapter argument '%s' out of range [0..%d]", -+ arg, MAX_ZDEV_CARDIDS_EXT - 1); -+ } -+ -+ if (!all) { -+ add_del_ap(cmd, node, ap); -+ printf("Adapter %d %s\n", ap, -+ (cmd == CMD_ADD_AP ? "added" : "removed")); -+ } else { -+ for (ap = 0; ap < MAX_ZDEV_CARDIDS_EXT; ap++) -+ add_del_ap(cmd, node, ap); -+ printf("All adapters %s\n", -+ (cmd == CMD_ADD_AP ? "added" : "removed")); -+ } -+ -+ return 0; -+} -+ -+static void add_del_dom(int cmd, const char *node, int dom) -+{ -+ int rc; -+ char buf[PATH_MAX]; -+ -+ if (cmd == CMD_ADD_DOM) -+ sprintf(buf, "+%d", dom); -+ else -+ sprintf(buf, "-%d", dom); -+ rc = write_dn_attr(node, "aqmask", buf); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not write into sysfs entry to %s domain %d for zdev node '%s'", -+ cmd == CMD_ADD_DOM ? "add" : "remove", dom, node); -+} -+ -+static int cmd_add_del_dom(int cmd, const char *node, const char *arg) -+{ -+ int dom, all = 0; -+ -+ if (strcasecmp(arg, "ALL") == 0) { -+ all = 1; -+ } else { -+ if (sscanf(arg, "%i", &dom) != 1) -+ errx(EXIT_FAILURE, -+ "Invalid domain argument '%s'", arg); -+ if (dom < 0 || dom >= MAX_ZDEV_DOMAINS_EXT) -+ errx(EXIT_FAILURE, -+ "Domain argument '%s' out of range [0..%d]", -+ arg, MAX_ZDEV_DOMAINS_EXT - 1); -+ } -+ -+ if (!all) { -+ add_del_dom(cmd, node, dom); -+ printf("Domain %d %s\n", dom, -+ (cmd == CMD_ADD_DOM ? "added" : "removed")); -+ } else { -+ for (dom = 0; dom < MAX_ZDEV_DOMAINS_EXT; dom++) -+ add_del_dom(cmd, node, dom); -+ printf("All domains %s\n", -+ (cmd == CMD_ADD_DOM ? "added" : "removed")); -+ } -+ -+ return 0; -+} -+ -+static void add_del_ioctl(int cmd, const char *node, int ioctlnr) -+{ -+ int rc; -+ char buf[PATH_MAX]; -+ -+ if (cmd == CMD_ADD_IOCTL) -+ sprintf(buf, "+%d", ioctlnr); -+ else -+ sprintf(buf, "-%d", ioctlnr); -+ rc = write_dn_attr(node, "ioctlmask", buf); -+ if (rc != 0) -+ errx(EXIT_FAILURE, -+ "Could not write into sysfs entry to %s ioctl %d for zdev node '%s'", -+ cmd == CMD_ADD_IOCTL ? "add" : "remove", ioctlnr, node); -+} -+ -+static int cmd_add_del_ioctl(int cmd, const char *node, const char *arg) -+{ -+ int ioctlnr, all = 0; -+ -+ if (strcasecmp(arg, "ALL") == 0) { -+ all = 1; -+ } else { -+ ioctlnr = ioctlstr2value(arg); -+ if (ioctlnr < 0) -+ if (sscanf(arg, "%i", &ioctlnr) != 1) -+ errx(EXIT_FAILURE, -+ "Invalid ioctl argument '%s'", arg); -+ if (ioctlnr < 0 || ioctlnr >= MAX_ZDEV_IOCTLS) -+ errx(EXIT_FAILURE, -+ "Ioctl argument '%s' out of range [0..%d]", -+ arg, MAX_ZDEV_IOCTLS - 1); -+ } -+ -+ if (!all) { -+ add_del_ioctl(cmd, node, ioctlnr); -+ printf("Ioctl %s %s\n", arg, -+ (cmd == CMD_ADD_IOCTL ? "added" : "removed")); -+ } else { -+ for (ioctlnr = 0; ioctlnr < MAX_ZDEV_IOCTLS; ioctlnr++) -+ add_del_ioctl(cmd, node, ioctlnr); -+ printf("All Ioctls %s\n", -+ (cmd == CMD_ADD_IOCTL ? "added" : "removed")); -+ } -+ -+ return 0; -+} -+ -+static int _match_keyword(char **p, const char *keyword) -+{ -+ int n = strlen(keyword); -+ -+ if (strncmp(*p, keyword, n) == 0) { -+ *p += n; -+ return n; -+ } -+ -+ return 0; -+} -+ -+static int _match_character(char **p, char c) -+{ -+ char *q = *p; -+ -+ while (isblank(*q)) -+ q++; -+ if (*q != c) -+ return 0; -+ q++; -+ while (isblank(*q)) -+ q++; -+ *p = q; -+ -+ return 1; -+} -+ -+static int _match_string(char **p, char *buf) -+{ -+ int n = 0; -+ char *q = *p; -+ -+ while (isblank(*q)) -+ q++; -+ while (*q && *q != ',' && !isspace(*q)) { -+ buf[n++] = *q; -+ q++; -+ } -+ while (isblank(*q)) -+ q++; -+ -+ if (n > 0) { -+ buf[n] = '\0'; -+ *p = q; -+ } -+ -+ return n; -+} -+ -+static int cmd_config(int cmd _UNUSED_, -+ const char *nodename _UNUSED_, -+ const char *arg) -+{ -+ ssize_t n; -+ size_t linesize = 0; -+ int nr = 0, havenode = 0; -+ FILE *f = fopen(arg, "r"); -+ char *p, *line = NULL, node[128], buf[128]; -+ -+ if (!f) -+ errx(EXIT_FAILURE, -+ "Could not open file '%s'", arg); -+ -+ while ((n = getline(&line, &linesize, f)) != -1) { -+ nr++; -+ p = line; -+ while (isspace(*p)) -+ p++; -+ if (*p == '\0' || *p == '#') -+ continue; -+ if (_match_keyword(&p, "node")) { -+ if (!_match_character(&p, '=')) -+ errx(EXIT_FAILURE, -+ "Missing '=' at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ if (!_match_string(&p, node)) -+ errx(EXIT_FAILURE, -+ "Missing node name at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ cmd_create(CMD_CREATE, node, NULL); -+ havenode = 1; -+ } else if (_match_keyword(&p, "aps")) { -+ if (!havenode) -+ errx(EXIT_FAILURE, -+ "Missing node=... before processing any aps=... statements in line %d '%s'", -+ nr, line); -+ if (!_match_character(&p, '=')) -+ errx(EXIT_FAILURE, -+ "Missing '=' at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ while (1) { -+ while (isspace(*p)) -+ p++; -+ if (*p == '\0' || *p == '#') -+ break; -+ if (!_match_string(&p, buf)) -+ errx(EXIT_FAILURE, -+ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ cmd_add_del_ap(CMD_ADD_AP, node, buf); -+ while (isblank(*p) || *p == ',') -+ p++; -+ } -+ } else if (_match_keyword(&p, "doms")) { -+ if (!havenode) -+ errx(EXIT_FAILURE, -+ "Missing node=... before processing any doms=... statements in line %d '%s'", -+ nr, line); -+ if (!_match_character(&p, '=')) -+ errx(EXIT_FAILURE, -+ "Missing '=' at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ while (1) { -+ while (isspace(*p)) -+ p++; -+ if (*p == '\0' || *p == '#') -+ break; -+ if (!_match_string(&p, buf)) -+ errx(EXIT_FAILURE, -+ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ cmd_add_del_dom(CMD_ADD_DOM, node, buf); -+ while (isblank(*p) || *p == ',') -+ p++; -+ } -+ } else if (_match_keyword(&p, "ioctls")) { -+ if (!havenode) -+ errx(EXIT_FAILURE, -+ "Missing node=... before processing any ioctls=... statements in line %d '%s'", -+ nr, line); -+ if (!_match_character(&p, '=')) -+ errx(EXIT_FAILURE, -+ "Missing '=' at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ while (1) { -+ while (isspace(*p)) -+ p++; -+ if (*p == '\0' || *p == '#') -+ break; -+ if (!_match_string(&p, buf)) -+ errx(EXIT_FAILURE, -+ "Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ cmd_add_del_ioctl(CMD_ADD_IOCTL, node, buf); -+ while (isblank(*p) || *p == ',') -+ p++; -+ } -+ } else -+ errx(EXIT_FAILURE, -+ "Unknown keyword '%-8.8s...' in line %d '%s'", -+ p, nr, line); -+ } -+ -+ free(line); -+ fclose(f); -+ -+ return 0; -+} -+ -+static struct zcryptctl_cmds_s { -+ int cmd; -+ const char *usage; -+ const char *command; -+ const char *description; -+ int (*function)(int cmd, const char *node, const char *arg); -+} zcryptctl_cmds[] = { -+ { -+ .cmd = CMD_LIST, -+ .command = "list", -+ .function = cmd_list, -+ .usage = "zcryptctl list", -+ .description = -+ "List all currently known additional zcrypt device nodes.", -+ }, -+ { -+ .cmd = CMD_CREATE, -+ .command = "create", -+ .function = cmd_create, -+ .usage = "zcryptctl create [nodename]", -+ .description = -+ "Create a new zcrypt device node.\n" -+ "The node-name might be given and needs to be unique and not\n" -+ "in use. If there is no node name provided, the zcrypt device\n" -+ "driver will create a new one with pattern zcrypt_\n" -+ "with being the next free number. By default all\n" -+ "adapters, domains and ioctls are initially disabled on this\n" -+ "new device node." -+ }, -+ { -+ .cmd = CMD_DESTROY, -+ .command = "destroy", -+ .function = cmd_destroy, -+ .usage = "zcryptctl destroy ", -+ .description = -+ "Destroy an additional zcrypt device node.\n" -+ "Mark the given zcrypt device node as disposable. The removal\n" -+ "will take place when it is no longer used.", -+ }, -+ { -+ .cmd = CMD_ADD_AP, -+ .command = "addap", -+ .function = cmd_add_del_ap, -+ .usage = "zcryptctl addap ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "add an crypto adapter to be accessible via this node. The\n" -+ "adapter argument may be a number in the range 0-255 or the\n" -+ "symbol ALL.", -+ }, -+ { -+ .cmd = CMD_DEL_AP, -+ .command = "delap", -+ .function = cmd_add_del_ap, -+ .usage = "zcryptctl delap ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "remove a crypto adapter from the allowed adapters list. The\n" -+ "adapter argument may be a number in the range 0-255 or the\n" -+ "symbol ALL.", -+ }, -+ { -+ .cmd = CMD_ADD_DOM, -+ .command = "adddom", -+ .function = cmd_add_del_dom, -+ .usage = "zcryptctl adddom ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "add a crypto domain to be accessible via this node. The\n" -+ "domain argument may be a number in the range 0-255 or the\n" -+ "symbol ALL.", -+ }, -+ { -+ .cmd = CMD_DEL_DOM, -+ .command = "deldom", -+ .function = cmd_add_del_dom, -+ .usage = "zcryptctl deldom ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "remove a crypto domain from the allowed domains list. The\n" -+ "domain argument may be a number in the range 0-255 or the\n" -+ "symbol ALL.", -+ }, -+ { -+ .cmd = CMD_ADD_IOCTL, -+ .command = "addioctl", -+ .function = cmd_add_del_ioctl, -+ .usage = "zcryptctl addioctl ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "add an ioctl number to be accessible via this node. The\n" -+ "ioctlexp argument may be one of symbols ICARSAMODEXPO,\n" -+ "ICARSACRT, ZSECSENDCPRB, ZSENDEP11CPRB, ZCRYPT_DEVICE_STATUS\n" -+ "ZCRYPT_STATUS_MASK, ZCRYPT_QDEPTH_MASK, ZCRYPT_PERDEV_REQCNT\n" -+ "or a number in the range 0-255 or the symbol ALL.", -+ }, -+ { -+ .cmd = CMD_DEL_IOCTL, -+ .command = "delioctl", -+ .function = cmd_add_del_ioctl, -+ .usage = "zcryptctl delioctl ", -+ .description = -+ "Update the filter for the specified zcrypt device node and\n" -+ "remove an ioctl number from the allowed ioctls list. The\n" -+ "ioctlexp argument may be one of symbols ICARSAMODEXPO,\n" -+ "ICARSACRT, ZSECSENDCPRB, ZSENDEP11CPRB, ZCRYPT_DEVICE_STATUS\n" -+ "ZCRYPT_STATUS_MASK, ZCRYPT_QDEPTH_MASK, ZCRYPT_PERDEV_REQCNT\n" -+ "or a number in the range 0-255 or the symbol ALL.", -+ }, -+ { -+ .cmd = CMD_CONFIG, -+ .command = "config", -+ .function = cmd_config, -+ .usage = "zcryptctl config ", -+ .description = -+ "Process a config file. The given config file is read line by\n" -+ "line and the settings are applied. Syntax is simple:\n" -+ " node=\n" -+ " aps=\n" -+ " doms=\n" -+ " ioctls=\n" -+ "Empty lines are ignored and the '#' marks the rest of the\n" -+ "line as comment.\n" -+ "The node= line creates a new zcrypt device node, the\n" -+ "aps=, doms= and ioctls= lines customize the previously\n" -+ "created node. The symbol ALL is also recognized for aps,\n" -+ "doms, and ioctls.\n" -+ "Each action must fit into one line, spreading over multiple\n" -+ "lines is not supported. But you can use more than one\n" -+ "aps=, doms= and ioctls= lines to customize the very same\n" -+ "node.\n" -+ "Processing stops when a line cannot be parsed or the\n" -+ "current action fails. When the config file has been\n" -+ "processed successful, the zcryptctl return code is 0. A non\n" -+ "zero return code (and some kind of failure message) is\n" -+ "emitted on partial completion.", -+ }, -+ { -+ .cmd = CMD_LISTCONFIG, -+ .command = "listconfig", -+ .function = cmd_list, -+ .usage = "zcryptctl listconfig", -+ .description = -+ "List all currently known additional zcrypt device nodes\n" -+ "in a format suitable for the 'config' command.", -+ }, -+ { -+ .command = NULL, -+ .cmd = 0, -+ } -+}; -+ -+static int get_command_index(const char *cmdstr) -+{ -+ int i; -+ -+ for (i = 0; zcryptctl_cmds[i].command; i++) -+ if (!strcmp(zcryptctl_cmds[i].command, cmdstr)) -+ return i; -+ -+ return -1; -+} -+ -+static void commands_print_help(void) -+{ -+ int i; -+ -+ for (i = 0; zcryptctl_cmds[i].command; i++) -+ if (zcryptctl_cmds[i].usage) -+ printf(" %s\n", zcryptctl_cmds[i].usage); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int c, cmdindex = -1; -+ int rc = EXIT_SUCCESS; -+ -+ util_prg_init(&prg); -+ util_opt_init(opt_vec, NULL); -+ -+ for (c = 1; c < argc; c++) { -+ cmdindex = get_command_index(argv[c]); -+ if (cmdindex >= 0) -+ break; -+ } -+ -+ while (1) { -+ c = util_opt_getopt_long(argc, argv); -+ if (c == -1) -+ break; -+ switch (c) { -+ case 'h': -+ if (cmdindex < 0) { -+ util_prg_print_help(); -+ commands_print_help(); -+ util_opt_print_help(); -+ } else { -+ printf("Usage: %s\n", -+ zcryptctl_cmds[cmdindex].usage); -+ printf("%s\n", -+ zcryptctl_cmds[cmdindex].description); -+ } -+ return EXIT_SUCCESS; -+ case 'v': -+ util_prg_print_version(); -+ return EXIT_SUCCESS; -+ default: -+ util_opt_print_parse_error(c, argv); -+ return EXIT_FAILURE; -+ } -+ } -+ -+ if (cmdindex < 0) -+ errx(EXIT_FAILURE, "Missing or invalid command argument"); -+ -+ if (check_zcrypt_class_dir() != 0) -+ errx(EXIT_FAILURE, -+ "Directory class/%s is missing in sysfs.\n" -+ "Multiple zcrypt node support is not available", -+ ZCRYPT_NAME); -+ -+ c = zcryptctl_cmds[cmdindex].cmd; -+ switch (c) { -+ case CMD_LIST: -+ case CMD_LISTCONFIG: -+ rc = zcryptctl_cmds[cmdindex].function(c, NULL, NULL); -+ break; -+ case CMD_CREATE: -+ rc = zcryptctl_cmds[cmdindex].function(c, -+ optind + 1 < argc ? -+ argv[optind + 1] : NULL, -+ NULL); -+ break; -+ case CMD_DESTROY: -+ if (optind + 1 >= argc) -+ errx(EXIT_FAILURE, "Missing node name argument"); -+ if (check_nodename(argv[optind + 1]) != 0) -+ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", -+ argv[optind + 1]); -+ rc = zcryptctl_cmds[cmdindex].function(c, -+ argv[optind + 1], NULL); -+ break; -+ case CMD_ADD_AP: -+ case CMD_DEL_AP: -+ if (optind + 1 >= argc) -+ errx(EXIT_FAILURE, "Missing node name argument"); -+ if (optind + 2 >= argc) -+ errx(EXIT_FAILURE, "Missing adapter argument"); -+ if (check_nodename(argv[optind + 1]) != 0) -+ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", -+ argv[optind + 1]); -+ rc = zcryptctl_cmds[cmdindex].function(c, -+ argv[optind + 1], -+ argv[optind + 2]); -+ break; -+ case CMD_ADD_DOM: -+ case CMD_DEL_DOM: -+ if (optind + 1 >= argc) -+ errx(EXIT_FAILURE, "Missing node name argument"); -+ if (optind + 2 >= argc) -+ errx(EXIT_FAILURE, "Missing domain argument"); -+ if (check_nodename(argv[optind + 1]) != 0) -+ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", -+ argv[optind + 1]); -+ rc = zcryptctl_cmds[cmdindex].function(c, -+ argv[optind + 1], -+ argv[optind + 2]); -+ break; -+ case CMD_ADD_IOCTL: -+ case CMD_DEL_IOCTL: -+ if (optind + 1 >= argc) -+ errx(EXIT_FAILURE, "Missing node name argument"); -+ if (optind + 2 >= argc) -+ errx(EXIT_FAILURE, "Missing ioctl argument"); -+ if (check_nodename(argv[optind + 1]) != 0) -+ errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'", -+ argv[optind + 1]); -+ rc = zcryptctl_cmds[cmdindex].function(c, -+ argv[optind + 1], -+ argv[optind + 2]); -+ break; -+ case CMD_CONFIG: -+ if (optind + 1 >= argc) -+ errx(EXIT_FAILURE, "Missing filename argument"); -+ rc = zcryptctl_cmds[cmdindex].function(c, NULL, -+ argv[optind + 1]); -+ break; -+ default: -+ errx(EXIT_FAILURE, "Unknown command %d", c); -+ } -+ -+ return rc; -+} diff --git a/s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch b/s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch deleted file mode 100644 index 580ca4b..0000000 --- a/s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch +++ /dev/null @@ -1,797 +0,0 @@ -Subject: zdev: use libutil provided path functions -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: d542138868153a36c3de6a21c3dea56125157e26 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: use libutil provided path functions - - Closes: #20 - - Signed-off-by: Rafael Fonseca - Acked-by: Peter Oberparleiter - Signed-off-by: Michael Holzheu - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/misc.h | 4 -- - zdev/src/ccw.c | 20 ++++-------- - zdev/src/ccwgroup.c | 7 ++-- - zdev/src/chzdev.c | 3 + - zdev/src/ctc_auto.c | 6 ++- - zdev/src/device.c | 5 ++- - zdev/src/devnode.c | 8 +++- - zdev/src/generic_ccw.c | 4 +- - zdev/src/lcs_auto.c | 6 ++- - zdev/src/misc.c | 63 --------------------------------------- - zdev/src/modprobe.c | 8 +++- - zdev/src/module.c | 8 +++- - zdev/src/qeth_auto.c | 4 +- - zdev/src/root.c | 4 +- - zdev/src/scsi.c | 4 +- - zdev/src/select.c | 4 +- - zdev/src/udev.c | 4 +- - zdev/src/udev_ccw.c | 10 +++--- - zdev/src/udev_ccwgroup.c | 10 +++--- - zdev/src/udev_zfcp_lun.c | 8 +++- - zdev/src/zfcp_lun.c | 16 +++++---- - 21 files changed, 84 insertions(+), 122 deletions(-) - ---- a/zdev/include/misc.h -+++ b/zdev/include/misc.h -@@ -157,10 +157,6 @@ char *misc_asprintf(const char *, ...); - int misc_system(err_t, const char *, ...); - bool misc_read_dir(const char *, struct util_list *, - bool (*)(const char *, void *), void *); --bool path_exists(const char *); --bool file_exists(const char *); --bool file_writable(const char *); --bool dir_exists(const char *); - bool file_is_devnode(const char *); - exit_code_t remove_file(const char *); - char *misc_read_text_file(const char *, int, err_t); ---- a/zdev/src/ccw.c -+++ b/zdev/src/ccw.c -@@ -14,6 +14,7 @@ - #include - - #include "lib/util_base.h" -+#include "lib/util_path.h" - - #include "attrib.h" - #include "ccw.h" -@@ -1165,15 +1166,10 @@ out: - - static void read_grouped(struct ccw_devinfo *info, const char *path) - { -- char *file_path; -- -- file_path = misc_asprintf("%s/group_device", path); -- if (path_exists(file_path)) -+ if (util_path_exists("%s/group_device", path)) - info->grouped = 1; - else - info->grouped = 0; -- -- free(file_path); - } - - static void read_cutype(struct ccw_devinfo *info, const char *path) -@@ -1229,7 +1225,7 @@ static struct ccw_devinfo *ccw_devinfo_r - - id = ccw_devid_to_str(devid); - path = path_get_ccw_device(NULL, id); -- if (!dir_exists(path)) -+ if (!util_path_is_dir(path)) - goto out; - - info->exists = 1; -@@ -1354,7 +1350,7 @@ bool ccw_exists(const char *drv, const c - if (!path) - return false; - -- rc = dir_exists(path); -+ rc = util_path_is_dir(path); - free(path); - - return rc; -@@ -1428,7 +1424,7 @@ static exit_code_t ccw_st_read_active(st - state->definable = 0; - - path = path_get_ccw_device(drv, id); -- if (path_exists(path)) { -+ if (util_path_exists(path)) { - state->exists = 1; - device_read_active_settings(dev, scope); - } else -@@ -1641,7 +1637,7 @@ static void ccw_st_add_errors(struct sub - if (!path) - return; - -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - strlist_add(errors, "CCW device %s does not exist", id); - goto out; - } -@@ -1662,9 +1658,7 @@ static void ccw_st_add_errors(struct sub - "paths", id); - goto out; - } -- free(apath); -- apath = misc_asprintf("%s/driver", path); -- if (!path_exists(apath)) { -+ if (!util_path_exists("%s/driver", path)) { - strlist_add(errors, "CCW device %s is not bound to a driver", - id); - goto out; ---- a/zdev/src/ccwgroup.c -+++ b/zdev/src/ccwgroup.c -@@ -12,6 +12,7 @@ - #include - - #include "lib/util_base.h" -+#include "lib/util_path.h" - - #include "attrib.h" - #include "ccw.h" -@@ -557,7 +558,7 @@ static bool read_full_id(struct ccwgroup - bool result = false; - - path = path_get_ccwgroup_device(drv, id); -- if (!dir_exists(path)) -+ if (!util_path_is_dir(path)) - goto out; - - memset(&devid, 0, sizeof(struct ccwgroup_devid)); -@@ -625,7 +626,7 @@ static void ccwgroup_add_ids(const char - path = path_get_ccwgroup_devices(drv); - if (mod) - module_try_load_once(mod, path); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, get_ids_cb, &cb_data); - free(path); - } -@@ -663,7 +664,7 @@ static exit_code_t ccwgroup_st_read_acti - state->definable = 0; - - path = ccwgroup_get_dev_path_by_devid(drv, devid); -- if (path_exists(path)) { -+ if (util_path_exists(path)) { - state->exists = 1; - device_read_active_settings(dev, scope); - } else ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -16,6 +16,7 @@ - #include - #include - -+#include "lib/util_path.h" - #include "lib/zt_common.h" - - #include "attrib.h" -@@ -2502,7 +2503,7 @@ static exit_code_t do_export(struct opti - info("Exporting configuration data to standard output\n"); - } else { - info("Exporting configuration data to %s\n", opts->export); -- if (!path_exists(opts->export)) { -+ if (!util_path_exists(opts->export)) { - rc = path_create(opts->export); - if (rc) - return rc; ---- a/zdev/src/ctc_auto.c -+++ b/zdev/src/ctc_auto.c -@@ -9,6 +9,8 @@ - - #include - -+#include "lib/util_path.h" -+ - #include "ccw.h" - #include "ccwgroup.h" - #include "ctc.h" -@@ -125,13 +127,13 @@ static struct util_list *read_sorted_ctc - /* Add CCW devices bound to the CTC CCW device driver. */ - module_try_load_once(CTC_MOD_NAME, NULL); - path = path_get_sys_bus_drv(CCW_BUS_NAME, CTC_CCWDRV_NAME); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, infos); - free(path); - - /* Add CCW devices bound to the LCS CCW device driver. */ - path = path_get_sys_bus_drv(CCW_BUS_NAME, LCS_CCWDRV_NAME); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, infos); - free(path); - ---- a/zdev/src/device.c -+++ b/zdev/src/device.c -@@ -11,6 +11,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "device.h" - #include "devtype.h" -@@ -480,7 +482,8 @@ void device_read_active_settings(struct - a = attrib_find(st->dev_attribs, name); - s = setting_list_apply_actual(dev->active.settings, a, name, - value); -- if (link || (scope == scope_all && !file_writable(path))) -+ if (link || (scope == scope_all && -+ !util_path_is_writable(path))) - s->readonly = 1; - if (link) - free(link); ---- a/zdev/src/devnode.c -+++ b/zdev/src/devnode.c -@@ -15,6 +15,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "devnode.h" - #include "misc.h" - #include "path.h" -@@ -230,7 +232,7 @@ static exit_code_t add_block_cb(const ch - - /* Add additional nodes. */ - cb_data->prefix = filename; -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_part_cb, cb_data); - - return EXIT_OK; -@@ -249,7 +251,7 @@ int devnode_add_block_from_sysfs(struct - cb_data.prefix = NULL; - - blkpath = misc_asprintf("%s/block", path); -- if (dir_exists(blkpath)) -+ if (util_path_is_dir(blkpath)) - path_for_each(blkpath, add_block_cb, &cb_data); - free(blkpath); - -@@ -283,7 +285,7 @@ int devnode_add_net_from_sysfs(struct ut - cb_data.prefix = NULL; - - netpath = misc_asprintf("%s/net", path); -- if (dir_exists(netpath)) -+ if (util_path_is_dir(netpath)) - path_for_each(netpath, add_net_cb, &cb_data); - free(netpath); - ---- a/zdev/src/generic_ccw.c -+++ b/zdev/src/generic_ccw.c -@@ -9,6 +9,8 @@ - - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "ccw.h" - #include "ccwgroup.h" -@@ -162,7 +164,7 @@ static void generic_ccw_st_add_devnodes( - cb_data.devnodes = devnodes; - cb_data.id = id; - path = path_get_sys_dev_char_devices(); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, &cb_data); - free(path); - } ---- a/zdev/src/lcs_auto.c -+++ b/zdev/src/lcs_auto.c -@@ -9,6 +9,8 @@ - - #include - -+#include "lib/util_path.h" -+ - #include "ccw.h" - #include "ccwgroup.h" - #include "ctc.h" -@@ -129,13 +131,13 @@ static struct util_list *read_sorted_lcs - /* Add CCW devices bound to the LCS CCW device driver. */ - module_try_load_once(LCS_MOD_NAME, NULL); - path = path_get_sys_bus_drv(CCW_BUS_NAME, LCS_CCWDRV_NAME); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, infos); - free(path); - - /* Add CCW devices bound to the CTC CCW device driver. */ - path = path_get_sys_bus_drv(CCW_BUS_NAME, CTC_CCWDRV_NAME); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, infos); - free(path); - ---- a/zdev/src/misc.c -+++ b/zdev/src/misc.c -@@ -889,69 +889,6 @@ void ptrlist_move(struct util_list *to, - util_list_add_tail(to, node); - } - --/* Check if a path exists. */ --bool path_exists(const char *path) --{ -- struct stat s; -- -- debug("Checking if file exists: %s\n", path); -- if (stat(path, &s) != 0) -- return false; -- -- return true; --} -- --/* Check if a file exists. */ --bool file_exists(const char *path) --{ -- struct stat s; -- -- debug("Checking if regular file exists: %s\n", path); -- if (stat(path, &s) != 0) -- return false; -- -- if (!S_ISREG(s.st_mode)) -- return false; -- -- return true; --} -- --/* Check if a file is writable. */ --bool file_writable(const char *path) --{ -- struct stat s; -- -- debug("Checking if regular file is writable: %s\n", path); -- if (stat(path, &s) != 0) -- return false; -- -- if (!S_ISREG(s.st_mode)) -- return false; -- -- if (!(s.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) -- return false; -- -- return true; --} -- --/* Check if a directory exists. */ --bool dir_exists(const char *path) --{ -- bool result = false; -- struct stat s; -- -- debug("Checking if directory exists: %s\n", path); -- if (stat(path, &s) != 0) -- goto out; -- if (!S_ISDIR(s.st_mode)) -- goto out; -- result = true; --out: -- debug("Result: %d\n", result); -- -- return result; --} -- - /* Check if file is a block or character special file. */ - bool file_is_devnode(const char *path) - { ---- a/zdev/src/modprobe.c -+++ b/zdev/src/modprobe.c -@@ -14,6 +14,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "misc.h" - #include "modprobe.h" -@@ -376,7 +378,7 @@ exit_code_t modprobe_read_settings(const - struct modprobe_file *mf; - exit_code_t rc; - -- if (!file_exists(path)) { -+ if (!util_path_is_reg_file(path)) { - *settings = NULL; - return EXIT_OK; - } -@@ -398,7 +400,7 @@ exit_code_t modprobe_write_settings(cons - exit_code_t rc; - unsigned long lines; - -- if (file_exists(path)) { -+ if (util_path_is_reg_file(path)) { - rc = modprobe_read(path, &mf); - if (rc) - return rc; -@@ -414,7 +416,7 @@ exit_code_t modprobe_write_settings(cons - lines = util_list_len(&mf->lines); - if (lines == 0 || (lines == 1 && find_chzdev_comment(mf))) { - /* Do not write empty files. */ -- if (file_exists(path)) -+ if (util_path_is_reg_file(path)) - rc = remove_file(path); - } else - rc = modprobe_write(mf); ---- a/zdev/src/module.c -+++ b/zdev/src/module.c -@@ -12,6 +12,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "misc.h" - #include "module.h" -@@ -34,7 +36,7 @@ bool module_loaded(const char *mod) - char *path = path_get_sys_module(mod); - bool rc; - -- rc = dir_exists(path); -+ rc = util_path_is_dir(path); - free(path); - - return rc; -@@ -229,7 +231,7 @@ void module_try_load_once(const char *mo - } else - tried_loading = strlist_new(); - strlist_add(tried_loading, mod); -- if (path && path_exists(path)) -+ if (path && util_path_exists(path)) - return; - if (module_loaded(mod)) - return; -@@ -275,7 +277,7 @@ bool module_set_params(const char *mod, - return false; - } - path = path_get_sys_module_param(mod, s->name); -- result = file_writable(path); -+ result = util_path_is_writable(path); - free(path); - if (!result) { - /* Sysfs file is not writable. */ ---- a/zdev/src/qeth_auto.c -+++ b/zdev/src/qeth_auto.c -@@ -11,6 +11,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "ccw.h" - #include "ccwgroup.h" - #include "device.h" -@@ -277,7 +279,7 @@ static struct util_list *read_sorted_qet - /* Get CHPID information for all devices bound to the QETH driver. */ - infos = ptrlist_new(); - path = path_get_sys_bus_drv(CCW_BUS_NAME, QETH_CCWDRV_NAME); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_cb, infos); - free(path); - ---- a/zdev/src/root.c -+++ b/zdev/src/root.c -@@ -9,6 +9,8 @@ - - #include - -+#include "lib/util_path.h" -+ - #include "device.h" - #include "devtype.h" - #include "misc.h" -@@ -74,7 +76,7 @@ exit_code_t root_check(void) - "required.\n"); - - /* Check if script is available. */ -- if (!file_exists(PATH_ROOT_SCRIPT)) -+ if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) - goto out; - - /* Ask for confirmation. */ ---- a/zdev/src/scsi.c -+++ b/zdev/src/scsi.c -@@ -12,6 +12,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "misc.h" - #include "path.h" - #include "scsi.h" -@@ -253,7 +255,7 @@ static struct util_list *read_scsi_zfcp_ - - list = ptrlist_new(); - path = path_get_sys_bus_dev("scsi", NULL); -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, add_ids_cb, list); - free(path); - ---- a/zdev/src/select.c -+++ b/zdev/src/select.c -@@ -10,6 +10,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "blkinfo.h" - #include "ccw.h" - #include "device.h" -@@ -622,7 +624,7 @@ exit_code_t select_by_path(struct select - struct ptrlist_node *p; - exit_code_t rc; - -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - err_t_print(err, "Path not found: %s\n", path); - return EXIT_DEVICE_NOT_FOUND; - } ---- a/zdev/src/udev.c -+++ b/zdev/src/udev.c -@@ -13,6 +13,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "ccw.h" - #include "device.h" -@@ -391,7 +393,7 @@ exit_code_t udev_remove_rule(const char - exit_code_t rc = EXIT_OK; - - path = path_get_udev_rule(type, id); -- if (file_exists(path)) -+ if (util_path_is_reg_file(path)) - rc = remove_file(path); - free(path); - ---- a/zdev/src/udev_ccw.c -+++ b/zdev/src/udev_ccw.c -@@ -13,6 +13,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "ccw.h" - #include "device.h" -@@ -33,7 +35,7 @@ bool udev_ccw_exists(const char *type, c - return false; - - path = path_get_udev_rule(type, normid); -- rc = file_exists(path); -+ rc = util_path_is_reg_file(path); - free(path); - free(normid); - -@@ -150,7 +152,7 @@ exit_code_t udev_ccw_write_device(struct - - path = path_get_udev_rule(type, id); - debug("Writing %s udev rule file %s\n", type, path); -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - rc = path_create(path); - if (rc) - goto out; -@@ -243,7 +245,7 @@ exit_code_t udev_ccw_write_cio_ignore(co - - if (!*id_list) { - /* Empty id_list string - remove file. */ -- if (!file_exists(path)) { -+ if (!util_path_is_reg_file(path)) { - /* Already removed. */ - goto out; - } -@@ -256,7 +258,7 @@ exit_code_t udev_ccw_write_cio_ignore(co - goto out; - - debug("Writing cio-ignore udev rule file %s\n", path); -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - rc = path_create(path); - if (rc) - goto out; ---- a/zdev/src/udev_ccwgroup.c -+++ b/zdev/src/udev_ccwgroup.c -@@ -13,6 +13,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "ccwgroup.h" - #include "device.h" -@@ -53,7 +55,7 @@ bool udev_ccwgroup_exists(const char *ty - path = get_rule_path(type, id); - if (!path) - return false; -- rc = file_exists(path); -+ rc = util_path_is_reg_file(path); - free(path); - - return rc; -@@ -215,7 +217,7 @@ exit_code_t udev_ccwgroup_write_device(s - list = setting_list_get_sorted(dev->persistent.settings); - - debug("Writing %s udev rule file %s\n", type, path); -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - rc = path_create(path); - if (rc) - goto out; -@@ -364,7 +366,7 @@ void udev_ccwgroup_add_device_ids(const - cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type); - cb_data.ids = list; - -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, get_ids_cb, &cb_data); - - free(cb_data.prefix); -@@ -382,7 +384,7 @@ exit_code_t udev_ccwgroup_remove_rule(co - return EXIT_INVALID_ID; - - path = path_get_udev_rule(type, partial_id); -- if (file_exists(path)) -+ if (util_path_is_reg_file(path)) - rc = remove_file(path); - free(path); - free(partial_id); ---- a/zdev/src/udev_zfcp_lun.c -+++ b/zdev/src/udev_zfcp_lun.c -@@ -14,6 +14,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "device.h" - #include "misc.h" -@@ -376,7 +378,7 @@ void udev_zfcp_lun_add_device_ids(struct - cb_data.list = list; - path = path_get_udev_rules(); - -- if (dir_exists(path)) -+ if (util_path_is_dir(path)) - path_for_each(path, lun_cb, &cb_data); - - free(path); -@@ -497,7 +499,7 @@ static exit_code_t write_luns_rule(const - return EXIT_INTERNAL_ERROR; - hba_id = ccw_devid_to_str(&node->id.fcp_dev); - debug("Writing FCP LUN udev rule file %s\n", path); -- if (!path_exists(path)) { -+ if (!util_path_exists(path)) { - rc = path_create(path); - if (rc) - goto out; -@@ -614,7 +616,7 @@ static exit_code_t update_lun_rule(const - - /* Get previous rule data. */ - luns = zfcp_lun_node_list_new(); -- exists = file_exists(path); -+ exists = util_path_is_reg_file(path); - if (exists) - udev_read_zfcp_lun_rule(path, luns); - ---- a/zdev/src/zfcp_lun.c -+++ b/zdev/src/zfcp_lun.c -@@ -13,6 +13,8 @@ - #include - #include - -+#include "lib/util_path.h" -+ - #include "attrib.h" - #include "ccw.h" - #include "device.h" -@@ -430,7 +432,7 @@ static exit_code_t zfcp_lun_st_read_acti - - /* Check for FC unit. */ - fc_path = path_get_zfcp_lun_dev(dev->devid); -- fc_exists = path_exists(fc_path); -+ fc_exists = util_path_exists(fc_path); - free(fc_path); - - /* Check for SCSI device. */ -@@ -478,7 +480,7 @@ static exit_code_t zfcp_lun_add(struct d - /* Check if LUN already exists. */ - fcp_dev_id = ccw_devid_to_str(&devid->fcp_dev); - lunpath = path_get_zfcp_lun_dev(devid); -- if (dir_exists(lunpath)) { -+ if (util_path_is_dir(lunpath)) { - hctl = scsi_hctl_from_zfcp_lun_devid(devid); - if (!hctl) - goto check_failed; -@@ -486,7 +488,7 @@ static exit_code_t zfcp_lun_add(struct d - } - - portpath = path_get_zfcp_port_dev(devid); -- if (!dir_exists(portpath)) { -+ if (!util_path_is_dir(portpath)) { - delayed_err("Target port not found\n"); - rc = EXIT_ZFCP_WWPN_NOT_FOUND; - goto out; -@@ -681,14 +683,14 @@ static exit_code_t zfcp_lun_st_device_un - - remove_lun: - path = path_get_zfcp_lun_dev(devid); -- if (!path_exists(path)) -+ if (!util_path_exists(path)) - goto out; - free(path); - path = NULL; - - /* Remove FCP LUN. */ - devpath = path_get_zfcp_port_dev(devid); -- if (!dir_exists(devpath)) { -+ if (!util_path_is_dir(devpath)) { - rc = EXIT_ZFCP_WWPN_NOT_FOUND; - goto out; - } -@@ -779,7 +781,7 @@ static bool zfcp_lun_fc_lun_exists(const - if (zfcp_lun_parse_devid(&devid, id, err_ignore) != EXIT_OK) - return false; - path = path_get_zfcp_lun_dev(&devid); -- result = path_exists(path); -+ result = util_path_exists(path); - free(path); - - return result; -@@ -910,7 +912,7 @@ static void add_sg_from_sysfs(struct uti - char *sgpath; - - sgpath = misc_asprintf("%s/scsi_generic", path); -- if (dir_exists(sgpath)) -+ if (util_path_is_dir(sgpath)) - path_for_each(sgpath, add_sg_cb, list); - free(sgpath); - } diff --git a/s390-tools-sles15sp1-01-zkey-Include-sbin-into-PATH-when-executing-commands.patch b/s390-tools-sles15sp1-01-zkey-Include-sbin-into-PATH-when-executing-commands.patch deleted file mode 100644 index e726963..0000000 --- a/s390-tools-sles15sp1-01-zkey-Include-sbin-into-PATH-when-executing-commands.patch +++ /dev/null @@ -1,30 +0,0 @@ -Subject: zkey: Fails to run commands generated by 'zkey cryptsetup' -From: Ingo Franzki - -Description: zkey: Fails to run commands generated by 'zkey cryptsetup' -Symptom: Fails to run commands generated by 'zkey cryptsetup'. -Problem: When using 'zkey cryptsetup' with --run option the - execution of the generated commands may fail, when - the executable to be run is located in '/sbin'. -Solution: Include /sbin into PATH when executing commands. -Reproduction: Use 'zkey cryptsetup' with option --run on a distribution - where 'cryptsetup' is located in '/sbin'. -Upstream-ID: - -Problem-ID: 173155 - -Signed-off-by: Ingo Franzki ---- - zkey/keystore.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/zkey/keystore.c -+++ b/zkey/keystore.c -@@ -3235,7 +3235,7 @@ static int _keystore_execute_cmd(const c - { - int rc; - -- rc = setenv("PATH", "/bin:/usr/bin:/usr/sbin", 1); -+ rc = setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin", 1); - if (rc < 0) - return rc; - diff --git a/s390-tools-sles15sp1-02-cpumf-z14-split-counter-sets-according-to-CFVN-CSVN-.patch b/s390-tools-sles15sp1-02-cpumf-z14-split-counter-sets-according-to-CFVN-CSVN-.patch deleted file mode 100644 index bffb743..0000000 --- a/s390-tools-sles15sp1-02-cpumf-z14-split-counter-sets-according-to-CFVN-CSVN-.patch +++ /dev/null @@ -1,382 +0,0 @@ -Subject: cpumf/z14: split counter sets according to CFVN/CSVN (part 1/2) -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: d121ffa3f01e08d2cc53140444dfcab830319012 -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf/z14: split counter sets according to CFVN/CSVN (part 1/2) - - With z14, the counters in the problem-state are reduced resulting - in an increased first version number of the CPUM CF. To adapt to - this change, split the counter sets according to their counter - first and second version number. The second version number controls - the crypto-activity and extended counter set. Treat the crypto-activity - counter set as generic, as the extended counter set is already handled - based on hardware models. - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Stefan Haberland - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/Makefile | 4 - - cpumf/data/cpum-cf-cfvn-1.ctr | 48 +++++++++++++ - cpumf/data/cpum-cf-cfvn-3.ctr | 32 ++++++++ - cpumf/data/cpum-cf-csvn-generic.ctr | 84 ++++++++++++++++++++++ - cpumf/data/cpum-cf-generic.ctr | 132 ------------------------------------ - cpumf/data/cpum-cf-hw-counter.map | 15 +++- - 6 files changed, 180 insertions(+), 135 deletions(-) - ---- a/cpumf/Makefile -+++ b/cpumf/Makefile -@@ -4,7 +4,9 @@ include ../common.mak - - - CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf --DATA_FILES = cpum-cf-hw-counter.map cpum-cf-generic.ctr \ -+DATA_FILES = cpum-cf-hw-counter.map \ -+ cpum-cf-cfvn-1.ctr cpum-cf-cfvn-3.ctr \ -+ cpum-cf-csvn-generic.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 ---- /dev/null -+++ b/cpumf/data/cpum-cf-cfvn-1.ctr -@@ -0,0 +1,48 @@ -+Counter: 0 Name:CPU_CYCLES -+Description: -+Cycle Count -+. -+Counter: 1 Name:INSTRUCTIONS -+Description: -+Instruction Count -+. -+Counter: 2 Name:L1I_DIR_WRITES -+Description: -+Level-1 I-Cache Directory Write Count -+. -+Counter: 3 Name:L1I_PENALTY_CYCLES -+Description: -+Level-1 I-Cache Penalty Cycle Count -+. -+Counter: 4 Name:L1D_DIR_WRITES -+Description: -+Level-1 D-Cache Directory Write Count -+. -+Counter: 5 Name:L1D_PENALTY_CYCLES -+Description: -+Level-1 D-Cache Penalty Cycle Count -+. -+Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES -+Description: -+Problem-State Cycle Count -+. -+Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS -+Description: -+Problem-State Instruction Count -+. -+Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES -+Description: -+Problem-State Level-1 I-Cache Directory Write Count -+. -+Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES -+Description: -+Problem-State Level-1 I-Cache Penalty Cycle Count -+. -+Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES -+Description: -+Problem-State Level-1 D-Cache Directory Write Count -+. -+Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES -+Description: -+Problem-State Level-1 D-Cache Penalty Cycle Count -+. ---- /dev/null -+++ b/cpumf/data/cpum-cf-cfvn-3.ctr -@@ -0,0 +1,32 @@ -+Counter: 0 Name:CPU_CYCLES -+Description: -+Cycle Count -+. -+Counter: 1 Name:INSTRUCTIONS -+Description: -+Instruction Count -+. -+Counter: 2 Name:L1I_DIR_WRITES -+Description: -+Level-1 I-Cache Directory Write Count -+. -+Counter: 3 Name:L1I_PENALTY_CYCLES -+Description: -+Level-1 I-Cache Penalty Cycle Count -+. -+Counter: 4 Name:L1D_DIR_WRITES -+Description: -+Level-1 D-Cache Directory Write Count -+. -+Counter: 5 Name:L1D_PENALTY_CYCLES -+Description: -+Level-1 D-Cache Penalty Cycle Count -+. -+Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES -+Description: -+Problem-State Cycle Count -+. -+Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS -+Description: -+Problem-State Instruction Count -+. ---- /dev/null -+++ b/cpumf/data/cpum-cf-csvn-generic.ctr -@@ -0,0 +1,84 @@ -+Counter: 64 Name:PRNG_FUNCTIONS -+Description: -+Total number of the PRNG functions issued by the CPU -+. -+Counter: 65 Name:PRNG_CYCLES -+Description: -+Total number of CPU cycles when the DEA/AES coprocessor is busy -+performing PRNG functions issued by the CPU -+. -+Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS -+Description: -+Total number of the PRNG functions that are issued by the CPU and are -+blocked because the DEA/AES coprocessor is busy performing a function -+issued by another CPU -+. -+Counter: 67 Name:PRNG_BLOCKED_CYCLES -+Description: -+Total number of CPU cycles blocked for the PRNG functions issued by -+the CPU because the DEA/AES coprocessor is busy performing a function -+issued by another CPU -+. -+Counter: 68 Name:SHA_FUNCTIONS -+Description: -+Total number of SHA functions issued by the CPU -+. -+Counter: 69 Name:SHA_CYCLES -+Description: -+Total number of CPU cycles when the SHA coprocessor is busy performing -+the SHA functions issued by the CPU -+. -+Counter: 70 Name:SHA_BLOCKED_FUNCTIONS -+Description: -+Total number of the SHA functions that are issued by the CPU and are -+blocked because the SHA coprocessor is busy performing a function issued -+by another CPU -+. -+Counter: 71 Name:SHA_BLOCKED_CYCLES -+Description: -+Total number of CPU cycles blocked for the SHA functions issued by the -+CPU because the SHA coprocessor is busy performing a function issued -+by another CPU -+. -+Counter: 72 Name:DEA_FUNCTIONS -+Description: -+Total number of the DEA functions issued by the CPU -+. -+Counter: 73 Name:DEA_CYCLES -+Description: -+Total number of CPU cycles when the DEA/AES coprocessor is busy -+performing the DEA functions issued by the CPU -+. -+Counter: 74 Name:DEA_BLOCKED_FUNCTIONS -+Description: -+Total number of the DEA functions that are issued by the CPU and are -+blocked because the DEA/AES coprocessor is busy performing a function -+issued by another CPU -+. -+Counter: 75 Name:DEA_BLOCKED_CYCLES -+Description: -+Total number of CPU cycles blocked for the DEA functions issued by the -+CPU because the DEA/AES coprocessor is busy performing a function issued -+by another CPU -+. -+Counter: 76 Name:AES_FUNCTIONS -+Description: -+Total number of AES functions issued by the CPU -+. -+Counter: 77 Name:AES_CYCLES -+Description: -+Total number of CPU cycles when the DEA/AES coprocessor is busy -+performing the AES functions issued by the CPU -+. -+Counter: 78 Name:AES_BLOCKED_FUNCTIONS -+Description: -+Total number of AES functions that are issued by the CPU and are blocked -+because the DEA/AES coprocessor is busy performing a function issued -+by another CPU -+. -+Counter: 79 Name:AES_BLOCKED_CYCLES -+Description: -+Total number of CPU cycles blocked for the AES functions issued by the -+CPU because the DEA/AES coprocessor is busy performing a function issued -+by another CPU -+. ---- a/cpumf/data/cpum-cf-generic.ctr -+++ /dev/null -@@ -1,132 +0,0 @@ --Counter: 0 Name:CPU_CYCLES --Description: --Cycle Count --. --Counter: 1 Name:INSTRUCTIONS --Description: --Instruction Count --. --Counter: 2 Name:L1I_DIR_WRITES --Description: --Level-1 I-Cache Directory Write Count --. --Counter: 3 Name:L1I_PENALTY_CYCLES --Description: --Level-1 I-Cache Penalty Cycle Count --. --Counter: 4 Name:L1D_DIR_WRITES --Description: --Level-1 D-Cache Directory Write Count --. --Counter: 5 Name:L1D_PENALTY_CYCLES --Description: --Level-1 D-Cache Penalty Cycle Count --. --Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES --Description: --Problem-State Cycle Count --. --Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS --Description: --Problem-State Instruction Count --. --Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES --Description: --Problem-State Level-1 I-Cache Directory Write Count --. --Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES --Description: --Problem-State Level-1 I-Cache Penalty Cycle Count --. --Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES --Description: --Problem-State Level-1 D-Cache Directory Write Count --. --Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES --Description: --Problem-State Level-1 D-Cache Penalty Cycle Count --. --Counter: 64 Name:PRNG_FUNCTIONS --Description: --Total number of the PRNG functions issued by the CPU --. --Counter: 65 Name:PRNG_CYCLES --Description: --Total number of CPU cycles when the DEA/AES coprocessor is busy --performing PRNG functions issued by the CPU --. --Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS --Description: --Total number of the PRNG functions that are issued by the CPU and are --blocked because the DEA/AES coprocessor is busy performing a function --issued by another CPU --. --Counter: 67 Name:PRNG_BLOCKED_CYCLES --Description: --Total number of CPU cycles blocked for the PRNG functions issued by --the CPU because the DEA/AES coprocessor is busy performing a function --issued by another CPU --. --Counter: 68 Name:SHA_FUNCTIONS --Description: --Total number of SHA functions issued by the CPU --. --Counter: 69 Name:SHA_CYCLES --Description: --Total number of CPU cycles when the SHA coprocessor is busy performing --the SHA functions issued by the CPU --. --Counter: 70 Name:SHA_BLOCKED_FUNCTIONS --Description: --Total number of the SHA functions that are issued by the CPU and are --blocked because the SHA coprocessor is busy performing a function issued --by another CPU --. --Counter: 71 Name:SHA_BLOCKED_CYCLES --Description: --Total number of CPU cycles blocked for the SHA functions issued by the --CPU because the SHA coprocessor is busy performing a function issued --by another CPU --. --Counter: 72 Name:DEA_FUNCTIONS --Description: --Total number of the DEA functions issued by the CPU --. --Counter: 73 Name:DEA_CYCLES --Description: --Total number of CPU cycles when the DEA/AES coprocessor is busy --performing the DEA functions issued by the CPU --. --Counter: 74 Name:DEA_BLOCKED_FUNCTIONS --Description: --Total number of the DEA functions that are issued by the CPU and are --blocked because the DEA/AES coprocessor is busy performing a function --issued by another CPU --. --Counter: 75 Name:DEA_BLOCKED_CYCLES --Description: --Total number of CPU cycles blocked for the DEA functions issued by the --CPU because the DEA/AES coprocessor is busy performing a function issued --by another CPU --. --Counter: 76 Name:AES_FUNCTIONS --Description: --Total number of AES functions issued by the CPU --. --Counter: 77 Name:AES_CYCLES --Description: --Total number of CPU cycles when the DEA/AES coprocessor is busy --performing the AES functions issued by the CPU --. --Counter: 78 Name:AES_BLOCKED_FUNCTIONS --Description: --Total number of AES functions that are issued by the CPU and are blocked --because the DEA/AES coprocessor is busy performing a function issued --by another CPU --. --Counter: 79 Name:AES_BLOCKED_CYCLES --Description: --Total number of CPU cycles blocked for the AES functions issued by the --CPU because the DEA/AES coprocessor is busy performing a function issued --by another CPU --. ---- a/cpumf/data/cpum-cf-hw-counter.map -+++ b/cpumf/data/cpum-cf-hw-counter.map -@@ -1,11 +1,22 @@ - # CPU-measurement facilities - # --# Mapping of IBM System z hardware types to extended counter set defintions -+# Mapping of: -+# 1. CPU-MF counter first/second version numbers to "generic" counter -+# definitions -+# 2. IBM z Systems hardware to respective extended counter set definitions - # - # - { - # Definition # File name -- 0 => 'cpum-cf-generic.ctr', -+ -+ # CFVN -+ 'cfvn-1' => 'cpum-cf-cfvn-1.ctr', -+ 'cfvn-3' => 'cpum-cf-cfvn-3.ctr', -+ -+ # CSVN -+ 'csvn-generic' => 'cpum-cf-csvn-generic.ctr', -+ -+ # Extended counters - 2097 => 'cpum-cf-extended-z10.ctr', - 2098 => 'cpum-cf-extended-z10.ctr', - 2817 => 'cpum-cf-extended-z196.ctr', diff --git a/s390-tools-sles15sp1-02-lszcrypt-fix-date-and-wrong-indentation.patch b/s390-tools-sles15sp1-02-lszcrypt-fix-date-and-wrong-indentation.patch deleted file mode 100644 index 91c03c4..0000000 --- a/s390-tools-sles15sp1-02-lszcrypt-fix-date-and-wrong-indentation.patch +++ /dev/null @@ -1,56 +0,0 @@ -Subject: lszcrypt: fix date and wrong indentation -From: Harald Freudenberger - -Summary: s390-tools: Exploitation Support for CEX6S -Description: Exploitation Support for CEX6S -Upstream-ID: 4ad5e29f2f02e02c772ca4707b9f10253b1e5692 -Problem-ID: SEC1519 - -Upstream-Description: - - lszcrypt: fix date and wrong indentation - - The man page date was AUG 2008. Changed to OCT 2017. - A previous commit had a wrong indentation on following - options text for lszcrypt. Fixed. - - Signed-off-by: Harald Freudenberger - Signed-off-by: Stefan Haberland - - -Signed-off-by: Harald Freudenberger ---- - zconf/zcrypt/chzcrypt.8 | 2 +- - zconf/zcrypt/lszcrypt.8 | 3 ++- - 2 files changed, 3 insertions(+), 2 deletions(-) - ---- a/zconf/zcrypt/chzcrypt.8 -+++ b/zconf/zcrypt/chzcrypt.8 -@@ -2,7 +2,7 @@ - .\" s390-tools is free software; you can redistribute it and/or modify - .\" it under the terms of the MIT license. See LICENSE for details. - .\" --.TH CHZCRYPT 8 "AUG 2008" "s390-tools" -+.TH CHZCRYPT 8 "OCT 2017" "s390-tools" - .SH NAME - chzcrypt \- modify zcrypt configuration - .SH SYNOPSIS ---- a/zconf/zcrypt/lszcrypt.8 -+++ b/zconf/zcrypt/lszcrypt.8 -@@ -10,7 +10,7 @@ - .\" nroff -man lszcrypt.8 - .\" to process this source - .\" --.TH LSZCRYPT 8 "AUG 2008" "s390-tools" -+.TH LSZCRYPT 8 "OCT 2017" "s390-tools" - .SH NAME - lszcrypt \- display zcrypt device and configuration information - .SH SYNOPSIS -@@ -91,6 +91,7 @@ The CCA Secure Key capability may be lim - layer. The remarks 'full function set' or 'restricted function set' may - reflect this. For details about these limitations please check the - hypervisor documentation. -+.RE - .TP 8 - .B -d, --domains - Shows the usage and control domains of the cryptographic devices. diff --git a/s390-tools-sles15sp1-02-lszcrypt-support-for-alternate-zcrypt-device-drivers.patch b/s390-tools-sles15sp1-02-lszcrypt-support-for-alternate-zcrypt-device-drivers.patch deleted file mode 100644 index 0ab8c4e..0000000 --- a/s390-tools-sles15sp1-02-lszcrypt-support-for-alternate-zcrypt-device-drivers.patch +++ /dev/null @@ -1,369 +0,0 @@ -Subject: lszcrypt: support for alternate zcrypt device drivers -From: Harald Freudenberger - -Summary: lszcrypt: support for alternate zcrypt device drivers -Description: With kernel 4.19 there comes an extension to the - existing AP bus which supports alternate zcrypt - drivers. For details about this see kernel patch - "s390/zcrypt: AP bus support for alternate - driver(s)". So now lszcrypt displays the driver name - in verbose mode. As some of the information - displayed by lszcrypt was based on sysfs attributes, - which are only available when the default zcrypt - driver is bound to the device, this also needed some - rework. If a sysfs attribute is not available - because of an alternate driver binding (or no - driver) a question mark is printed into the field. -Upstream-ID: 0a0b4c382693cded5652404e8fa2c0e483aa33df -Problem-ID: SEC1806 - -Upstream-Description: - - lszcrypt: support for alternate zcrypt device drivers - - With kernel 4.19 there comes an extension to the existing - AP bus which supports alternate zcrypt drivers. For details - about this see kernel patch "s390/zcrypt: AP bus support for - alternate driver(s)". So now lszcrypt displays the driver - name in verbose mode. As some of the information displayed - by lszcrypt was based on sysfs attributes, which are only - available when the default zcrypt driver is bound to the - device, this also needed some rework. If a sysfs attribute - is not available because of an alternate driver binding - (or no driver) a question mark is printed into the field. - - Together with this a slight rework of the displayed information - has been done. The two columns for pending requests and pending - replies has been merged to one pending column and the column - sizes have been adjusted. - - Signed-off-by: Harald Freudenberger - Signed-off-by: Jan Höppner - - -Signed-off-by: Harald Freudenberger ---- - zconf/zcrypt/lszcrypt.8 | 4 - - zconf/zcrypt/lszcrypt.c | 163 ++++++++++++++++++++++++++++++++---------------- - 2 files changed, 112 insertions(+), 55 deletions(-) - ---- a/zconf/zcrypt/lszcrypt.8 -+++ b/zconf/zcrypt/lszcrypt.8 -@@ -54,8 +54,8 @@ status. - .B -V, --verbose - The verbose level for cryptographic device information. - With this verbose level additional information like hardware card type, --hardware queue depth, pending request queue count, outstanding --request queue count, and installed function facilities are displayed. -+hardware queue depth, pending requests count, installed function -+facilities and driver binding is displayed. - .TP 8 - .B - Specifies a cryptographic device to display. A cryptographic device can be ---- a/zconf/zcrypt/lszcrypt.c -+++ b/zconf/zcrypt/lszcrypt.c -@@ -1,7 +1,7 @@ - /** - * lszcrypt - Display zcrypt devices and configuration settings - * -- * Copyright IBM Corp. 2008, 2017 -+ * Copyright IBM Corp. 2008, 2018 - * - * s390-tools is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. -@@ -57,6 +57,25 @@ struct lszcrypt_l *lszcrypt_l = &l; - #define CLASS_STATELESS "restricted function set" - - /* -+ * facility bits -+ */ -+#define MAX_FAC_BITS 9 -+static struct fac_bits_s { -+ int mask; -+ char c; -+} fac_bits[MAX_FAC_BITS] = { -+ { 0x80000000, 'S' }, -+ { 0x40000000, 'M' }, -+ { 0x20000000, 'C' }, -+ { 0x10000000, 'D' }, -+ { 0x08000000, 'A' }, -+ { 0x04000000, 'X' }, -+ { 0x02000000, 'N' }, -+ { 0x00800000, 'F' }, -+ { 0x00400000, 'R' }, -+}; -+ -+/* - * Program configuration - */ - const struct util_prg prg = { -@@ -66,7 +85,7 @@ const struct util_prg prg = { - { - .owner = "IBM Corp.", - .pub_first = 2008, -- .pub_last = 2017, -+ .pub_last = 2018, - }, - UTIL_PRG_COPYRIGHT_END - } -@@ -255,7 +274,8 @@ static void show_capability(const char * - /* Skip devices, which are not supported by zcrypt layer */ - if (!util_path_is_readable("%s/type", dev) || - !util_path_is_readable("%s/online", dev)) { -- printf("Detailed capability information for %s (hardware type %ld) is not available.\n", card, hwtype); -+ printf("Detailed capability information for %s (hardware type %ld) is not available.\n", -+ card, hwtype); - return; - } - cbuf[0] = '\0'; -@@ -299,11 +319,13 @@ static void show_capability(const char * - } else if (func_val & MASK_EP11) { - printf("%s", CAP_EP11); - } else { -- printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype); -+ printf("Detailed capability information for %s (hardware type %ld) is not available.", -+ card, hwtype); - } - break; - default: -- printf("Detailed capability information for %s (hardware type %ld) is not available.", card, hwtype); -+ printf("Detailed capability information for %s (hardware type %ld) is not available.", -+ card, hwtype); - break; - } - printf("\n"); -@@ -315,17 +337,22 @@ static void show_capability(const char * - static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev, - const char *sub_dev) - { -- unsigned long facility; - char buf[256]; -+ unsigned long facility; - -- util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev); -- util_rec_set(rec, "type", buf); -+ if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev)) -+ util_rec_set(rec, "type", "-"); -+ else -+ util_rec_set(rec, "type", buf); - -- util_file_read_line(buf, sizeof(buf), "%s/%s/online", grp_dev, sub_dev); -- if (strcmp(buf, "0") == 0) -- util_rec_set(rec, "online", "offline"); -+ if (util_file_read_line(buf, sizeof(buf), "%s/%s/online", -+ grp_dev, sub_dev)) -+ util_rec_set(rec, "online", "-"); - else -- util_rec_set(rec, "online", "online"); -+ if (strcmp(buf, "0") == 0) -+ util_rec_set(rec, "online", "offline"); -+ else -+ util_rec_set(rec, "online", "online"); - - util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); - if (facility & MASK_COPRO) -@@ -339,7 +366,7 @@ static void read_subdev_rec_default(stru - - util_file_read_line(buf, sizeof(buf), "%s/%s/request_count", - grp_dev, sub_dev); -- util_rec_set(rec, "request_count", buf); -+ util_rec_set(rec, "requests", buf); - } - - /* -@@ -348,20 +375,19 @@ static void read_subdev_rec_default(stru - static void read_subdev_rec_verbose(struct util_rec *rec, const char *grp_dev, - const char *sub_dev) - { -+ int i; - unsigned long facility; -- char buf[256]; -- long depth; -+ char buf[256], afile[PATH_MAX]; -+ long depth, pending1, pending2; - - if (l.verbose == 0) - return; - -- util_file_read_line(buf, sizeof(buf), "%s/%s/pendingq_count", -- grp_dev, sub_dev); -- util_rec_set(rec, "pendingq_count", buf); -- -- util_file_read_line(buf, sizeof(buf), "%s/%s/requestq_count", -- grp_dev, sub_dev); -- util_rec_set(rec, "requestq_count", buf); -+ util_file_read_l(&pending1, 10, "%s/%s/pendingq_count", -+ grp_dev, sub_dev); -+ util_file_read_l(&pending2, 10, "%s/%s/requestq_count", -+ grp_dev, sub_dev); -+ util_rec_set(rec, "pending", "%ld", pending1 + pending2); - - util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev); - util_rec_set(rec, "hwtype", buf); -@@ -370,7 +396,18 @@ static void read_subdev_rec_verbose(stru - util_rec_set(rec, "depth", "%02d", depth + 1); - - util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); -- util_rec_set(rec, "facility", "0x%08x", facility); -+ for (i = 0; i < MAX_FAC_BITS; i++) -+ buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-'; -+ buf[i] = '\0'; -+ util_rec_set(rec, "facility", buf); -+ -+ snprintf(afile, sizeof(afile), "%s/%s/driver", grp_dev, sub_dev); -+ afile[sizeof(afile) - 1] = '\0'; -+ memset(buf, 0, sizeof(buf)); -+ if (readlink(afile, buf, sizeof(buf)) > 0) -+ util_rec_set(rec, "driver", strrchr(buf, '/') + 1); -+ else -+ util_rec_set(rec, "driver", "-no-driver-"); - } - - /* -@@ -382,9 +419,13 @@ static void show_subdevice(struct util_r - if (!util_path_is_dir("%s/%s", grp_dev, sub_dev)) - errx(EXIT_FAILURE, "Error - cryptographic device %s/%s does not exist.", grp_dev, sub_dev); - -- /* Skip devices, which are not supported by zcrypt layer */ -- if (!util_path_is_readable("%s/type", grp_dev) || -- !util_path_is_readable("%s/%s/online", grp_dev, sub_dev)) -+ /* -+ * If not verbose mode, skip devices which are not supported -+ * by the zcrypt layer. -+ */ -+ if (l.verbose == 0 && -+ (!util_path_is_readable("%s/type", grp_dev) || -+ !util_path_is_readable("%s/%s/online", grp_dev, sub_dev))) - return; - - util_rec_set(rec, "card", sub_dev); -@@ -414,11 +455,13 @@ static void show_subdevices(struct util_ - */ - static void read_rec_default(struct util_rec *rec, const char *grp_dev) - { -- unsigned long facility; - char buf[256]; -+ unsigned long facility; - -- util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev); -- util_rec_set(rec, "type", buf); -+ if (util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev)) -+ util_rec_set(rec, "type", "-"); -+ else -+ util_rec_set(rec, "type", buf); - - util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); - if (facility & MASK_COPRO) -@@ -430,14 +473,16 @@ static void read_rec_default(struct util - else - util_rec_set(rec, "mode", "Unknown"); - -- util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev); -- if (strcmp(buf, "0") == 0) -- util_rec_set(rec, "online", "offline"); -+ if (util_file_read_line(buf, sizeof(buf), "%s/online", grp_dev)) -+ util_rec_set(rec, "online", "-"); - else -- util_rec_set(rec, "online", "online"); -+ if (strcmp(buf, "0") == 0) -+ util_rec_set(rec, "online", "offline"); -+ else -+ util_rec_set(rec, "online", "online"); - - util_file_read_line(buf, sizeof(buf), "%s/request_count", grp_dev); -- util_rec_set(rec, "request_count", buf); -+ util_rec_set(rec, "requests", buf); - } - - /* -@@ -445,18 +490,17 @@ static void read_rec_default(struct util - */ - static void read_rec_verbose(struct util_rec *rec, const char *grp_dev) - { -+ int i; - unsigned long facility; -- char buf[256]; -- long depth; -+ char buf[256], afile[PATH_MAX]; -+ long depth, pending1, pending2; - - if (l.verbose == 0) - return; - -- util_file_read_line(buf, sizeof(buf), "%s/pendingq_count", grp_dev); -- util_rec_set(rec, "pendingq_count", buf); -- -- util_file_read_line(buf, sizeof(buf), "%s/requestq_count", grp_dev); -- util_rec_set(rec, "requestq_count", buf); -+ util_file_read_l(&pending1, 10, "%s/pendingq_count", grp_dev); -+ util_file_read_l(&pending2, 10, "%s/requestq_count", grp_dev); -+ util_rec_set(rec, "pending", "%ld", pending1 + pending2); - - util_file_read_line(buf, sizeof(buf), "%s/hwtype", grp_dev); - util_rec_set(rec, "hwtype", buf); -@@ -465,7 +509,18 @@ static void read_rec_verbose(struct util - util_rec_set(rec, "depth", "%02d", depth + 1); - - util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev); -- util_rec_set(rec, "facility", "0x%08x", facility); -+ for (i = 0; i < MAX_FAC_BITS; i++) -+ buf[i] = facility & fac_bits[i].mask ? fac_bits[i].c : '-'; -+ buf[i] = '\0'; -+ util_rec_set(rec, "facility", buf); -+ -+ snprintf(afile, sizeof(afile), "%s/driver", grp_dev); -+ afile[sizeof(afile) - 1] = '\0'; -+ memset(buf, 0, sizeof(buf)); -+ if (readlink(afile, buf, sizeof(buf)) > 0) -+ util_rec_set(rec, "driver", strrchr(buf, '/') + 1); -+ else -+ util_rec_set(rec, "driver", "-no-driver-"); - } - - /* -@@ -481,9 +536,14 @@ static void show_device(struct util_rec - grp_dev = util_path_sysfs("devices/ap/%s", device); - if (!util_path_is_dir(grp_dev)) - errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device); -- /* Skip devices, which are not supported by zcrypt layer */ -- if (!util_path_is_readable("%s/type", grp_dev) || -- !util_path_is_readable("%s/online", grp_dev)) { -+ -+ /* -+ * If not verbose mode, skip devices which are not supported -+ * by the zcrypt layer. -+ */ -+ if (l.verbose == 0 && -+ (!util_path_is_readable("%s/type", grp_dev) || -+ !util_path_is_readable("%s/online", grp_dev))) { - goto out_free; - } - util_rec_set(rec, "card", card); -@@ -506,8 +566,7 @@ static void define_rec_default(struct ut - util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE"); - util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE"); - util_rec_def(rec, "online", UTIL_REC_ALIGN_LEFT, 7, "STATUS"); -- util_rec_def(rec, "request_count", UTIL_REC_ALIGN_RIGHT, 11, -- "REQUEST_CNT"); -+ util_rec_def(rec, "requests", UTIL_REC_ALIGN_RIGHT, 8, "REQUESTS"); - } - - /* -@@ -517,13 +576,11 @@ static void define_rec_verbose(struct ut - { - if (l.verbose == 0) - return; -- util_rec_def(rec, "pendingq_count", UTIL_REC_ALIGN_RIGHT, 12, -- "PENDINGQ_CNT"); -- util_rec_def(rec, "requestq_count", UTIL_REC_ALIGN_RIGHT, 12, -- "REQUESTQ_CNT"); -- util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 7, "HW_TYPE"); -- util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 7, "Q_DEPTH"); -+ util_rec_def(rec, "pending", UTIL_REC_ALIGN_RIGHT, 8, "PENDING"); -+ util_rec_def(rec, "hwtype", UTIL_REC_ALIGN_RIGHT, 6, "HWTYPE"); -+ util_rec_def(rec, "depth", UTIL_REC_ALIGN_RIGHT, 6, "QDEPTH"); - util_rec_def(rec, "facility", UTIL_REC_ALIGN_LEFT, 10, "FUNCTIONS"); -+ util_rec_def(rec, "driver", UTIL_REC_ALIGN_LEFT, 11, "DRIVER"); - } - - /* diff --git a/s390-tools-sles15sp1-02-util_path-Add-description-for-util_path_exists.patch b/s390-tools-sles15sp1-02-util_path-Add-description-for-util_path_exists.patch deleted file mode 100644 index 72fb9e3..0000000 --- a/s390-tools-sles15sp1-02-util_path-Add-description-for-util_path_exists.patch +++ /dev/null @@ -1,43 +0,0 @@ -Subject: util_path: Add description for util_path_exists() -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: d0e2caf0ffb195568bba89a95549a5a4f026a4e6 -Problem-ID: RAS1703 - -Upstream-Description: - - util_path: Add description for util_path_exists() - - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jan Hoeppner ---- - libutil/util_path.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - ---- a/libutil/util_path.c -+++ b/libutil/util_path.c -@@ -195,6 +195,17 @@ free_str: - return rc; - } - -+/** -+ * Test if path to directory or file exists -+ * -+ * This function has the same semantics as "-e path" in bash. -+ * -+ * @param[in] fmt Format string for path to test -+ * @param[in] ... Variable arguments for format string -+ * -+ * @returns true Path exists -+ * false Otherwise -+ */ - bool util_path_exists(const char *fmt, ...) - { - va_list ap; diff --git a/s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch b/s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch deleted file mode 100644 index 6c528d1..0000000 --- a/s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch +++ /dev/null @@ -1,287 +0,0 @@ -Subject: zdev: Prepare for firmware configuration file support -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: ab4445c261749caa7aee2154e3b26c767b6c5e60 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Prepare for firmware configuration file support - - Apply some changes to existing functions and data structures to simplify - the firmware configuration file support implementation. - - - Make qeth and dasd subtype objects non-static - - Change the existing helper functions for reading file contents into - memory to also support binary functions - - Move some configuration file import functions to make them available - for use in other source files - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/dasd.h | 3 ++ - zdev/include/device.h | 2 + - zdev/include/export.h | 1 - zdev/include/misc.h | 1 - zdev/include/qeth.h | 2 + - zdev/src/dasd.c | 4 +-- - zdev/src/device.c | 13 +++++++++++ - zdev/src/export.c | 17 +------------- - zdev/src/misc.c | 48 ++++++++++++++++++++++++++++++------------ - zdev/src/qeth.c | 2 - - 10 files changed, 62 insertions(+), 31 deletions(-) - ---- a/zdev/include/dasd.h -+++ b/zdev/include/dasd.h -@@ -11,7 +11,10 @@ - #define DASD_H - - struct devtype; -+struct subtype; - - extern struct devtype dasd_devtype; -+extern struct subtype dasd_subtype_eckd; -+extern struct subtype dasd_subtype_fba; - - #endif /* DASD_H */ ---- a/zdev/include/device.h -+++ b/zdev/include/device.h -@@ -94,5 +94,7 @@ void device_list_add(struct device_list - struct device *device_list_find(struct device_list *, const char *, - struct device *); - void device_list_print(struct device_list *, int); -+struct setting_list *device_get_setting_list(struct device *dev, -+ config_t config); - - #endif /* DEVICE_H */ ---- a/zdev/include/export.h -+++ b/zdev/include/export.h -@@ -31,6 +31,7 @@ struct export_object { - } ptr; - }; - -+struct export_object *object_new(export_t type, void *ptr); - exit_code_t export_write_device(FILE *, struct device *, config_t, int *); - exit_code_t export_write_devtype(FILE *, struct devtype *, config_t, int *); - exit_code_t export_read(FILE *, const char *, struct util_list *); ---- a/zdev/include/misc.h -+++ b/zdev/include/misc.h -@@ -159,6 +159,7 @@ bool misc_read_dir(const char *, struct - bool (*)(const char *, void *), void *); - bool file_is_devnode(const char *); - exit_code_t remove_file(const char *); -+exit_code_t misc_read_fd(FILE *fd, void **buffer, size_t *size_ptr); - char *misc_read_text_file(const char *, int, err_t); - char *misc_read_cmd_output(const char *, int, err_t); - char *config_read_cmd_output(const char *, int, err_t); ---- a/zdev/include/qeth.h -+++ b/zdev/include/qeth.h -@@ -17,9 +17,11 @@ - #define QETH_NUM_DEVS 3 - - struct devtype; -+struct subtype; - struct namespace; - - extern struct devtype qeth_devtype; -+extern struct subtype qeth_subtype_qeth; - extern struct namespace qeth_namespace; - - #endif /* QETH_H */ ---- a/zdev/src/dasd.c -+++ b/zdev/src/dasd.c -@@ -589,7 +589,7 @@ static struct ccw_subtype_data dasd_eckd - .mod = "dasd_eckd_mod", - }; - --static struct subtype dasd_subtype_eckd = { -+struct subtype dasd_subtype_eckd = { - .super = &ccw_subtype, - .devtype = &dasd_devtype, - .name = "dasd-eckd", -@@ -626,7 +626,7 @@ static struct ccw_subtype_data dasd_fba_ - .mod = "dasd_fba_mod", - }; - --static struct subtype dasd_subtype_fba = { -+struct subtype dasd_subtype_fba = { - .super = &ccw_subtype, - .devtype = &dasd_devtype, - .name = "dasd-fba", ---- a/zdev/src/device.c -+++ b/zdev/src/device.c -@@ -570,3 +570,16 @@ exit_code_t device_check_settings(struct - - return EXIT_OK; - } -+ -+struct setting_list *device_get_setting_list(struct device *dev, -+ config_t config) -+{ -+ struct setting_list *settings = NULL; -+ -+ if (config == config_active) -+ settings = dev->active.settings; -+ else -+ settings = dev->persistent.settings; -+ -+ return settings; -+} ---- a/zdev/src/export.c -+++ b/zdev/src/export.c -@@ -282,19 +282,6 @@ static bool parse_setting(const char *li - return true; - } - --static struct setting_list *dev_get_setting_list(struct device *dev, -- config_t config) --{ -- struct setting_list *settings = NULL; -- -- if (config == config_active) -- settings = dev->active.settings; -- else -- settings = dev->persistent.settings; -- -- return settings; --} -- - static struct setting_list *dt_get_setting_list(struct devtype *dt, - config_t config) - { -@@ -426,7 +413,7 @@ static exit_code_t handle_setting(const - } else if (dev) { - /* We're inside a device section. */ - attribs = dev->subtype->dev_attribs; -- list = dev_get_setting_list(dev, config); -+ list = device_get_setting_list(dev, config); - } else - return EXIT_OK; - -@@ -444,7 +431,7 @@ static exit_code_t handle_setting(const - return EXIT_OK; - } - --static struct export_object *object_new(export_t type, void *ptr) -+struct export_object *object_new(export_t type, void *ptr) - { - struct export_object *obj; - ---- a/zdev/src/misc.c -+++ b/zdev/src/misc.c -@@ -98,26 +98,47 @@ static void dryrun_end_data(void) - - #define READ_CHUNK_SIZE 4096 - --/* Read text from @fd and return resulting NULL-terminated text buffer. -- * If @chomp is non-zero, remove trailing newline character. Return %NULL -- * on error or when unprintable characters are read. */ --static char *read_fd(FILE *fd, int chomp) -+/* Read all data from @fd and return address of resulting buffer in -+ * @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the -+ * resulting buffer. Return %EXIT_OK on success. */ -+exit_code_t misc_read_fd(FILE *fd, void **buffer_ptr, size_t *size_ptr) - { - char *buffer = NULL; -- size_t done, i; -+ size_t done = 0; - -- done = 0; - while (!feof(fd)) { -- buffer = realloc(buffer, done + READ_CHUNK_SIZE + 1); -+ buffer = realloc(buffer, done + READ_CHUNK_SIZE); - if (!buffer) - oom(); - done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd); - if (ferror(fd)) { - free(buffer); -- return NULL; -+ return EXIT_RUNTIME_ERROR; - } - } - -+ buffer = realloc(buffer, done); -+ if (!buffer && done > 0) -+ oom(); -+ -+ *buffer_ptr = buffer; -+ if (size_ptr) -+ *size_ptr = done; -+ -+ return EXIT_OK; -+} -+ -+/* Read text from @fd and return resulting NULL-terminated text buffer. -+ * If @chomp is non-zero, remove trailing newline character. Return %NULL -+ * on error or when unprintable characters are read. */ -+static char *read_fd(FILE *fd, int chomp) -+{ -+ char *buffer; -+ size_t done, i; -+ -+ if (misc_read_fd(fd, (void **) &buffer, &done)) -+ return NULL; -+ - /* Check if this is a text file at all (required to filter out - * binary sysfs attributes). */ - for (i = 0; i < done; i++) { -@@ -131,12 +152,13 @@ static char *read_fd(FILE *fd, int chomp - if (chomp && done > 0 && buffer[done - 1] == '\n') - done--; - -- if (buffer) { -- /* NULL-terminate. */ -- buffer[done++] = 0; -- } -+ /* NULL-terminate. */ -+ buffer = realloc(buffer, done + 1); -+ if (!buffer) -+ oom(); -+ buffer[done] = 0; - -- return realloc(buffer, done); -+ return buffer; - } - - static int count_newline(const char *str) ---- a/zdev/src/qeth.c -+++ b/zdev/src/qeth.c -@@ -1369,7 +1369,7 @@ static struct ccwgroup_subtype_data qeth - .num_devs = QETH_NUM_DEVS, - }; - --static struct subtype qeth_subtype_qeth = { -+struct subtype qeth_subtype_qeth = { - .super = &ccwgroup_subtype, - .devtype = &qeth_devtype, - .name = "qeth", diff --git a/s390-tools-sles15sp1-03-cpumf-cpumf_helper-read-split-counter-sets-part-2-2.patch b/s390-tools-sles15sp1-03-cpumf-cpumf_helper-read-split-counter-sets-part-2-2.patch deleted file mode 100644 index b8e6dfe..0000000 --- a/s390-tools-sles15sp1-03-cpumf-cpumf_helper-read-split-counter-sets-part-2-2.patch +++ /dev/null @@ -1,107 +0,0 @@ -Subject: cpumf/cpumf_helper: read split counter sets (part 2/2) -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: 1064e5b9cc3bdeb5731c2e152ce146dfdad27e6f -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf/cpumf_helper: read split counter sets (part 2/2) - - Update the cpumf helper program to read the split counter set - definition files. Changes to higher-level program like lscpumf - are not necessary. - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Stefan Haberland - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/bin/cpumf_helper.in | 50 ++++++++++++++++++++++++++++++++++++++-------- - 1 file changed, 42 insertions(+), 8 deletions(-) - ---- a/cpumf/bin/cpumf_helper.in -+++ b/cpumf/bin/cpumf_helper.in -@@ -229,6 +229,28 @@ sub get_hardware_type() - return $type; - } - -+sub get_cpum_cf_version() -+{ -+ my $SL; -+ -+ my $v = { -+ cfvn => 0, -+ csvn => 0, -+ }; -+ -+ return $v unless open($SL, '<', $SERVICE_LEVELS); -+ while (my $line = <$SL>) { -+ # CPU-MF: Counter facility: version=3.5 -+ if ($line =~ m/^CPU-MF: Counter facility: version=(\d+)\.(\d+)/) { -+ $v->{cfvn} = $1; # Counter First Version Number -+ $v->{csvn} = $2; # Counter Second Version Number -+ last; -+ } -+ } -+ close($SL); -+ return $v -+} -+ - sub cpumf_load_ctrdef($;$) - { - my $hw_type = shift(); -@@ -237,10 +259,20 @@ sub cpumf_load_ctrdef($;$) - my $ctrmap = cpumf_hardware_counter_map(); - return unless $ctrmap; - -+ # Obtain CPU-MF counter facility versions -+ my $version = get_cpum_cf_version(); -+ -+ # List of "generic" counter sets -+ my @def = (); -+ push @def, "cfvn-" . $version->{cfvn}; -+ push @def, "csvn-generic"; -+ - my $h = {}; -- # Load generic counter sets -- cpumf_parse_ctrdef($ctrmap->{0}, $h) or -- croak "Failed to read generic counter definition: $!\n"; -+ # Load counter set definition -+ foreach my $ent (@def) { -+ cpumf_parse_ctrdef($ctrmap->{$ent}, $h) or -+ croak "Failed to read counter definition for $ent: $!\n"; -+ } - # Load hardware model specific counter set(s) - if ($hw_type && $ctrmap->{$hw_type}) { - # Hardware-model specific counter sets are: -@@ -323,7 +355,7 @@ sub cpumf_helper_main() - GetOptions( - "i|info" => \$conf->{opt_info}, - "c|counter=i" => \$conf->{opt_ctr}, -- "ctr-def=i" => \$conf->{opt_ctrdef}, -+ "ctr-def=s" => \$conf->{opt_ctrdef}, - "hardware-type" => \$conf->{opt_hwtype}, - "ctr-set-names" => \$conf->{opt_ctrset_names}, - "ctr-set-ids" => \$conf->{opt_ctrset_ids}, -@@ -428,11 +460,13 @@ B<--ctr-def> option and specify the Syst - - Displays the System z hardware type. - --=item B<--ctr-def> I -+=item B<--ctr-def> I - --Displays detailed information about a particular counter set for the specified --System z hardware type, I. If you specify zero for --I, type-independent counter sets are displayed. -+Displays detailed information about the specified counter definition. -+Valid counter definitions start with C or followed by -+the counter first/second version number of the CPU-Measurement Counter -+Facility. To display counter information of model-specific counter -+sets, specify the System z hardware type for I. - - =item B<--ctr-set-names> - diff --git a/s390-tools-sles15sp1-03-util_path-Make-true-false-handling-consistent-with-o.patch b/s390-tools-sles15sp1-03-util_path-Make-true-false-handling-consistent-with-o.patch deleted file mode 100644 index 0ac8c00..0000000 --- a/s390-tools-sles15sp1-03-util_path-Make-true-false-handling-consistent-with-o.patch +++ /dev/null @@ -1,34 +0,0 @@ -Subject: util_path: Make true/false handling consistent with other functions -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: 2b92bc4c087fd7a2275ba8fd5608cf3c86cdcc98 -Problem-ID: RAS1703 - -Upstream-Description: - - util_path: Make true/false handling consistent with other functions - - Signed-off-by: Michael Holzheu - - -Signed-off-by: Jan Hoeppner ---- - libutil/util_path.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/libutil/util_path.c -+++ b/libutil/util_path.c -@@ -213,7 +213,7 @@ bool util_path_exists(const char *fmt, . - bool rc; - - UTIL_VASPRINTF(&path, fmt, ap); -- rc = access(path, F_OK) == 0; -+ rc = access(path, F_OK) == 0 ? true : false; - free(path); - return rc; - } diff --git a/s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch b/s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch deleted file mode 100644 index a20a3fa..0000000 --- a/s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch +++ /dev/null @@ -1,874 +0,0 @@ -Subject: zdev: Add support for reading firmware configuration files -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: 7d355b0fec964ad84ecaf88eb946121d39486070 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Add support for reading firmware configuration files - - Add support for reading firmware-provided I/O configuration data files. - Such configuration files are generated by the Dynamic Partition Manager - and made available via a kernel interface for consumption by Linux. - - To read a firmware configuration file, use the existing --import option: - - # chzdev --import /sys/firmware/sclp_sd/config/data - - This will apply all I/O configuration data found in the specified file - to the persistent configuration. - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/firmware.h | 25 + - zdev/man/chzdev.8 | 16 - zdev/src/Makefile | 2 - zdev/src/chzdev.c | 21 - - zdev/src/firmware.c | 676 ++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 730 insertions(+), 10 deletions(-) - ---- /dev/null -+++ b/zdev/include/firmware.h -@@ -0,0 +1,25 @@ -+/* -+ * zdev - Modify and display the persistent configuration of devices -+ * -+ * Copyright IBM Corp. 2017 -+ * -+ * 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 FIRMWARE_H -+#define FIRMWARE_H -+ -+#include -+#include -+ -+#include "exit_code.h" -+#include "misc.h" -+ -+struct util_list; -+ -+bool firmware_detect(FILE *fd); -+exit_code_t firmware_read(FILE *fd, const char *filename, long skip, -+ config_t config, struct util_list *objects); -+ -+#endif /* FIRMWARE_H */ ---- a/zdev/man/chzdev.8 -+++ b/zdev/man/chzdev.8 -@@ -409,13 +409,23 @@ default value. - .PP - . - .OD import "" "FILENAME" "|-" --Import configuration data from a text file. -+Import configuration data from a text or machine-provided file. - - Reads configuration data from FILENAME and applies it. If a single hyphen ("-") - is specified as FILENAME data is read from the standard input stream. The --input format of the data read must be the same format as produced by the --chzdev \-\-export action. -+input format must be either in the format as produced by the chzdev \-\-export -+action, or in the format of a machine-provided I/O configuration data file. - -+.B Machine-provided data: -+Some machine models provide I/O configuration data which is made available -+by the Linux kernel via a sysfs interface. While this data is intended for -+automatic consumption during the boot phase, you can also apply it manually -+using the \-\-import action like in the following example -+ -+.B Example: -+.CL chzdev --import /sys/firmware/sclp_sd/config/data -+ -+.B Note: - By default all configuration data that is read is also applied. To reduce the - scope of imported configuration data, you can select specific devices, a device - type, or define whether only data for the active or persistent configuration ---- a/zdev/src/Makefile -+++ b/zdev/src/Makefile -@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 - chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \ - export.o hash.o inuse.o misc.o namespace.o opts.o path.o \ - root.o select.o setting.o subtype.o table.o table_attribs.o \ -- table_types.o net.o -+ table_types.o net.o firmware.o - - # Devtype Helpers - chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \ ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -27,6 +27,7 @@ - #include "devnode.h" - #include "devtype.h" - #include "export.h" -+#include "firmware.h" - #include "inuse.h" - #include "misc.h" - #include "module.h" -@@ -2500,9 +2501,9 @@ static exit_code_t do_export(struct opti - /* Open output stream. */ - if (strcmp(opts->export, "-") == 0) { - fd = stdout; -- info("Exporting configuration data to standard output\n"); -+ info("Exporting data to standard output\n"); - } else { -- info("Exporting configuration data to %s\n", opts->export); -+ info("Exporting data to %s\n", opts->export); - if (!util_path_exists(opts->export)) { - rc = path_create(opts->export); - if (rc) -@@ -2735,6 +2736,7 @@ static exit_code_t do_import(struct opti - exit_code_t drc = EXIT_OK; - const char *filename; - int found; -+ bool is_firmware; - - /* Open input stream. */ - if (strcmp(opts->import, "-") == 0) { -@@ -2744,16 +2746,23 @@ static exit_code_t do_import(struct opti - fd = fopen(opts->import, "r"); - filename = opts->import; - } -- info("Importing configuration data from %s\n", filename); -+ - if (!fd) { - error("Could not open file %s: %s\n", opts->import, - strerror(errno)); - return EXIT_RUNTIME_ERROR; - } - -+ is_firmware = firmware_detect(fd); -+ info("Importing data from %s%s\n", filename, -+ is_firmware ? " (firmware format)" : ""); -+ - /* Read data. */ - objects = ptrlist_new(); -- rc = export_read(fd, filename, objects); -+ if (is_firmware) -+ rc = firmware_read(fd, filename, -1, opts->config, objects); -+ else -+ rc = export_read(fd, filename, objects); - if (rc) - goto out; - -@@ -2766,8 +2775,8 @@ static exit_code_t do_import(struct opti - "selection\n", filename); - rc = EXIT_EMPTY_SELECTION; - } else { -- error("%s: No settings found to import\n", filename); -- rc = EXIT_NO_DATA; -+ info("%s: No settings found to import\n", filename); -+ rc = EXIT_OK; - } - goto out; - } ---- /dev/null -+++ b/zdev/src/firmware.c -@@ -0,0 +1,676 @@ -+/* -+ * zdev - Modify and display the persistent configuration of devices -+ * -+ * Copyright IBM Corp. 2017 -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "attrib.h" -+#include "ccw.h" -+#include "ccwgroup.h" -+#include "dasd.h" -+#include "device.h" -+#include "export.h" -+#include "firmware.h" -+#include "misc.h" -+#include "qeth.h" -+#include "subtype.h" -+#include "zfcp_host.h" -+#include "zfcp_lun.h" -+ -+/* In-memory firmware file representation. */ -+struct fw_file { -+ const char *name; -+ char *buffer; -+ size_t size; -+ char *last_access; -+ size_t last_size; -+}; -+ -+/* Record access to fields of the buffered file for use in warning messages. */ -+#define fwacc(f, x) ((f)->last_access = (char *) &(x), \ -+ (f)->last_size = sizeof(x), x) -+ -+/* -+ * Firmware file format definitions. -+ */ -+ -+/* Firmware file header. */ -+struct fw_filehdr { -+ uint32_t magic; -+ uint16_t ver; -+ uint16_t hdr_len; -+ uint32_t file_len; -+ uint32_t seq; -+ uint32_t zeroes; -+ uint16_t de_count; -+ char unused[10]; -+} __packed; -+ -+#define FW_HDR_MAGIC 0x7a646576 /* ASCII "zdev" */ -+#define FW_HDR_VER_Z14 0x0000 -+ -+/* I/O device ID. */ -+struct fw_iodevid { -+ uint8_t cssid; -+ uint8_t ssid; -+ uint16_t devno; -+} __packed; -+ -+#define FW_IODEVID_FLAG_MCSS 0x01 -+ -+/* Device setting. */ -+struct fw_setting { -+ uint16_t len; -+ uint8_t key_type; -+ uint8_t key_len; -+ uint8_t val_type; -+ uint8_t val_len; -+ char data[]; -+} __packed; -+ -+#define FW_SETTING_KEYTYPE_ASCII 0x00 -+#define FW_SETTING_VALTYPE_ASCII 0x00 -+#define FW_SETTING_VALTYPE_UINT 0x01 -+ -+/* Device settings list. */ -+struct fw_setlist { -+ uint16_t len; -+ char data[]; -+} __packed; -+ -+/* Device entry header. */ -+struct fw_dehdr { -+ uint16_t type; -+ uint16_t len; -+ uint32_t seq; -+} __packed; -+ -+#define FW_DE_HDR_TYPE_DASD 0x0001 -+#define FW_DE_HDR_TYPE_ZFCP_HOST 0x0002 -+#define FW_DE_HDR_TYPE_ZFCP_LUN 0x0003 -+#define FW_DE_HDR_TYPE_QETH 0x0004 -+ -+/* DASD device entry. */ -+struct fw_dasd { -+ struct fw_dehdr hdr; -+ uint8_t id_flags; -+ struct fw_iodevid id; -+ char settings[]; -+} __packed; -+ -+/* zFCP host device entry. */ -+struct fw_zfcp_host { -+ struct fw_dehdr hdr; -+ uint8_t id_flags; -+ struct fw_iodevid id; -+ char settings[]; -+} __packed; -+ -+/* zFCP LUN device entry. */ -+struct fw_zfcp_lun { -+ struct fw_dehdr hdr; -+ uint8_t id_flags; -+ struct fw_iodevid id; -+ uint64_t wwpn; -+ uint64_t fcp_lun; -+ char settings[]; -+} __packed; -+ -+/* QETH device entry. */ -+struct fw_qeth { -+ struct fw_dehdr hdr; -+ uint8_t id_flags; -+ struct fw_iodevid read_id; -+ struct fw_iodevid write_id; -+ struct fw_iodevid data_id; -+ char settings[]; -+} __packed; -+ -+/* Emit a warning that refers to a position in a firmware file. */ -+static void fwwarn(struct fw_file *f, const char *fmt, ...) -+{ -+ va_list args; -+ off_t start = (off_t) (f->last_access - f->buffer), -+ end = start + f->last_size - 1; -+ -+ fprintf(stderr, "%s: ", f->name); -+ if (start == end) -+ fprintf(stderr, "Byte 0x%zx: ", start); -+ else -+ fprintf(stderr, "Bytes 0x%zx-0x%zx: ", start, end); -+ -+ va_start(args, fmt); -+ vfprintf(stderr, fmt, args); -+ va_end(args); -+ fprintf(stderr, "\n"); -+} -+ -+/* Basic file format header sanity check. */ -+static bool check_header(struct fw_file *f, struct fw_filehdr *hdr) -+{ -+ if (fwacc(f, hdr->magic) != FW_HDR_MAGIC) -+ fwwarn(f, "Invalid file magic (0x%08x)", hdr->magic); -+ else if (fwacc(f, hdr->ver) != FW_HDR_VER_Z14) -+ fwwarn(f, "Unsupported file version (0x%04x)", hdr->ver); -+ else -+ return true; -+ -+ return false; -+} -+ -+#define READ_RETRY 3 -+ -+/* Read a firmware configuration file. */ -+static exit_code_t read_fw(struct fw_file *file, FILE *fd, const char *filename) -+{ -+ struct fw_file f = { NULL }; -+ struct fw_filehdr *hdr; -+ char *buffer, *buffer2; -+ size_t size, size2; -+ int retry; -+ exit_code_t rc = EXIT_OK; -+ -+ for (retry = 0; retry < READ_RETRY; retry++) { -+ /* Read complete file once */ -+ rc = misc_read_fd(fd, (void **) &buffer, &size); -+ if (rc) { -+ warn("%s: Could not read file", filename); -+ return rc; -+ } -+ if (!buffer) { -+ /* Empty file - skip silently as this is the default -+ * on machines without firmware support. */ -+ return rc; -+ } -+ -+ /* Re-read complete file to detect in-flight modifications. */ -+ if (fseek(fd, 0, SEEK_SET) == -1) { -+ /* Could be a pipe, socket, or FIFO - accept v1. */ -+ break; -+ } -+ rc = misc_read_fd(fd, (void **) &buffer2, &size2); -+ if (rc || !buffer2) { -+ /* Could not get second version - accept v1. */ -+ break; -+ } -+ -+ if (size == size2 && memcmp(buffer, buffer2, size) == 0) { -+ /* No change */ -+ free(buffer2); -+ break; -+ } -+ -+ free(buffer); -+ free(buffer2); -+ } -+ -+ if (retry >= READ_RETRY) { -+ warnx("%s: File changed %d times while reading - aborting", -+ filename, retry); -+ return EXIT_RUNTIME_ERROR; -+ } -+ -+ /* Perform basic checks */ -+ f.name = filename; -+ f.buffer = buffer; -+ f.size = size; -+ hdr = (void *) buffer; -+ if (!check_header(&f, hdr)) { -+ free(buffer); -+ return EXIT_FORMAT_ERROR; -+ } -+ if (fwacc(&f, hdr->file_len) > size) { -+ fwwarn(&f, "File length mismatch (expect %zu) - adjusting", -+ size); -+ hdr->file_len = size; -+ } -+ -+ *file = f; -+ -+ return EXIT_OK; -+} -+ -+/* Return textual representation of a device entry type. */ -+static const char *type_to_str(uint16_t type) -+{ -+ switch (type) { -+ case FW_DE_HDR_TYPE_DASD: -+ return "dasd"; -+ case FW_DE_HDR_TYPE_ZFCP_HOST: -+ return "zfcp-host"; -+ case FW_DE_HDR_TYPE_ZFCP_LUN: -+ return "zfcp-lun"; -+ case FW_DE_HDR_TYPE_QETH: -+ return "qeth"; -+ default: -+ return ""; -+ } -+} -+ -+/* Convert a binary format device setting of the specified length to integer. */ -+static unsigned long parse_value(char *data, uint8_t len) -+{ -+ switch (len) { -+ case 1: -+ return (unsigned long) *((uint8_t *) data); -+ case 2: -+ return (unsigned long) *((uint16_t *) data); -+ case 4: -+ return (unsigned long) *((uint32_t *) data); -+ case 8: -+ return (unsigned long) *((uint64_t *) data); -+ default: -+ return 0; -+ } -+} -+ -+/* Perform sanity checks on device setting. */ -+static bool check_setting(struct fw_file *f, struct fw_setting *set) -+{ -+ /* Key sanity checks */ -+ if (fwacc(f, set->key_type) != FW_SETTING_KEYTYPE_ASCII) { -+ fwwarn(f, "Unsupported key type: %d", set->key_type); -+ return false; -+ } -+ if (fwacc(f, set->key_len) < 1) { -+ fwwarn(f, "Unsupported key length: %d", set->key_len); -+ return false; -+ } -+ if (sizeof(struct fw_setting) + fwacc(f, set->key_len) > set->len) { -+ fwwarn(f, "Key length exceeds setting"); -+ return false; -+ } -+ if (fwacc(f, set->data[set->key_len - 1])) { -+ fwwarn(f, "Key not null-terminated"); -+ return false; -+ } -+ -+ /* Value sanity checks */ -+ if (fwacc(f, set->val_type) != FW_SETTING_VALTYPE_UINT && -+ fwacc(f, set->val_type) != FW_SETTING_VALTYPE_ASCII) { -+ fwwarn(f, "Unsupported value type: %d", set->val_type); -+ return false; -+ } -+ if (fwacc(f, set->val_len) < 1) { -+ fwwarn(f, "Unsupported value length: %d", set->val_len); -+ return false; -+ } -+ if (sizeof(struct fw_setting) + set->key_len + -+ fwacc(f, set->val_len) > set->len) { -+ fwwarn(f, "Value length exceeds setting"); -+ return false; -+ } -+ if ((set->val_type == FW_SETTING_VALTYPE_ASCII) && -+ fwacc(f, set->data[set->key_len + set->val_len - 1])) { -+ fwwarn(f, "Value not null-terminated"); -+ return false; -+ } -+ if (set->val_type == FW_SETTING_VALTYPE_UINT) { -+ switch (fwacc(f, set->val_len)) { -+ case 1: -+ case 2: -+ case 4: -+ case 8: -+ break; -+ default: -+ fwwarn(f, "Unsupported integer value length: %d", -+ set->val_len); -+ return false; -+ } -+ } -+ -+ return true; -+} -+ -+/* Add a setting to the device. Emit a warning if the setting is not known. */ -+static void _add_setting(const char *filename, struct device *dev, -+ config_t config, const char *key, const char *value) -+{ -+ struct attrib *a; -+ struct setting_list *list; -+ -+ list = device_get_setting_list(dev, config); -+ a = attrib_find(dev->subtype->dev_attribs, key); -+ if (!a) { -+ warnx("%s: Applying unknown device setting %s=%s", filename, -+ key, value); -+ } -+ setting_list_apply(list, a, key, value); -+} -+ -+static void add_setting(const char *filename, struct device *dev, -+ config_t config, const char *key, const char *value) -+{ -+ if (SCOPE_ACTIVE(config)) -+ _add_setting(filename, dev, config_active, key, value); -+ if (SCOPE_PERSISTENT(config)) -+ _add_setting(filename, dev, config_persistent, key, value); -+} -+ -+/* Parse a single device setting in firmware format and apply it to the -+ * specified device. */ -+static void parse_setting(struct fw_file *f, struct fw_setting *set, -+ struct device *dev, config_t config) -+{ -+ char *ascii_key, *ascii_val; -+ unsigned long ulong_val; -+ -+ if (!check_setting(f, set)) -+ return; -+ -+ ascii_key = &set->data[0]; -+ if (set->val_type == FW_SETTING_VALTYPE_UINT) { -+ ulong_val = parse_value(&set->data[set->key_len], set->val_len); -+ ascii_val = misc_asprintf("%lu", ulong_val); -+ add_setting(f->name, dev, config, ascii_key, ascii_val); -+ free(ascii_val); -+ } else { -+ ascii_val = &set->data[set->key_len]; -+ add_setting(f->name, dev, config, ascii_key, ascii_val); -+ } -+} -+ -+/* Parse a device settings list in firmware format and apply the resulting -+ * settings to the specified device. */ -+static void parse_settings(struct fw_file *f, char *data, struct device *dev, -+ config_t config) -+{ -+ struct fw_setlist *list = (struct fw_setlist *) data; -+ struct fw_setting *set; -+ uint16_t off; -+ -+ for (off = sizeof(struct fw_setlist); off < list->len; -+ off += set->len) { -+ set = (struct fw_setting *) &data[off]; -+ if (fwacc(f, set->len) < sizeof(struct fw_setting)) { -+ fwwarn(f, "Setting too short"); -+ break; -+ } -+ if (off + fwacc(f, set->len) > list->len) { -+ fwwarn(f, "Setting too long"); -+ break; -+ } -+ parse_setting(f, set, dev, config); -+ } -+} -+ -+/* Perform sanity checks on an I/O device ID. */ -+static bool check_iodevid(struct fw_file *f, uint8_t *flags, -+ struct fw_iodevid *id) -+{ -+ -+ if (fwacc(f, *flags) & FW_IODEVID_FLAG_MCSS) { -+ fwwarn(f, "Unsupported entry in non-default CSS"); -+ return false; -+ } -+ if (fwacc(f, id->cssid) != 0) { -+ fwwarn(f, "Non-zero CSS-ID"); -+ return false; -+ } -+ return true; -+} -+ -+/* Perform sanity checks on a device entry. */ -+static bool check_de_size(struct fw_file *f, struct fw_dehdr *de, size_t size) -+{ -+ if (fwacc(f, de->len) < size) { -+ fwwarn(f, "Device entry too short (expect %zu)", size); -+ return false; -+ } -+ return true; -+} -+ -+/* Convert an I/O device ID to CCW device ID format. */ -+static void io_to_ccw(struct ccw_devid *c, struct fw_iodevid *i) -+{ -+ c->cssid = i->cssid; -+ c->ssid = i->ssid; -+ c->devno = i->devno; -+} -+ -+/* Register a new device configuration. */ -+static struct device *add_device(struct fw_file *f, struct subtype *st, -+ const char *id, config_t config, -+ struct util_list *objects) -+{ -+ struct device *dev; -+ -+ if (!st->devices) -+ st->devices = device_list_new(st); -+ -+ dev = device_list_find(st->devices, id, NULL); -+ if (!dev) { -+ dev = device_new(st, id); -+ if (!dev) { -+ warnx("%s: Skipping invalid %s device ID %s", f->name, -+ st->name, id); -+ return NULL; -+ } -+ device_list_add(st->devices, dev); -+ } -+ ptrlist_add(objects, object_new(export_device, dev)); -+ -+ /* Prepare device for new settings. */ -+ if (SCOPE_ACTIVE(config)) { -+ setting_list_clear(dev->active.settings); -+ if (dev->subtype->support_definable) -+ dev->active.definable = 1; -+ else -+ dev->active.exists = 1; -+ } -+ if (SCOPE_PERSISTENT(config)) { -+ setting_list_clear(dev->persistent.settings); -+ dev->persistent.exists = 1; -+ } -+ -+ return dev; -+} -+ -+/* Parse a DASD device entry. */ -+static void parse_dasd(struct fw_file *f, struct fw_dehdr *de, config_t config, -+ struct util_list *objects) -+{ -+ struct fw_dasd *dasd = (struct fw_dasd *) de; -+ struct ccw_devid devid; -+ struct device *dev_eckd, *dev_fba; -+ char *id; -+ -+ if (!check_de_size(f, de, sizeof(struct fw_dasd))) -+ return; -+ if (!check_iodevid(f, &dasd->id_flags, &dasd->id)) -+ return; -+ -+ /* Could be either dasd_eckd or dasd_fba - add both entries */ -+ io_to_ccw(&devid, &dasd->id); -+ id = ccw_devid_to_str(&devid); -+ dev_eckd = add_device(f, &dasd_subtype_eckd, id, config, objects); -+ dev_fba = add_device(f, &dasd_subtype_fba, id, config, objects); -+ free(id); -+ -+ if (dasd->hdr.len > sizeof(struct fw_dasd)) { -+ if (dev_eckd) -+ parse_settings(f, dasd->settings, dev_eckd, config); -+ if (dev_fba) -+ parse_settings(f, dasd->settings, dev_fba, config); -+ } -+} -+ -+/* Parse a zFCP host device entry. */ -+static void parse_zfcp_host(struct fw_file *f, struct fw_dehdr *de, -+ config_t config, struct util_list *objects) -+{ -+ struct fw_zfcp_host *zfcp_host = (struct fw_zfcp_host *) de; -+ struct ccw_devid devid; -+ struct device *dev; -+ char *id; -+ -+ if (!check_de_size(f, de, sizeof(struct fw_zfcp_host))) -+ return; -+ if (!check_iodevid(f, &zfcp_host->id_flags, &zfcp_host->id)) -+ return; -+ -+ /* Add zfcp_host entry */ -+ io_to_ccw(&devid, &zfcp_host->id); -+ id = ccw_devid_to_str(&devid); -+ dev = add_device(f, &zfcp_host_subtype, id, config, objects); -+ free(id); -+ -+ if (dev && zfcp_host->hdr.len > sizeof(struct fw_zfcp_host)) -+ parse_settings(f, zfcp_host->settings, dev, config); -+} -+ -+/* Parse a zFCP LUN device entry. */ -+static void parse_zfcp_lun(struct fw_file *f, struct fw_dehdr *de, -+ config_t config, struct util_list *objects) -+{ -+ struct fw_zfcp_lun *zfcp_lun = (struct fw_zfcp_lun *) de; -+ struct zfcp_lun_devid devid; -+ struct device *dev; -+ char *id; -+ -+ if (!check_de_size(f, de, sizeof(struct fw_zfcp_lun))) -+ return; -+ if (!check_iodevid(f, &zfcp_lun->id_flags, &zfcp_lun->id)) -+ return; -+ -+ /* Add zfcp_lun entry */ -+ io_to_ccw(&devid.fcp_dev, &zfcp_lun->id); -+ devid.wwpn = zfcp_lun->wwpn; -+ devid.lun = zfcp_lun->fcp_lun; -+ id = zfcp_lun_devid_to_str(&devid); -+ dev = add_device(f, &zfcp_lun_subtype, id, config, objects); -+ free(id); -+ -+ if (dev && zfcp_lun->hdr.len > sizeof(struct fw_zfcp_lun)) -+ parse_settings(f, zfcp_lun->settings, dev, config); -+ -+} -+ -+/* Parse a QETH device entry. */ -+static void parse_qeth(struct fw_file *f, struct fw_dehdr *de, config_t config, -+ struct util_list *objects) -+{ -+ struct fw_qeth *qeth = (struct fw_qeth *) de; -+ struct ccwgroup_devid devid; -+ struct device *dev; -+ char *id; -+ -+ if (!check_de_size(f, de, sizeof(struct fw_qeth))) -+ return; -+ if (!check_iodevid(f, &qeth->id_flags, &qeth->read_id) || -+ !check_iodevid(f, &qeth->id_flags, &qeth->write_id) || -+ !check_iodevid(f, &qeth->id_flags, &qeth->data_id)) -+ return; -+ -+ /* Add qeth entry */ -+ devid.num = 3; -+ io_to_ccw(&devid.devid[0], &qeth->read_id); -+ io_to_ccw(&devid.devid[1], &qeth->write_id); -+ io_to_ccw(&devid.devid[2], &qeth->data_id); -+ id = ccwgroup_devid_to_str(&devid); -+ dev = add_device(f, &qeth_subtype_qeth, id, config, objects); -+ free(id); -+ -+ if (dev && qeth->hdr.len > sizeof(struct fw_qeth)) -+ parse_settings(f, qeth->settings, dev, config); -+} -+ -+/* Parse a firmware file. */ -+static void parse_fw(struct fw_file *f, long skip, config_t config, -+ struct util_list *objects) -+{ -+ char *data = f->buffer; -+ struct fw_filehdr *hdr = (struct fw_filehdr *) data; -+ struct fw_dehdr *de; -+ uint16_t count = 0; -+ uint32_t off; -+ -+ for (off = hdr->hdr_len; off < hdr->file_len; off += de->len) { -+ count++; -+ de = (struct fw_dehdr *) &data[off]; -+ if (fwacc(f, de->len) == 0) { -+ fwwarn(f, "Empty device entry"); -+ break; -+ } -+ if (off + fwacc(f, de->len) > hdr->file_len) { -+ fwwarn(f, "Device entry too long"); -+ break; -+ } -+ if (skip >= 0 && de->seq <= skip) { -+ debug("Skipping %s entry due to sequence (%08x)\n", -+ type_to_str(de->type), de->seq); -+ continue; -+ } -+ switch (fwacc(f, de->type)) { -+ case FW_DE_HDR_TYPE_DASD: -+ parse_dasd(f, de, config, objects); -+ break; -+ case FW_DE_HDR_TYPE_ZFCP_HOST: -+ parse_zfcp_host(f, de, config, objects); -+ break; -+ case FW_DE_HDR_TYPE_ZFCP_LUN: -+ parse_zfcp_lun(f, de, config, objects); -+ break; -+ case FW_DE_HDR_TYPE_QETH: -+ parse_qeth(f, de, config, objects); -+ break; -+ default: -+ fwwarn(f, "Unknown entry (type=%04x)", de->type); -+ break; -+ } -+ } -+ -+ if (count != fwacc(f, hdr->de_count)) -+ fwwarn(f, "Device entry count mismatch"); -+} -+ -+/* Read configuration objects from @fd in firmware file format. Add pointers to -+ * newly allocated struct export_objects to ptrlist @objects. If @skip is a -+ * positive number, skip over entries with a sequence number equal to or -+ * greater than @skip. */ -+exit_code_t firmware_read(FILE *fd, const char *filename, long skip, -+ config_t config, struct util_list *objects) -+{ -+ struct fw_file file; -+ exit_code_t rc; -+ -+ rc = read_fw(&file, fd, filename); -+ if (rc) -+ return rc; -+ -+ parse_fw(&file, skip, config, objects); -+ free(file.buffer); -+ -+ return rc; -+} -+ -+/* Check if @fd refers to a file in binary firmware format. */ -+bool firmware_detect(FILE *fd) -+{ -+ int c; -+ -+ c = fgetc(fd); -+ ungetc(c, fd); -+ -+ /* Note: A full check would require looking at least at the first 4 -+ * bytes, but fd might be non-seekable (e.g. pipe). Since there is no -+ * way that a textual import file can start with a 'z', looking at -+ * the first char should be enough. */ -+ -+ return c == 'z'; -+} diff --git a/s390-tools-sles15sp1-04-cpumf-correct-z14-counter-number.patch b/s390-tools-sles15sp1-04-cpumf-correct-z14-counter-number.patch deleted file mode 100644 index 45e1127..0000000 --- a/s390-tools-sles15sp1-04-cpumf-correct-z14-counter-number.patch +++ /dev/null @@ -1,32 +0,0 @@ -Subject: cpumf: correct z14 counter number -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: 144bddbf5bce749549a289acbeb49337edaaea45 -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf: correct z14 counter number - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Stefan Haberland - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/data/cpum-cf-extended-z14.ctr | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/cpumf/data/cpum-cf-extended-z14.ctr -+++ b/cpumf/data/cpum-cf-extended-z14.ctr -@@ -269,7 +269,7 @@ Description: - Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED, - EDMK, MP, SRP, SP, ZAP - . --Counter:233 Name:LAST_HOST_TRANSLATIONS -+Counter:232 Name:LAST_HOST_TRANSLATIONS - Description: - Last Host Translation done - . diff --git a/s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch b/s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch deleted file mode 100644 index 9d1d794..0000000 --- a/s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch +++ /dev/null @@ -1,157 +0,0 @@ -Subject: zdev: Implement --no-settle -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: f32bff96881a04bb68b895c23b13ae50daa9e7b4 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Implement --no-settle - - There are some situations where running "udevadm settle" can result in - a deadlock, such as in the early stages of initial RAM-disk processing. - - Introduce a new command-line option --no-settle that can be used to - suppress calling "udevadm settle" to allow chzdev to be run in such - situations. - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/udev.h | 1 + - zdev/man/chzdev.8 | 9 +++++++++ - zdev/src/chzdev.c | 9 +++++++++ - zdev/src/chzdev_usage.txt | 1 + - zdev/src/udev.c | 3 +++ - 5 files changed, 23 insertions(+) - ---- a/zdev/include/udev.h -+++ b/zdev/include/udev.h -@@ -14,6 +14,7 @@ - #include "exit_code.h" - - extern int udev_need_settle; -+extern int udev_no_settle; - - /* Single key-operator-value entry in a udev rule line.*/ - struct udev_entry_node { ---- a/zdev/man/chzdev.8 -+++ b/zdev/man/chzdev.8 -@@ -528,6 +528,15 @@ device configuration persistent. Typical - initial RAM disk, or modifying the kernel command line. - .PP - . -+.OD no-settle "" "" -+Do not wait for udev processing to complete. -+ -+Skips all calls to the udevadm tool that are intended to wait for udev to -+finish processing before continuing. There is typically no need to use this -+option unless chzdev is run in an environment where udev is not fully -+functional (such as in the early phase of an initial RAM disk). -+.PP -+. - .OD persistent "p" "" - Apply changes to persistent configuration only. - ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -95,6 +95,7 @@ struct options { - struct util_list *base; /* List of struct strlist_node */ - unsigned int verbose:1; - unsigned int quiet:1; -+ unsigned int no_settle:1; - }; - - /* Makefile converts chzdev_usage.txt into C file which we include here. */ -@@ -136,6 +137,7 @@ enum { - OPT_VERSION = 'v', - OPT_VERBOSE = 'V', - OPT_QUIET = 'q', -+ OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__), - }; - - static struct opts_conflict conflict_list[] = { -@@ -217,6 +219,7 @@ static const struct option opt_list[] = - { "base", required_argument, NULL, OPT_BASE }, - { "verbose", no_argument, NULL, OPT_VERBOSE }, - { "quiet", no_argument, NULL, OPT_QUIET }, -+ { "no-settle", no_argument, NULL, OPT_NO_SETTLE }, - { NULL, no_argument, NULL, 0 }, - }; - -@@ -937,6 +940,11 @@ static exit_code_t parse_options(struct - opts->quiet = 1; - break; - -+ case OPT_NO_SETTLE: -+ /* --no-settle */ -+ opts->no_settle = 1; -+ break; -+ - case ':': - /* Missing option argument. */ - syntax("Option '%s' requires an argument\n", -@@ -2904,6 +2912,7 @@ int main(int argc, char *argv[]) - force = opts.force; - yes = opts.yes; - dryrun = opts.dryrun; -+ udev_no_settle = opts.no_settle; - path_set_base(opts.base); - - if (dryrun) ---- a/zdev/src/chzdev_usage.txt -+++ b/zdev/src/chzdev_usage.txt -@@ -54,5 +54,6 @@ OPTIONS - --no-root-update Skip root device update - --dry-run Display changes without applying - --base PATH Use PATH as base for accessing files -+ --no-settle Do not wait for udev to settle - -V, --verbose Print additional run-time information - -q, --quiet Print only minimal run-time information ---- a/zdev/src/udev.c -+++ b/zdev/src/udev.c -@@ -24,6 +24,7 @@ - #include "udev.h" - - int udev_need_settle = 0; -+int udev_no_settle; - - /* Create a newly allocated udev entry. */ - static struct udev_entry_node *udev_entry_node_new(const char *key, -@@ -403,5 +404,7 @@ exit_code_t udev_remove_rule(const char - /* Wait for all current udev events to finish. */ - void udev_settle(void) - { -+ if (udev_no_settle) -+ return; - misc_system(err_ignore, "%s settle", PATH_UDEVADM); - } diff --git a/s390-tools-sles15sp1-04-zpcictl-Introduce-new-tool-zpcictl.patch b/s390-tools-sles15sp1-04-zpcictl-Introduce-new-tool-zpcictl.patch deleted file mode 100644 index 880ce29..0000000 --- a/s390-tools-sles15sp1-04-zpcictl-Introduce-new-tool-zpcictl.patch +++ /dev/null @@ -1,603 +0,0 @@ -Subject: zpcictl: Introduce new tool zpcictl -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: 177cf8cfeb83f85bc164c462b5534f93be3bd979 -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Introduce new tool zpcictl - - zpcictl is used to manage PCI devices on z Systems. In this first - version it is mainly used to handle erroneous PCI devices by changing - their state and make those changes known to the SE. Log data, such as - S.M.A.R.T. data for NVMe devices, is sent alongside those state changes. - - The state change is issued by sending data via the PCI 'report_error' - sysfs attribute. It's a binary attribute which will cause the host to - send an Adapter Notification Event. - - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - .gitignore | 1 - Makefile | 2 - zpcictl/Makefile | 18 ++ - zpcictl/zpcictl.8 | 80 +++++++++++ - zpcictl/zpcictl.c | 378 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - zpcictl/zpcictl.h | 60 ++++++++ - 6 files changed, 538 insertions(+), 1 deletion(-) - ---- a/.gitignore -+++ b/.gitignore -@@ -87,3 +87,4 @@ zipl/boot/data.h - zipl/src/chreipl_helper.device-mapper - zipl/src/zipl - zkey/zkey -+zpcictl/zpcictl ---- a/Makefile -+++ b/Makefile -@@ -8,7 +8,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt das - tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \ - vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \ - ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \ -- systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot -+ systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot zpcictl - SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS) - - all: $(TOOL_DIRS) ---- /dev/null -+++ b/zpcictl/Makefile -@@ -0,0 +1,18 @@ -+include ../common.mak -+ -+all: zpcictl -+ -+libs = $(rootdir)/libutil/libutil.a -+ -+zpcictl: zpcictl.o $(libs) -+ -+install: all -+ $(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8 -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zpcictl $(DESTDIR)$(BINDIR) -+ $(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 zpcictl.8 \ -+ $(DESTDIR)$(MANDIR)/man8 -+ -+clean: -+ rm -f *.o *~ zpcictl core -+ -+.PHONY: all install clean ---- /dev/null -+++ b/zpcictl/zpcictl.8 -@@ -0,0 +1,80 @@ -+.\" Copyright 2017 IBM Corp. -+.\" s390-tools is free software; you can redistribute it and/or modify -+.\" it under the terms of the MIT license. See LICENSE for details. -+.\" -+.\" Macro for inserting an option description prologue. -+.\" .OD [] [args] -+.de OD -+. ds args " -+. if !'\\$3'' .as args \fI\\$3\fP -+. if !'\\$4'' .as args \\$4 -+. if !'\\$5'' .as args \fI\\$5\fP -+. if !'\\$6'' .as args \\$6 -+. if !'\\$7'' .as args \fI\\$7\fP -+. PD 0 -+. if !'\\$2'' .IP "\fB\-\\$2\fP \\*[args]" 4 -+. if !'\\$1'' .IP "\fB\-\-\\$1\fP \\*[args]" 4 -+. PD -+.. -+. -+.TH zpcictl 8 "Oct 2018" s390-tools zpcictl -+. -+.SH NAME -+zpcictl - Manage PCI devices on z Systems -+. -+. -+.SH SYNOPSIS -+.B "zpcictl" -+.I "OPTIONS" -+.I "DEVICE" -+. -+. -+.SH DESCRIPTION -+.B zpcictl -+is a tool for managing PCI devices on the IBM z Systems platform. It is -+especially used for reporting errorneous PCI devices to the service element. -+ -+.B Note: -+For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent -+with any error handling action. The smartmontools are required to be installed -+for this to work. -+.PP -+. -+. -+.SH DEVICE -+.B DEVICE -+can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node -+of an NVMe device (e.g. /dev/nvme0). -+. -+. -+.SH OPTIONS -+.SS Error Handling -+.OD reset "" "DEVICE" -+Reset -+.I DEVICE -+and initiate a re-initialisation of the adapter. -+.PP -+. -+.OD deconfigure "" "DEVICE" -+De-configure -+.I DEVICE -+and prepare for any repair action. This action will move the -+PCI device from a configured to a reserved state. -+.PP -+. -+.OD report-error "" "DEVICE" -+Report any device error for -+.IR DEVICE . -+The -+.I DEVICE -+is marked as erroneous and no further action is initiated on it. -+.PP -+. -+.SS Misc -+.OD help "h" "" -+Print usage information, then exit. -+.PP -+. -+.OD version "v" "" -+Print version information, then exit. -+.PP ---- /dev/null -+++ b/zpcictl/zpcictl.c -@@ -0,0 +1,378 @@ -+/* -+ * zpcictl - Manage PCI devices on z Systems -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 -+#include -+#include -+#include -+ -+#include "lib/util_base.h" -+#include "lib/util_libc.h" -+#include "lib/util_opt.h" -+#include "lib/util_path.h" -+#include "lib/util_prg.h" -+#include "lib/util_proc.h" -+#include "lib/util_rec.h" -+#include "lib/util_scandir.h" -+ -+#include "zpcictl.h" -+ -+#define SMARTCTL_CMDLINE "smartctl -x %s 2>/dev/null" -+ -+static const struct util_prg prg = { -+ .desc = "Use zpcictl to manage PCI devices on s390\n" -+ "DEVICE is the slot id or node of the device (e.g. /dev/nvme0)", -+ .args = "DEVICE", -+ .copyright_vec = { -+ { -+ .owner = "IBM Corp.", -+ .pub_first = 2018, -+ .pub_last = 2018, -+ }, -+ UTIL_PRG_COPYRIGHT_END -+ } -+}; -+ -+/* Defines for options with no short command */ -+#define OPT_RESET 128 -+#define OPT_DECONF 129 -+#define OPT_REPORT_ERR 130 -+ -+static struct util_opt opt_vec[] = { -+ UTIL_OPT_SECTION("ERROR HANDLING"), -+ { -+ .option = { "reset", no_argument, NULL, OPT_RESET }, -+ .desc = "Reset device", -+ .flags = UTIL_OPT_FLAG_NOSHORT, -+ }, -+ { -+ .option = { "deconfigure", no_argument, NULL, OPT_DECONF }, -+ .desc = "De-configure device and prepare for any repair action", -+ .flags = UTIL_OPT_FLAG_NOSHORT, -+ }, -+ { -+ .option = { "report-error", no_argument, NULL, OPT_REPORT_ERR }, -+ .desc = "Report device error to service element (SE)", -+ .flags = UTIL_OPT_FLAG_NOSHORT, -+ }, -+ UTIL_OPT_SECTION("MISC"), -+ UTIL_OPT_HELP, -+ UTIL_OPT_VERSION, -+ UTIL_OPT_END -+}; -+ -+static int is_char_dev(const char *dev) -+{ -+ struct stat s; -+ -+ if (stat(dev, &s)) -+ return 0; -+ -+ return S_ISCHR(s.st_mode); -+} -+ -+static int is_blk_dev(const char *dev) -+{ -+ struct stat s; -+ -+ if (stat(dev, &s)) -+ return 0; -+ -+ return S_ISBLK(s.st_mode); -+} -+ -+static void fopen_err(char *path) -+{ -+ warnx("Could not open file %s: %s", path, strerror(errno)); -+ free(path); -+ exit(EXIT_FAILURE); -+} -+ -+#define READ_CHUNK_SIZE 512 -+ -+static char *collect_smart_data(struct zpci_device *pdev) -+{ -+ char *buffer = NULL; -+ size_t count = 0; -+ char *cmd; -+ FILE *fd; -+ -+ util_asprintf(&cmd, SMARTCTL_CMDLINE, pdev->device); -+ fd = popen(cmd, "r"); -+ if (!fd) -+ goto out; -+ -+ while (!feof(fd)) { -+ buffer = realloc(buffer, count + READ_CHUNK_SIZE); -+ if (!buffer) { -+ warnx("Could not collect S.M.A.R.T. data"); -+ goto out; -+ } -+ count += fread(&buffer[count], 1, READ_CHUNK_SIZE, fd); -+ if (ferror(fd)) { -+ free(buffer); -+ buffer = NULL; -+ goto out; -+ } -+ } -+ -+ buffer = realloc(buffer, count); -+ if (!buffer && count > 0) -+ warnx("Could not collect S.M.A.R.T. data"); -+ if (buffer) -+ buffer[count] = '\0'; -+ -+out: -+ pclose(fd); -+ free(cmd); -+ -+ return buffer; -+} -+ -+static unsigned int sysfs_read_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, "r"); -+ if (!fp) -+ fopen_err(path); -+ fscanf(fp, "%x", &val); -+ fclose(fp); -+ free(path); -+ -+ return val; -+} -+ -+static void sysfs_write_data(struct zpci_report_error *report, char *slot) -+{ -+ char *path; -+ int fd, rc; -+ -+ path = util_path_sysfs("bus/pci/devices/%s/report_error", slot); -+ fd = open(path, O_WRONLY); -+ if (!fd) -+ fopen_err(path); -+ rc = write(fd, report, sizeof(*report)); -+ if (rc == -1) -+ warnx("Could not write to file: %s: %s", path, strerror(errno)); -+ if (close(fd)) -+ warnx("Could not close file: %s: %s", path, strerror(errno)); -+ free(path); -+} -+ -+static void sysfs_get_slot_addr(const char *dev, char *slot) -+{ -+ unsigned int major, minor; -+ struct stat dev_stat; -+ char addr[13]; -+ char *path; -+ FILE *fp; -+ -+ if (stat(dev, &dev_stat) != 0) { -+ errx(EXIT_FAILURE, "Could not get stat information for %s: %s", -+ dev, strerror(errno)); -+ } -+ major = major(dev_stat.st_rdev); -+ minor = minor(dev_stat.st_rdev); -+ -+ path = util_path_sysfs("dev/char/%u:%u/address", major, minor); -+ fp = fopen(path, "r"); -+ if (!fp) -+ fopen_err(path); -+ fscanf(fp, "%s", addr); -+ fclose(fp); -+ free(path); -+ -+ strcpy(slot, addr); -+} -+ -+static void get_device_node(struct zpci_device *pdev) -+{ -+ struct dirent **de_vec; -+ char *path, *dev; -+ char slot[13]; -+ int count, i; -+ -+ path = util_path_sysfs("bus/pci/devices/%s/nvme", pdev->slot); -+ count = util_scandir(&de_vec, alphasort, path, "nvme*"); -+ if (count == -1) { -+ warnx("Could not read directory %s: %s", path, strerror(errno)); -+ free(path); -+ exit(EXIT_FAILURE); -+ } -+ -+ for (i = 0; i < count; i++) { -+ util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); -+ sysfs_get_slot_addr(dev, slot); -+ if (strcmp(slot, pdev->slot) == 0) { -+ pdev->device = dev; -+ break; -+ } -+ } -+ -+ util_scandir_free(de_vec, count); -+ free(path); -+} -+ -+static int device_exists(char *dev) -+{ -+ char *path; -+ int rc = 0; -+ -+ path = util_path_sysfs("bus/pci/devices/%s", dev); -+ if (util_path_exists(path) || util_path_exists(dev)) -+ rc = 1; -+ free(path); -+ -+ return rc; -+} -+ -+static void get_device_info(struct zpci_device *pdev, char *dev) -+{ -+ if (!device_exists(dev)) -+ errx(EXIT_FAILURE, "Device %s not found", dev); -+ if (is_blk_dev(dev)) -+ errx(EXIT_FAILURE, "Unsupported device type %s", dev); -+ if (is_char_dev(dev)) { -+ sysfs_get_slot_addr(dev, pdev->slot); -+ pdev->device = dev; -+ } else { -+ strcpy(pdev->slot, dev); -+ } -+ -+ pdev->class = sysfs_read_value(pdev, "class"); -+ pdev->fid = sysfs_read_value(pdev, "function_id"); -+ pdev->pchid = sysfs_read_value(pdev, "pchid"); -+ -+ /* In case a slot address was specified, we still need to figure out -+ * the device node for NVMe devices. Otherwise we won't be able to -+ * collect S.M.A.R.T. data at a later point. -+ */ -+ if (!pdev->device && pdev->class == PCI_CLASS_NVME) -+ get_device_node(pdev); -+} -+ -+/* -+ * Issue an SCLP Adapter Error Notification event with a specific action -+ * qualifier. -+ * -+ * Collect additional information when possible (e.g. S.M.A.R.T. data for NVMe -+ * devices). -+ */ -+static void sclp_issue_action(struct zpci_device *pdev, int action) -+{ -+ struct zpci_report_error report = { -+ .header = { 0 }, -+ .data = { 0 } -+ }; -+ char *sdata = NULL; -+ -+ report.header.version = 1; -+ report.header.action = action; -+ report.header.length = sizeof(report.data); -+ report.data.timestamp = (__u64)time(NULL); -+ report.data.err_log_id = 0x4713; -+ -+ if (pdev->class == PCI_CLASS_NVME) -+ sdata = collect_smart_data(pdev); -+ if (sdata) { -+ strncpy(report.data.log_data, sdata, sizeof(report.data.log_data)); -+ free(sdata); -+ } -+ sysfs_write_data(&report, pdev->slot); -+} -+ -+/* -+ * Reset the PCI device and initiate a re-initialization. -+ */ -+static void sclp_reset_device(struct zpci_device *pdev) -+{ -+ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET); -+} -+ -+/* -+ * De-Configure/repair PCI device. Moves the device from configured -+ * to reserved state. -+ */ -+static void sclp_deconfigure(struct zpci_device *pdev) -+{ -+ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_DECONF); -+} -+ -+/* -+ * Report an error to the SE. -+ */ -+static void sclp_report_error(struct zpci_device *pdev) -+{ -+ sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_REPORT_ERR); -+} -+ -+static void parse_cmdline(int argc, char *argv[], struct options *opts) -+{ -+ int cmd; -+ -+ util_prg_init(&prg); -+ util_opt_init(opt_vec, NULL); -+ -+ do { -+ cmd = util_opt_getopt_long(argc, argv); -+ -+ switch (cmd) { -+ case OPT_RESET: -+ opts->reset = 1; -+ break; -+ case OPT_DECONF: -+ opts->deconfigure = 1; -+ break; -+ case OPT_REPORT_ERR: -+ opts->report = 1; -+ break; -+ case 'h': -+ util_prg_print_help(); -+ util_opt_print_help(); -+ exit(EXIT_SUCCESS); -+ case 'v': -+ util_prg_print_version(); -+ exit(EXIT_SUCCESS); -+ case -1: -+ /* End of options string */ -+ if (argc == 1) { -+ errx(EXIT_FAILURE, -+ "Use '%s --help' for more information", -+ argv[0]); -+ } -+ break; -+ } -+ } while (cmd != -1); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ struct zpci_device pdev = { 0 }; -+ struct options opts = { 0 }; -+ -+ parse_cmdline(argc, argv, &opts); -+ -+ if (optind >= argc) -+ errx(EXIT_FAILURE, "No device specified"); -+ -+ get_device_info(&pdev, argv[optind]); -+ -+ if (opts.reset) -+ sclp_reset_device(&pdev); -+ else if (opts.deconfigure) -+ sclp_deconfigure(&pdev); -+ else if (opts.report) -+ sclp_report_error(&pdev); -+ -+ return 0; -+} ---- /dev/null -+++ b/zpcictl/zpcictl.h -@@ -0,0 +1,60 @@ -+/* -+ * zpcictl - Manage PCI devices on z Systems -+ * -+ * Copyright IBM Corp. 2018 -+ * -+ * 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 ZPCICTL_H -+#define ZPCICTL_H -+ -+#include -+#include "lib/zt_common.h" -+ -+#define SCLP_ERRNOTIFY_AQ_RESET 0 -+#define SCLP_ERRNOTIFY_AQ_DECONF 1 -+#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2 -+ -+#define PCI_CLASS_UNCLASSIFIED 0x000000U -+#define PCI_CLASS_NVME 0x010802U -+#define PCI_CLASS_NETWORK 0x020000U -+ -+struct options { -+ unsigned int reset; -+ unsigned int deconfigure; -+ unsigned int report; -+}; -+ -+struct zpci_device { -+ u16 fid; -+ u16 pchid; -+ u32 class; -+ char slot[13]; -+ char *device; -+}; -+ -+struct zpci_report_error_header { -+ __u8 version; /* Interface version byte */ -+ __u8 action; /* Action qualifier byte -+ * 0: Adapter Reset Request -+ * 1: Deconfigure and repair action requested -+ * 2: Informational Report -+ */ -+ __u16 length; /* Length of Subsequent Data (up to 4K – SCLP header) */ -+ __u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ -+}; -+ -+struct zpci_report_error_data { -+ __u64 timestamp; -+ __u64 err_log_id; -+ char log_data[4054]; /* We cannot exceed a total of 4074 bytes (header + data) */ -+}; -+ -+struct zpci_report_error { -+ struct zpci_report_error_header header; -+ struct zpci_report_error_data data; -+} __packed; -+ -+#endif /* ZPCICTL_H */ diff --git a/s390-tools-sles15sp1-05-cpumf-add-missing-Description-tag-for-z13-z14-ctr-12.patch b/s390-tools-sles15sp1-05-cpumf-add-missing-Description-tag-for-z13-z14-ctr-12.patch deleted file mode 100644 index 01f3e19..0000000 --- a/s390-tools-sles15sp1-05-cpumf-add-missing-Description-tag-for-z13-z14-ctr-12.patch +++ /dev/null @@ -1,42 +0,0 @@ -Subject: cpumf: add missing Description: tag for z13/z14/ctr:128 -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: a3c746846d86ebcee6cbf36505598b7da367665b -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf: add missing Description: tag for z13/z14/ctr:128 - - Signed-off-by: Thomas Richter - Signed-off-by: Jan Höppner - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/data/cpum-cf-extended-z13.ctr | 1 + - cpumf/data/cpum-cf-extended-z14.ctr | 1 + - 2 files changed, 2 insertions(+) - ---- a/cpumf/data/cpum-cf-extended-z13.ctr -+++ b/cpumf/data/cpum-cf-extended-z13.ctr -@@ -17,6 +17,7 @@ - # Extended Counter Set - # --------------------------------------------------------------------- - Counter:128 Name:L1D_WRITES_RO_EXCL -+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. ---- a/cpumf/data/cpum-cf-extended-z14.ctr -+++ b/cpumf/data/cpum-cf-extended-z14.ctr -@@ -20,6 +20,7 @@ - # Extended Counter Set - # --------------------------------------------------------------------- - Counter:128 Name:L1D_WRITES_RO_EXCL -+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 diff --git a/s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch b/s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch deleted file mode 100644 index 9c386ce..0000000 --- a/s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch +++ /dev/null @@ -1,217 +0,0 @@ -Subject: zdev: Write zfcp-lun udev rules to separate files -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: a86fb8b09118e6de7463882f889eff7e278163cd -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Write zfcp-lun udev rules to separate files - - Change chzdev's udev rule generation from the previous approach of - combining all zfcp-lun udev rules associated with an FCP device into a - single file to storing zfcp-lun udev rules in one file per zfcp-lun. - This is done to enable per-device udev rule masking. - - With udev rule masking, if a udev rule file by the same name exists in - both /etc and /run, the udev daemon will only consider the rules found - in /etc. - - The auto-configuration feature will make use of per-device udev rule - masking to introduce a new class of configuration data (stored in /run) - that is only active if no user-provided configuration data (in /etc) - exists. - - In addition, change chzdev to allow the regeneration of udev rules by - using the --force command line like in the following example: - - # chzdev zfcp-lun --configured --enable --persistent --force - - This can be used to convert all existing zfcp-lun udev rules from the - old format to the new one. - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/src/chzdev.c | 6 +++- - zdev/src/root.c | 2 - - zdev/src/udev_zfcp_lun.c | 56 ++++++++++++++++++++++++++++++++++----- - 3 files changed, 55 insertions(+), 9 deletions(-) - ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -1333,7 +1333,7 @@ static exit_code_t cfg_write(struct devi - struct subtype *st = dev->subtype; - exit_code_t rc = EXIT_OK; - -- if (!device_needs_writing(dev, config)) -+ if (!device_needs_writing(dev, config) && !force) - goto out; - - if (check_active && config == config_persistent && -@@ -1624,6 +1624,10 @@ static exit_code_t print_config_result(s - already = device_needs_writing(dev, config) ? 0 : 1; - } - -+ /* Re-do actions if run with --force */ -+ if (force) -+ already = 0; -+ - if (dev) { - devname = dev->subtype->devname; - devid = dev->id; ---- a/zdev/src/root.c -+++ b/zdev/src/root.c -@@ -60,7 +60,7 @@ exit_code_t root_check(void) - /* Check devices. */ - dev = device_list_find(sel->st->devices, sel->id, NULL); - if (dev && dev->persistent.exists && -- device_needs_writing(dev, config_persistent)) { -+ (device_needs_writing(dev, config_persistent) || force)) { - strlist_add(mod, "%s %s", dev->subtype->devname, - dev->id); - } ---- a/zdev/src/udev_zfcp_lun.c -+++ b/zdev/src/udev_zfcp_lun.c -@@ -385,6 +385,8 @@ void udev_zfcp_lun_add_device_ids(struct - free(cb_data.prefix); - } - -+/* Return path to zfcp lun udev rule file containing configuration data for -+ * all LUNs of a zfcp device. */ - static char *get_zfcp_lun_path(const char *id) - { - char *copy, *e, *path; -@@ -399,6 +401,13 @@ static char *get_zfcp_lun_path(const cha - return path; - } - -+/* Return path to zfcp lun udev rule file containing configuration data for -+ * a single LUN. */ -+static char *get_single_zfcp_lun_path(const char *id) -+{ -+ return path_get_udev_rule(ZFCP_LUN_NAME, id); -+} -+ - /* Apply the settings found in NODE to STATE. */ - static void zfcp_lun_node_to_state(struct zfcp_lun_node *node, - struct attrib **attribs, -@@ -437,7 +446,12 @@ exit_code_t udev_zfcp_lun_read_device(st - exit_code_t rc = EXIT_OK; - char *path; - -- path = get_zfcp_lun_path(dev->id); -+ /* Check for single lun file first then try multi lun file. */ -+ path = get_single_zfcp_lun_path(dev->id); -+ if (!util_path_exists(path)) { -+ free(path); -+ path = get_zfcp_lun_path(dev->id); -+ } - - /* Get previous rule data. */ - luns = zfcp_lun_node_list_new(); -@@ -599,8 +613,10 @@ out: - - /* Update the udev rule file that configures the zfcp lun with the specified - * ID. If @state is %NULL, remove the rule, otherwise create a rule that -- * applies the corresponding parameters. */ --static exit_code_t update_lun_rule(const char *id, struct device_state *state) -+ * applies the corresponding parameters. If @single is set, update a single -+ * lun rule file, otherwise update a multi lun rule file. */ -+static exit_code_t update_lun_rule(const char *id, struct device_state *state, -+ bool single) - { - struct zfcp_lun_devid devid; - struct util_list *luns; -@@ -612,7 +628,7 @@ static exit_code_t update_lun_rule(const - rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print); - if (rc) - return rc; -- path = get_zfcp_lun_path(id); -+ path = single ? get_single_zfcp_lun_path(id) : get_zfcp_lun_path(id); - - /* Get previous rule data. */ - luns = zfcp_lun_node_list_new(); -@@ -650,24 +666,50 @@ static exit_code_t update_lun_rule(const - * device state. */ - exit_code_t udev_zfcp_lun_write_device(struct device *dev) - { -- return update_lun_rule(dev->id, &dev->persistent); -+ exit_code_t rc; -+ -+ rc = update_lun_rule(dev->id, &dev->persistent, true); -+ -+ /* We only want single lun rule files so remove any remaining -+ * references in multi lun rule files. */ -+ update_lun_rule(dev->id, NULL, false); -+ -+ return rc; - } - - /* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */ - exit_code_t udev_zfcp_lun_remove_rule(const char *id) - { -- return update_lun_rule(id, NULL); -+ exit_code_t rc, rc2; -+ -+ rc = update_lun_rule(id, NULL, true); -+ rc2 = update_lun_rule(id, NULL, false); -+ -+ if (rc) -+ return rc; -+ -+ return rc2; - } - - /* Determine if a udev rule exists for configuring the specified zfcp lun. */ - bool udev_zfcp_lun_exists(const char *id) - { - struct zfcp_lun_devid devid; -- char *path, *rule, *pattern = NULL; -+ char *path, *rule = NULL, *pattern = NULL; - bool rc = false; - - if (zfcp_lun_parse_devid(&devid, id, err_ignore) != EXIT_OK) - return false; -+ -+ /* Check for single lun rule file first. */ -+ path = get_single_zfcp_lun_path(id); -+ if (util_path_exists(path)) { -+ rc = true; -+ goto out; -+ } -+ free(path); -+ -+ /* Check multi lun rule file next. */ - path = get_zfcp_lun_path(id); - rule = misc_read_text_file(path, 1, err_ignore); - if (!rule) diff --git a/s390-tools-sles15sp1-05-zpcictl-include-sys-sysmacros.h-to-avoid-minor-major.patch b/s390-tools-sles15sp1-05-zpcictl-include-sys-sysmacros.h-to-avoid-minor-major.patch deleted file mode 100644 index 45e4dd3..0000000 --- a/s390-tools-sles15sp1-05-zpcictl-include-sys-sysmacros.h-to-avoid-minor-major.patch +++ /dev/null @@ -1,48 +0,0 @@ -Subject: zpcictl: include sys/sysmacros.h to avoid minor/major glibc warnings -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: f35c5d01fd04ecf019f31c58edc0c5165ad276ad -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: include sys/sysmacros.h to avoid minor/major glibc warnings - - The minor()/major() function definitions are moved to sys/sysmacros.h - and will be removed from sys/types.h. To correct below warning, simply - include sys/sysmacros.h. - - zpcictl.c: In function ‘sysfs_get_slot_addr’: - zpcictl.c:184:13: warning: In the GNU C Library, "major" is defined - by . For historical compatibility, it is - currently defined by as well, but we plan to - remove this soon. To use "major", include - directly. If you did not intend to use a system-defined macro - "major", you should undefine it after including . - major = major(dev_stat.st_rdev); - ^~~~~~~~~~~~~~~~~~~~~ - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Stefan Haberland - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.c | 1 + - 1 file changed, 1 insertion(+) - ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - - #include "lib/util_base.h" diff --git a/s390-tools-sles15sp1-06-cpumf-correct-counter-name-for-z13-and-z14.patch b/s390-tools-sles15sp1-06-cpumf-correct-counter-name-for-z13-and-z14.patch deleted file mode 100644 index c629e53..0000000 --- a/s390-tools-sles15sp1-06-cpumf-correct-counter-name-for-z13-and-z14.patch +++ /dev/null @@ -1,44 +0,0 @@ -Subject: cpumf: correct counter name for z13 and z14 -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: 9745e4678adf18869e661d13f2b666a929450fa1 -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf: correct counter name for z13 and z14 - - Signed-off-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/data/cpum-cf-extended-z13.ctr | 2 +- - cpumf/data/cpum-cf-extended-z14.ctr | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - ---- a/cpumf/data/cpum-cf-extended-z13.ctr -+++ b/cpumf/data/cpum-cf-extended-z13.ctr -@@ -16,7 +16,7 @@ - # - # Extended Counter Set - # --------------------------------------------------------------------- --Counter:128 Name:L1D_WRITES_RO_EXCL -+Counter:128 Name:L1D_RO_EXCL_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 ---- a/cpumf/data/cpum-cf-extended-z14.ctr -+++ b/cpumf/data/cpum-cf-extended-z14.ctr -@@ -19,7 +19,7 @@ - # - # Extended Counter Set - # --------------------------------------------------------------------- --Counter:128 Name:L1D_WRITES_RO_EXCL -+Counter:128 Name:L1D_RO_EXCL_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 diff --git a/s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch b/s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch deleted file mode 100644 index f7c3833..0000000 --- a/s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch +++ /dev/null @@ -1,3040 +0,0 @@ -Subject: zdev: Add support for handling auto-configuration data -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: fe68ec513dc1c73c1961f4e15b83d51291df20eb -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Add support for handling auto-configuration data - - Auto-configuration is the name of a new configuration target that is - supported by chzdev and lszdev besides the existing active and - persistent configuration targets. Directives created in this new - configuration are stored as udev rules in the /run/udev/rules.d - directory. - - Auto-configuration directives are only in effect if there are no - directives for the same device in the user-provided persistent - configuration. This allows users to override auto-configuration - directives if necessary. - - Due to the volatile nature of the /run directory, auto-configuration - directives are cleared on reboot. Therefore mechanisms that generate - auto-configuration directives must recreate them on every boot. - - The lszdev tool displays auto-configuration data both in list view - as well as in detail view. Users can specify the new option --auto-conf - to only show data from this configuration target. - - Mechanisms that generate automated configuration directives can use - chzdev together with the --auto-conf option to create the corresponding - udev rules. - - Note: This change does not include a mechanism that generates - auto-configuration directives. - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/device.h | 4 - zdev/include/misc.h | 28 +++--- - zdev/include/path.h | 5 - - zdev/include/setting.h | 3 - zdev/include/subtype.h | 22 ++++ - zdev/include/udev.h | 5 - - zdev/include/udev_ccw.h | 8 - - zdev/include/udev_ccwgroup.h | 12 +- - zdev/include/udev_zfcp_lun.h | 10 +- - zdev/man/chzdev.8 | 16 +++ - zdev/man/lszdev.8 | 22 +++- - zdev/src/ccw.c | 99 ++++++++++++++++++--- - zdev/src/ccwgroup.c | 76 ++++++++++++++-- - zdev/src/chzdev.c | 162 +++++++++++++++++++++++------------ - zdev/src/chzdev_usage.txt | 1 - zdev/src/dasd.c | 48 +++++----- - zdev/src/device.c | 55 +++++++++++ - zdev/src/export.c | 96 +++++++++++++++----- - zdev/src/firmware.c | 6 + - zdev/src/lszdev.c | 154 +++++++++++++++++++++++++-------- - zdev/src/lszdev_usage.txt | 1 - zdev/src/misc.c | 25 +++-- - zdev/src/path.c | 14 +-- - zdev/src/qeth.c | 32 ++++++ - zdev/src/select.c | 17 ++- - zdev/src/setting.c | 14 ++- - zdev/src/subtype.c | 83 +++++++++++++++++ - zdev/src/udev.c | 9 + - zdev/src/udev_ccw.c | 30 +++--- - zdev/src/udev_ccwgroup.c | 41 ++++---- - zdev/src/udev_zfcp_lun.c | 46 +++++---- - zdev/src/zfcp_lun.c | 51 +++++++++-- - 32 files changed, 910 insertions(+), 285 deletions(-) - ---- a/zdev/include/device.h -+++ b/zdev/include/device.h -@@ -45,6 +45,7 @@ struct device_state { - * @node: Node for adding this device to a list - * @active: Device state in the active configuration - * @persistent: Device state in the persistent configuration -+ * @autoconf: Auto-configured device state - * @errors: A strlist of error and warning messages issued for the device - * @processed: Device has been processed - */ -@@ -59,6 +60,7 @@ struct device { - - struct device_state active; - struct device_state persistent; -+ struct device_state autoconf; - - unsigned int processed:1; - }; -@@ -97,4 +99,6 @@ void device_list_print(struct device_lis - struct setting_list *device_get_setting_list(struct device *dev, - config_t config); - -+config_t device_get_config(struct device *dev); -+ - #endif /* DEVICE_H */ ---- a/zdev/include/misc.h -+++ b/zdev/include/misc.h -@@ -19,9 +19,14 @@ - #include "exit_code.h" - - #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) --#define SCOPE_ACTIVE(x) (((x) == config_active) || ((x) == config_all)) --#define SCOPE_PERSISTENT(x) (((x) == config_persistent) || \ -- ((x) == config_all)) -+#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) -+#define SCOPE_ALL(x) ((x) == (config_active | config_persistent |\ -+ config_autoconf)) -+#define SCOPE_SINGLE(x) ((x) == config_active || \ -+ (x) == config_persistent || \ -+ (x) == config_autoconf) - - #define DELAY_INDENT 4 - -@@ -34,12 +39,15 @@ - - #define EVEN(x) (((x) & 1) == 0) - --/* Enumeration of configuration sets. */ --typedef enum { -- config_active, -- config_persistent, -- config_all, --} config_t; -+/* Enumeration of configuration sets. Multiple configuration sets can be -+ * combined using bit-wise or. */ -+enum { -+ config_active = 1, -+ config_persistent = 2, -+ config_autoconf = 4, -+ config_all = 7, -+}; -+typedef int config_t; - - typedef enum { - err_ignore, -@@ -167,7 +175,7 @@ exit_code_t misc_write_text_file(const c - exit_code_t misc_write_text_file_retry(const char *, const char *, err_t); - exit_code_t misc_mktemp(char **, int *); - char *misc_readlink(const char *path); --config_t get_config(int, int); -+config_t get_config(int act, int pers, int ac); - bool is_zvm(void); - bool is_terminal(void); - const char *config_to_str(config_t); ---- a/zdev/include/path.h -+++ b/zdev/include/path.h -@@ -24,6 +24,7 @@ - #define PATH_CCW_BUS "/sys/bus/ccw" - #define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup" - #define PATH_UDEV_RULES "/etc/udev/rules.d" -+#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d" - #define PATH_PROC "/proc" - - #define PATH_UDEVADM "udevadm" -@@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *, - char *path_get_ccw_devices(const char *); - char *path_get_ccwgroup_device(const char *, const char *); - char *path_get_ccwgroup_devices(const char *); --char *path_get_udev_rule(const char *, const char *); --char *path_get_udev_rules(void); -+char *path_get_udev_rule(const char *type, const char *id, bool vol); -+char *path_get_udev_rules(bool vol); - char *path_get_proc(const char *); - char *path_get_sys_bus_dev(const char *, const char *); - char *path_get_sys_bus_drv(const char *, const char *); ---- a/zdev/include/setting.h -+++ b/zdev/include/setting.h -@@ -94,7 +94,8 @@ void setting_list_map_values(struct sett - void setting_list_mark_default_derived(struct setting_list *); - int setting_list_count_set(struct setting_list *); - void setting_list_remove_derived(struct setting_list *); --char *setting_get_changes(struct setting_list *, struct setting_list *); -+char *setting_get_changes(struct setting_list *act, struct setting_list *pers, -+ struct setting_list *ac); - bool setting_match_value(struct setting *, const char *); - - #endif /* SETTING_H */ ---- a/zdev/include/subtype.h -+++ b/zdev/include/subtype.h -@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(stru - * - * @exists_active: Check if device exists in active configuration - * @exists_persistent: Check if device exists in persistent configuration -+ * @exists_autoconf: Check if device exists in autoconf configuration - * - * @add_active_ids: Add IDs of all devices existing in active configuration to - * specified strlist - * @add_persistent_ids: Add IDs of all devices existing in persistent - * configuration to specified strlist -+ * @add_autoconf_ids: Add IDs of all devices existing in autoconf -+ * configuration to specified strlist - * - * @read_active: Read device configuration from active configuration - * @read_persistent: Read device configuration from persistent configuration -+ * @read_autoconf: Read device configuration from autoconf configuration - * - * @configure_active: Apply configuration to active configuration - * @configure_persistent: Apply configuration to persistent configuration -+ * @configure_autoconf: Apply configuration to autoconf configuration - * - * @check_pre_write: Optional: Determine if the given configuration is valid - * for the specified device. If not, emit warning messages -@@ -150,24 +155,33 @@ struct subtype { - - bool (*exists_active)(struct subtype *, const char *); - bool (*exists_persistent)(struct subtype *, const char *); -+ bool (*exists_autoconf)(struct subtype *, const char *); - - void (*add_active_ids)(struct subtype *, struct util_list *); - void (*add_persistent_ids)(struct subtype *, - struct util_list *); -+ void (*add_autoconf_ids)(struct subtype *, -+ struct util_list *); - - exit_code_t (*read_active)(struct subtype *, struct device *, - read_scope_t); - exit_code_t (*read_persistent)(struct subtype *, struct device *, - read_scope_t); -+ exit_code_t (*read_autoconf)(struct subtype *, struct device *, -+ read_scope_t); - - exit_code_t (*configure_active)(struct subtype *, struct device *); - exit_code_t (*configure_persistent)(struct subtype *, - struct device *); -+ exit_code_t (*configure_autoconf)(struct subtype *, -+ struct device *); - - exit_code_t (*deconfigure_active)(struct subtype *, - struct device *); - exit_code_t (*deconfigure_persistent)(struct subtype *, - struct device *); -+ exit_code_t (*deconfigure_autoconf)(struct subtype *, -+ struct device *); - - exit_code_t (*check_pre_configure)(struct subtype *, - struct device *, int, config_t); -@@ -217,23 +231,31 @@ void subtype_exit(struct subtype *); - - bool subtype_device_exists_active(struct subtype *, const char *); - bool subtype_device_exists_persistent(struct subtype *, const char *); -+bool subtype_device_exists_autoconf(struct subtype *st, const char *id); - - void subtype_add_active_ids(struct subtype *, struct util_list *); - void subtype_add_persistent_ids(struct subtype *, struct util_list *); -+void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids); - - exit_code_t subtype_device_read_active(struct subtype *, struct device *, - read_scope_t); - exit_code_t subtype_device_read_persistent(struct subtype *, struct device *, - read_scope_t); -+exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev, -+ read_scope_t scope); - - exit_code_t subtype_device_configure_active(struct subtype *, struct device *); - exit_code_t subtype_device_configure_persistent(struct subtype *, - struct device *); -+exit_code_t subtype_device_configure_autoconf(struct subtype *st, -+ struct device *dev); - - exit_code_t subtype_device_deconfigure_active(struct subtype *, - struct device *); - exit_code_t subtype_device_deconfigure_persistent(struct subtype *st, - struct device *); -+exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st, -+ struct device *dev); - - exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int, - config_t); ---- a/zdev/include/udev.h -+++ b/zdev/include/udev.h -@@ -40,8 +40,9 @@ exit_code_t udev_read_file(const char *, - void udev_free_file(struct udev_file *); - void udev_file_print(struct udev_file *); - --void udev_get_device_ids(const char *, struct util_list *); --exit_code_t udev_remove_rule(const char *, const char *); -+void udev_get_device_ids(const char *type, struct util_list *list, -+ bool autoconf); -+exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf); - - void udev_settle(void); - ---- a/zdev/include/udev_ccw.h -+++ b/zdev/include/udev_ccw.h -@@ -15,9 +15,9 @@ - - struct device; - --bool udev_ccw_exists(const char *, const char *); --exit_code_t udev_ccw_read_device(struct device *); --exit_code_t udev_ccw_write_device(struct device *); --exit_code_t udev_ccw_write_cio_ignore(const char *); -+bool udev_ccw_exists(const char *type, const char *id, bool autoconf); -+exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf); -+exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf); -+exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf); - - #endif /* UDEV_CCW_H */ ---- a/zdev/include/udev_ccwgroup.h -+++ b/zdev/include/udev_ccwgroup.h -@@ -16,10 +16,12 @@ - struct device; - struct util_list; - --bool udev_ccwgroup_exists(const char *, const char *); --exit_code_t udev_ccwgroup_read_device(struct device *); --exit_code_t udev_ccwgroup_write_device(struct device *); --void udev_ccwgroup_add_device_ids(const char *, struct util_list *); --exit_code_t udev_ccwgroup_remove_rule(const char *, const char *); -+bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf); -+exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf); -+exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf); -+void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list, -+ bool autoconf); -+exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id, -+ bool autoconf); - - #endif /* UDEV_CCWGROUP_H */ ---- a/zdev/include/udev_zfcp_lun.h -+++ b/zdev/include/udev_zfcp_lun.h -@@ -15,10 +15,10 @@ - - struct device; - --void udev_zfcp_lun_add_device_ids(struct util_list *); --bool udev_zfcp_lun_exists(const char *); --exit_code_t udev_zfcp_lun_read_device(struct device *); --exit_code_t udev_zfcp_lun_write_device(struct device *); --exit_code_t udev_zfcp_lun_remove_rule(const char *); -+void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf); -+bool udev_zfcp_lun_exists(const char *id, bool autoconf); -+exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf); -+exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf); -+exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf); - - #endif /* UDEV_ZFCP_LUN_H */ ---- a/zdev/man/chzdev.8 -+++ b/zdev/man/chzdev.8 -@@ -428,8 +428,8 @@ using the \-\-import action like in the - .B Note: - By default all configuration data that is read is also applied. To reduce the - scope of imported configuration data, you can select specific devices, a device --type, or define whether only data for the active or persistent configuration --should be imported. -+type, or define whether only data for the active, persistent or -+auto-configuration should be imported. - .PP - . - .OD list-attributes "l" "" -@@ -472,6 +472,18 @@ on reboot, or when a device becomes unav - unloaded. - .PP - . -+.OD auto-conf "" "" -+Apply changes to the auto-configuration only. -+ -+This option is used internally to apply machine-provided I/O configuration data -+to a Linux system. -+ -+.B Note: -+There is typically no need for users to specify this option directly. -+In particular, user-initiated changes to this configuration will be lost -+the next time that machine-provided data is obtained (i.e. during boot). -+.PP -+. - .OD base "" "PATH" | "KEY" = "VALUE" - Change file system paths used to access files. - ---- a/zdev/man/lszdev.8 -+++ b/zdev/man/lszdev.8 -@@ -69,12 +69,13 @@ With no further options specified, the o - . - . - .SS "Configurations" --There are two sources for configuration information: the active configuration --of the currently running system, and the persistent configuration stored in --configuration files. -+There are three sources for configuration information: the active configuration -+of the currently running system, the persistent configuration stored in -+configuration files, and the auto-configuration that is provided by some -+machine types to automatically enable I/O devices. - .PP - By default lszdev displays information from both the active and the persistent --configuration. -+configuration, and, if available, from the auto-configuration. - .PP - . - . -@@ -319,6 +320,19 @@ Restricts output to information obtained - is information from the running system. - .PP - . -+.OD auto-conf "" "" -+List information from the auto-configuration only. -+ -+Restricts output to information obtained from the auto-configuration. -+The auto-configuration is the collection of configuration data obtained -+automatically on some machine models during boot. -+ -+.B Note: -+This data is refreshed during each boot. Also configuration directives in -+the auto-configuration only take effect if there is no directive for the -+same device in the persistent configuration. -+.PP -+. - .OD base "" "PATH" | "KEY" = "VALUE" - Change file system paths used to access files. - ---- a/zdev/src/ccw.c -+++ b/zdev/src/ccw.c -@@ -892,12 +892,13 @@ static exit_code_t collect_group_cb(stru - } - - /* Set bits for all persistently configured CCW devices. */ --static char ***id_bitmap_collect(void) -+static char ***id_bitmap_collect(bool autoconf) - { - char ***id_bitmap; - int i, j; - struct devtype *dt; - struct subtype *st; -+ config_t config = autoconf ? config_autoconf : config_persistent; - - id_bitmap = id_bitmap_new(); - -@@ -906,14 +907,14 @@ static char ***id_bitmap_collect(void) - for (j = 0; (st = dt->subtypes[j]); j++) { - /* Collect CCW device IDs. */ - if (st->namespace == &ccw_namespace) { -- subtype_for_each_id(st, config_persistent, -+ subtype_for_each_id(st, config, - collect_cb, id_bitmap); - } - /* Collect CCWGROUP device IDs. Since there may be - * multiple namespaces, we need to make use of this - * hack. */ - if (ccwgroup_compatible_namespace(st->namespace)) { -- subtype_for_each_id(st, config_persistent, -+ subtype_for_each_id(st, config, - collect_group_cb, - id_bitmap); - } -@@ -952,7 +953,7 @@ static void range_add(struct util_list * - free(f_str); - } - --static struct util_list *cio_ignore_get_ranges(void) -+static struct util_list *cio_ignore_get_ranges(bool autoconf) - { - char ***id_bitmap; - unsigned int cssid, ssid, devno; -@@ -962,7 +963,7 @@ static struct util_list *cio_ignore_get_ - - ranges = strlist_new(); - -- id_bitmap = id_bitmap_collect(); -+ id_bitmap = id_bitmap_collect(autoconf); - for (cssid = 0; cssid < CSSID_MAX; cssid++) { - if (!id_bitmap[cssid]) - continue; -@@ -1003,24 +1004,34 @@ static struct util_list *cio_ignore_get_ - } - - /* Persistently configure cio_ignore. */ --exit_code_t ccw_blacklist_persist(void) -+static exit_code_t _ccw_blacklist_persist(bool autoconf) - { - struct util_list *ranges; - char *id_list; - exit_code_t rc; - - /* Get string to write to /proc/cio_ignore. */ -- ranges = cio_ignore_get_ranges(); -+ ranges = cio_ignore_get_ranges(autoconf); - id_list = strlist_flatten(ranges, ","); - strlist_free(ranges); - - /* Write udev rule to automatically write cio_ignore. */ -- rc = udev_ccw_write_cio_ignore(id_list); -+ rc = udev_ccw_write_cio_ignore(id_list, autoconf); - free(id_list); - - return rc; - } - -+exit_code_t ccw_blacklist_persist(void) -+{ -+ exit_code_t rc1, rc2; -+ -+ rc1 = _ccw_blacklist_persist(false); -+ rc2 = _ccw_blacklist_persist(true); -+ -+ return rc1 ? rc1 : rc2; -+} -+ - /* - * CCW device ID namespace. - */ -@@ -1368,7 +1379,13 @@ static bool ccw_st_exists_active(struct - /* Check if a configuration exists for a CCW device with the specified @id. */ - static bool ccw_st_exists_persistent(struct subtype *st, const char *id) - { -- return udev_ccw_exists(st->name, id); -+ return udev_ccw_exists(st->name, id, false); -+} -+ -+/* Check if a configuration exists for a CCW device with the specified @id. */ -+static bool ccw_st_exists_autoconf(struct subtype *st, const char *id) -+{ -+ return udev_ccw_exists(st->name, id, true); - } - - static bool get_ids_cb(const char *file, void *data) -@@ -1404,7 +1421,14 @@ static void ccw_st_add_active_ids(struct - * to strlist @ids. */ - static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids) - { -- udev_get_device_ids(st->name, ids); -+ udev_get_device_ids(st->name, ids, false); -+} -+ -+/* Add the IDs of all CCW devices for which a autoconf configuration exists -+ * to strlist @ids. */ -+static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids) -+{ -+ udev_get_device_ids(st->name, ids, true); - } - - /* Read the configuration of the CCW device with the specified @id from the -@@ -1440,7 +1464,16 @@ static exit_code_t ccw_st_read_persisten - struct device *dev, - read_scope_t scope) - { -- return udev_ccw_read_device(dev); -+ return udev_ccw_read_device(dev, false); -+} -+ -+/* Read the configuration of the CCW device with the specified @id from the -+ * autoconf configuration and add the resulting data to @dev. */ -+static exit_code_t ccw_st_read_autoconf(struct subtype *st, -+ struct device *dev, -+ read_scope_t scope) -+{ -+ return udev_ccw_read_device(dev, true); - } - - static int get_online(struct setting_list *list) -@@ -1505,7 +1538,14 @@ static exit_code_t ccw_st_configure_acti - static exit_code_t ccw_st_configure_persistent(struct subtype *st, - struct device *dev) - { -- return udev_ccw_write_device(dev); -+ return udev_ccw_write_device(dev, false); -+} -+ -+/* Create a autoconf configuration for the specified device @dev. */ -+static exit_code_t ccw_st_configure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return udev_ccw_write_device(dev, true); - } - - -@@ -1552,7 +1592,22 @@ static exit_code_t ccw_st_deconfigure_ac - static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st, - struct device *dev) - { -- return udev_remove_rule(st->name, dev->id); -+ return udev_remove_rule(st->name, dev->id, false); -+} -+ -+/** -+ * ccw_st_deconfigure_autoconf - Deconfigure device in autoconf -+ * configuration set -+ * @st: Subtype of target device -+ * @dev: Target device -+ * -+ * Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK -+ * on success, an error code otherwise. -+ */ -+static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return udev_remove_rule(st->name, dev->id, true); - } - - /* Perform basic sanity checks. */ -@@ -1589,6 +1644,8 @@ static void ccw_st_online_set(struct sub - setting_list_apply(dev->active.settings, a, name, value); - if (SCOPE_PERSISTENT(config)) - setting_list_apply(dev->persistent.settings, a, name, value); -+ if (SCOPE_AUTOCONF(config)) -+ setting_list_apply(dev->autoconf.settings, a, name, value); - } - - /* Determine the online state of the specified CCW device (0=offline, 1=online, -@@ -1596,14 +1653,16 @@ static void ccw_st_online_set(struct sub - static int ccw_st_online_get(struct subtype *st, struct device *dev, - config_t config) - { -- int act_online = 1, pers_online = 1; -+ int act_online = 1, pers_online = 1, auto_online = 1; - - if (SCOPE_ACTIVE(config)) - act_online = get_online(dev->active.settings); - if (SCOPE_PERSISTENT(config)) - pers_online = get_online(dev->persistent.settings); -+ if (SCOPE_AUTOCONF(config)) -+ auto_online = get_online(dev->autoconf.settings); - -- return MIN(act_online, pers_online); -+ return MIN(MIN(act_online, pers_online), auto_online); - } - - /* Determine if the online state of the specified CCW device was specified */ -@@ -1622,6 +1681,11 @@ static bool ccw_st_online_specified(stru - if (s && s->specified) - return true; - } -+ if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) { -+ s = setting_list_find(dev->autoconf.settings, "online"); -+ if (s && s->specified) -+ return true; -+ } - - return false; - } -@@ -1769,18 +1833,23 @@ struct subtype ccw_subtype = { - - .exists_active = &ccw_st_exists_active, - .exists_persistent = &ccw_st_exists_persistent, -+ .exists_autoconf = &ccw_st_exists_autoconf, - - .add_active_ids = &ccw_st_add_active_ids, - .add_persistent_ids = &ccw_st_add_persistent_ids, -+ .add_autoconf_ids = &ccw_st_add_autoconf_ids, - - .read_active = &ccw_st_read_active, - .read_persistent = &ccw_st_read_persistent, -+ .read_autoconf = &ccw_st_read_autoconf, - - .configure_active = &ccw_st_configure_active, - .configure_persistent = &ccw_st_configure_persistent, -+ .configure_autoconf = &ccw_st_configure_autoconf, - - .deconfigure_active = &ccw_st_deconfigure_active, - .deconfigure_persistent = &ccw_st_deconfigure_persistent, -+ .deconfigure_autoconf = &ccw_st_deconfigure_autoconf, - - .check_pre_configure = &ccw_st_check_pre_configure, - ---- a/zdev/src/ccwgroup.c -+++ b/zdev/src/ccwgroup.c -@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struc - } - if (SCOPE_PERSISTENT(config)) - setting_list_apply(dev->persistent.settings, a, name, value); -+ if (SCOPE_AUTOCONF(config)) -+ setting_list_apply(dev->autoconf.settings, a, name, value); - } - - static int get_online(struct setting_list *list) -@@ -446,18 +448,20 @@ static int get_online(struct setting_lis - } - - /* Return -1 if online state is not configured, 0 for offline and 1 for online. -- * If multiple configurations are specified, return the minimum of both. */ -+ * If multiple configurations are specified, return the minimum of all. */ - static int ccwgroup_st_online_get(struct subtype *st, struct device *dev, - config_t config) - { -- int act_online = 1, pers_online = 1; -+ int act_online = 1, pers_online = 1, auto_online = 1; - - if (SCOPE_ACTIVE(config)) - act_online = get_online(dev->active.settings); - if (SCOPE_PERSISTENT(config)) - pers_online = get_online(dev->persistent.settings); -+ if (SCOPE_AUTOCONF(config)) -+ auto_online = get_online(dev->autoconf.settings); - -- return MIN(act_online, pers_online); -+ return MIN(MIN(act_online, pers_online), auto_online); - } - - /* Determine if the online state of the specified device was modified. */ -@@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified - if (s && s->specified) - return true; - } -+ if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) { -+ s = setting_list_find(dev->autoconf.settings, "online"); -+ if (s && s->specified) -+ return true; -+ } - - return false; - } -@@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_pers - - expand_id(data->ccwgroupdrv, dev); - -- return udev_ccwgroup_read_device(dev); -+ return udev_ccwgroup_read_device(dev, false); -+} -+ -+static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st, -+ struct device *dev, -+ read_scope_t scope) -+{ -+ struct ccwgroup_subtype_data *data = st->data; -+ -+ expand_id(data->ccwgroupdrv, dev); -+ -+ return udev_ccwgroup_read_device(dev, true); - } - - static exit_code_t ccwgroup_st_configure_active(struct subtype *st, -@@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure - return device_write_active_settings(dev); - } - --static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st, -- struct device *dev) -+static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st, -+ struct device *dev, -+ bool autoconf) - { - struct ccwgroup_subtype_data *data = st->data; - struct ccwgroup_devid *devid = dev->devid; -@@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure - delayed_err("Incomplete device ID specified\n"); - return EXIT_INCOMPLETE_ID; - } -- return udev_ccwgroup_write_device(dev); -+ return udev_ccwgroup_write_device(dev, autoconf); -+} -+ -+static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st, -+ struct device *dev) -+{ -+ return _ccwgroup_st_configure_persistent(st, dev, false); -+} -+ -+static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return _ccwgroup_st_configure_persistent(st, dev, true); - } - -+ - static char *ccwgroup_st_get_active_attrib_path(struct subtype *, - struct device *, const char *); - -@@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigu - static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st, - struct device *dev) - { -- return udev_ccwgroup_remove_rule(st->name, dev->id); -+ return udev_ccwgroup_remove_rule(st->name, dev->id, false); -+} -+ -+static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return udev_ccwgroup_remove_rule(st->name, dev->id, true); - } - - /* Check if a CCWGROUP device with the specified ID exists. */ -@@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(st - - static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id) - { -- return udev_ccwgroup_exists(st->name, id); -+ return udev_ccwgroup_exists(st->name, id, false); -+} -+ -+static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id) -+{ -+ return udev_ccwgroup_exists(st->name, id, true); - } - - int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr) -@@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(s - static void ccwgroup_st_add_persistent_ids(struct subtype *st, - struct util_list *ids) - { -- udev_ccwgroup_add_device_ids(st->name, ids); -+ udev_ccwgroup_add_device_ids(st->name, ids, false); -+} -+ -+static void ccwgroup_st_add_autoconf_ids(struct subtype *st, -+ struct util_list *ids) -+{ -+ udev_ccwgroup_add_device_ids(st->name, ids, true); - } - - /* Check if CCW device ID @b is part of CCW group device ID @a. */ -@@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = { - - .exists_active = &ccwgroup_st_exists_active, - .exists_persistent = &ccwgroup_st_exists_persistent, -+ .exists_autoconf = &ccwgroup_st_exists_autoconf, - - .add_active_ids = &ccwgroup_st_add_active_ids, - .add_persistent_ids = &ccwgroup_st_add_persistent_ids, -+ .add_autoconf_ids = &ccwgroup_st_add_autoconf_ids, - - .read_active = &ccwgroup_st_read_active, - .read_persistent = &ccwgroup_st_read_persistent, -+ .read_autoconf = &ccwgroup_st_read_autoconf, - - .configure_active = &ccwgroup_st_configure_active, - .configure_persistent = &ccwgroup_st_configure_persistent, -+ .configure_autoconf = &ccwgroup_st_configure_autoconf, - - .deconfigure_active = &ccwgroup_st_deconfigure_active, - .deconfigure_persistent = &ccwgroup_st_deconfigure_persistent, -+ .deconfigure_autoconf = &ccwgroup_st_deconfigure_autoconf, - - .online_set = &ccwgroup_st_online_set, - .online_get = &ccwgroup_st_online_get, ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -86,6 +86,7 @@ struct options { - config_t config; - unsigned int active:1; - unsigned int persistent:1; -+ unsigned int auto_conf:1; - struct util_list *remove; /* List of struct strlist_node */ - unsigned int remove_all:1; - unsigned int force:1; -@@ -138,6 +139,7 @@ enum { - OPT_VERBOSE = 'V', - OPT_QUIET = 'q', - OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__), -+ OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__), - }; - - static struct opts_conflict conflict_list[] = { -@@ -172,11 +174,13 @@ static struct opts_conflict conflict_lis - OPTS_CONFLICT(OPT_APPLY, - OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS, - OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE, -- OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0), -+ OPT_REMOVE_ALL, OPT_ACTIVE, 0), - OPTS_CONFLICT(OPT_ONLINE, - OPT_OFFLINE), - OPTS_CONFLICT(OPT_QUIET, - OPT_VERBOSE), -+ OPTS_CONFLICT(OPT_AUTO_CONF, -+ OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES), - OPTS_CONFLICT(0, 0), - }; - -@@ -210,6 +214,7 @@ static const struct option opt_list[] = - /* Options. */ - { "active", no_argument, NULL, OPT_ACTIVE }, - { "persistent", no_argument, NULL, OPT_PERSISTENT }, -+ { "auto-conf", no_argument, NULL, OPT_AUTO_CONF }, - { "remove", required_argument, NULL, OPT_REMOVE }, - { "remove-all", no_argument, NULL, OPT_REMOVE_ALL }, - { "force", no_argument, NULL, OPT_FORCE }, -@@ -883,6 +888,11 @@ static exit_code_t parse_options(struct - opts->persistent = 1; - break; - -+ case OPT_AUTO_CONF: -+ /* --auto-conf */ -+ opts->auto_conf = 1; -+ break; -+ - case OPT_REMOVE: - /* --remove ATTRIB */ - strlist_add(opts->remove, "%s", optarg); -@@ -977,7 +987,13 @@ static exit_code_t parse_options(struct - goto out; - - /* Determine configuration set. */ -- opts->config = get_config(opts->active, opts->persistent); -+ if (!opts->active && !opts->persistent && !opts->auto_conf) { -+ /* Default configuration targets are active + persistent */ -+ opts->config = config_active | config_persistent; -+ } else { -+ opts->config = get_config(opts->active, opts->persistent, -+ opts->auto_conf); -+ } - - /* Handle positional parameters. */ - rc = parse_positional(opts, argc, argv, optind); -@@ -1049,13 +1065,15 @@ static void remove_all_settings(struct s - /* Perform --remove-all operation for specified config on device. */ - static exit_code_t device_remove_all(struct device *dev, config_t config) - { -- int active, persistent; -+ int active, persistent, autoconf; - - active = SCOPE_ACTIVE(config) ? - count_removable(dev->active.settings, 1) : 0; - persistent = SCOPE_PERSISTENT(config) ? - count_removable(dev->persistent.settings, 0) : 0; -- if (active == 0 && persistent == 0) { -+ autoconf = SCOPE_AUTOCONF(config) ? -+ count_removable(dev->autoconf.settings, 0) : 0; -+ if (active == 0 && persistent == 0 && autoconf == 0) { - delayed_err("No removable settings found\n"); - return EXIT_SETTING_NOT_FOUND; - } -@@ -1063,6 +1081,8 @@ static exit_code_t device_remove_all(str - remove_all_settings(dev->active.settings, 1); - if (persistent) - remove_all_settings(dev->persistent.settings, 0); -+ if (autoconf) -+ remove_all_settings(dev->autoconf.settings, 0); - - return EXIT_OK; - } -@@ -1132,6 +1152,13 @@ static exit_code_t device_remove_setting - goto out; - } - -+ if (SCOPE_AUTOCONF(config)) { -+ rc = remove_settings(dev->autoconf.settings, names, found, -+ notfound, 0); -+ if (rc) -+ goto out; -+ } -+ - if (!util_list_is_empty(notfound)) { - flat = strlist_flatten(notfound, " "); - delayed_err("Setting not found: %s\n", flat); -@@ -1199,7 +1226,8 @@ static void print_dev_config_info(struct - - changes = setting_get_changes( - SCOPE_ACTIVE(config) ? dev->active.settings : NULL, -- SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL); -+ SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL, -+ SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL); - if (changes) - info(" Changes: %s\n", changes); - free(changes); -@@ -1257,6 +1285,12 @@ static exit_code_t cfg_mod_existence(str - dev->persistent.modified = 1; - } - -+ /* Create autoconf config if necessary. */ -+ if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) { -+ dev->autoconf.exists = 1; -+ dev->autoconf.modified = 1; -+ } -+ - return EXIT_OK; - } - -@@ -1296,11 +1330,14 @@ online: - /* Make sure there's an online attribute. */ - ensure_online(dev, config_active); - ensure_online(dev, config_persistent); -+ ensure_online(dev, config_autoconf); - - mand: - /* Ensure default values for mandatory attributes. */ - setting_list_apply_defaults(dev->persistent.settings, - dev->subtype->dev_attribs, true); -+ setting_list_apply_defaults(dev->autoconf.settings, -+ dev->subtype->dev_attribs, true); - - return EXIT_OK; - } -@@ -1336,7 +1373,8 @@ static exit_code_t cfg_write(struct devi - if (!device_needs_writing(dev, config) && !force) - goto out; - -- if (check_active && config == config_persistent && -+ if (check_active && !SCOPE_ACTIVE(config) && -+ (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) && - (!dev->active.exists && !dev->active.definable)) { - rc = handle_nonexistent(dev); - if (rc) -@@ -1377,7 +1415,7 @@ static exit_code_t cfg_configure(struct - if (proc_ptr) - *proc_ptr = 0; - -- /* Read current device data. Note that we read data from both -+ /* Read current device data. Note that we read data from all - * configurations to enable QETH autodetection and subtype - * detection (e.g. dasd -> dasd_fba).*/ - dev = NULL; -@@ -1398,23 +1436,17 @@ static exit_code_t cfg_configure(struct - - /* Exit here if we're only trying and device cannot be configured. */ - if (try && !(dev->active.exists || dev->active.definable || -- dev->persistent.exists)) { -+ dev->persistent.exists || dev->autoconf.exists)) { - return EXIT_DEVICE_NOT_FOUND; - } - -- if (config == config_persistent) { -- /* Abort if a modification action is triggered for a -- * non-existing persistent device. */ -- if (!dev->persistent.exists && -- (!util_list_is_empty(opts->remove) || opts->remove_all)) -- return EXIT_DEVICE_NOT_FOUND; -+ /* Create device if needed by action. */ -+ if (opts->enable || !util_list_is_empty(opts->settings)) { -+ rc = cfg_mod_existence(dev, config); -+ if (rc) -+ return rc; - } - -- /* Apply changes to device existence. */ -- rc = cfg_mod_existence(dev, config); -- if (rc) -- return rc; -- - /* Apply changes to device settings. */ - rc = cfg_mod_settings(dev, opts, prereq); - if (rc) -@@ -1426,10 +1458,12 @@ static exit_code_t cfg_configure(struct - - /* Apply persistent configuration to active configuration. */ - static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq, -- struct device **dev_ptr, int *proc_ptr) -+ struct device **dev_ptr, int *proc_ptr, -+ bool autoconf) - { - exit_code_t rc; - struct device *dev; -+ struct device_state *state; - - /* Reset processed flag. */ - if (proc_ptr) -@@ -1452,8 +1486,9 @@ static exit_code_t cfg_apply(struct subt - *proc_ptr = 1; - dev->processed = 1; - -+ state = autoconf ? &dev->autoconf : &dev->persistent; - /* Exit here if there is no persistent configuration. */ -- if (!dev->persistent.exists) -+ if (!state->exists) - return EXIT_NO_DATA; - - /* Apply changes to device existence. */ -@@ -1462,8 +1497,7 @@ static exit_code_t cfg_apply(struct subt - return rc; - - /* Copy persistent settings to active configuration. */ -- rc = device_apply_settings(dev, config_active, -- &dev->persistent.settings->list); -+ rc = device_apply_settings(dev, config_active, &state->settings->list); - if (rc) - return rc; - -@@ -1477,7 +1511,8 @@ static exit_code_t cfg_import(struct sub - struct device **dev_ptr, int *proc_ptr) - { - exit_code_t rc; -- struct setting_list *active = NULL, *persistent = NULL; -+ struct setting_list *active = NULL, *persistent = NULL, -+ *autoconf = NULL; - struct device *dev; - - /* Reset processed flag. */ -@@ -1495,6 +1530,7 @@ static exit_code_t cfg_import(struct sub - return EXIT_OK; - active = setting_list_copy(dev->active.settings); - persistent = setting_list_copy(dev->persistent.settings); -+ autoconf = setting_list_copy(dev->autoconf.settings); - } else if (!prereq) { - /* Should not happen. */ - return EXIT_OK; -@@ -1524,14 +1560,20 @@ static exit_code_t cfg_import(struct sub - &persistent->list); - if (rc) - goto out; -+ rc = device_apply_settings(dev, config_autoconf, -+ &autoconf->list); -+ if (rc) -+ goto out; - } - ensure_online(dev, config_active); - ensure_online(dev, config_persistent); -+ ensure_online(dev, config_autoconf); - - /* Write resulting device data. */ - rc = cfg_write(dev, prereq, config, 0); - - out: -+ setting_list_free(autoconf); - setting_list_free(persistent); - setting_list_free(active); - -@@ -1609,11 +1651,13 @@ static exit_code_t print_config_result(s - if (opts->deconfigure) { - op = "deconfigure"; - verb = "deconfigured"; -- if (dev) -+ if (dev) { - already = !dev->active.modified && -- !dev->persistent.modified; -- else if (rc == EXIT_DEVICE_NOT_FOUND && -- config == config_persistent) { -+ !dev->persistent.modified && -+ !dev->autoconf.modified; -+ } else if (rc == EXIT_DEVICE_NOT_FOUND && -+ (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) || -+ SCOPE_AUTOCONF(config)))) { - rc = EXIT_OK; - already = 1; - } -@@ -1685,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct su - prereqs = selected_dev_list_new(); - subtype_add_prereqs(st, id, prereqs); - util_list_iterate(prereqs, sel) { -- if (opts->apply) -- rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc); -- else if (opts->import) { -+ if (opts->apply) { -+ rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc, -+ opts->auto_conf); -+ } else if (opts->import) { - rc = cfg_import(sel->st, sel->id, config, 1, &dev, - &proc); - } else { -@@ -1760,9 +1805,11 @@ static exit_code_t configure_devices(str - struct namespace *ns; - const char *param; - struct device *dev; -+ config_t config = opts->config; - - /* Determine list of selected devices. */ -- if (opts->config == config_persistent || -+ if ((!SCOPE_ACTIVE(config) && -+ (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) || - (opts->select->subtype && opts->select->subtype->support_definable)) - existing = 0; - else -@@ -1808,9 +1855,10 @@ static exit_code_t configure_devices(str - goto next; - - /* Configure actual target device. */ -- if (opts->apply) -- rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc); -- else { -+ if (opts->apply) { -+ rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc, -+ opts->auto_conf); -+ } else { - rc = cfg_configure(sel->st, sel->id, opts, 0, - 0, &dev, &proc); - } -@@ -1906,7 +1954,7 @@ static exit_code_t deconfigure_one_devic - dev->processed = 1; - - if (try && !(dev->active.exists || dev->active.definable || -- dev->persistent.exists)) { -+ dev->persistent.exists || dev->autoconf.exists)) { - /* Attempt to deconfigure this device will fail. */ - return EXIT_DEVICE_NOT_FOUND; - } -@@ -1916,7 +1964,8 @@ static exit_code_t deconfigure_one_devic - * dev. */ - if (SCOPE_ACTIVE(config) && - !(dev->active.exists || dev->active.definable)) { -- if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists) -+ if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) || -+ (SCOPE_AUTOCONF(config) && dev->autoconf.exists))) - return EXIT_DEVICE_NOT_FOUND; - } - -@@ -1940,7 +1989,12 @@ static exit_code_t deconfigure_one_devic - dev->persistent.deconfigured = 1; - dev->persistent.modified = 1; - } -- if (!dev->active.modified && !dev->persistent.modified) -+ if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) { -+ dev->autoconf.deconfigured = 1; -+ dev->autoconf.modified = 1; -+ } -+ if (!dev->active.modified && !dev->persistent.modified && -+ !dev->autoconf.modified) - return EXIT_OK; - - /* Pre-write check. */ -@@ -2084,7 +2138,8 @@ static void print_type_config_info(struc - - changes = setting_get_changes( - SCOPE_ACTIVE(config) ? dt->active_settings : NULL, -- SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL); -+ SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL, -+ NULL); - if (changes) - info(" %s: %s\n", title, changes); - free(changes); -@@ -2498,6 +2553,8 @@ static void action_note(const char *msg, - info("%s the active configuration only\n", msg); - else if (config == config_persistent) - info("%s the persistent configuration only\n", msg); -+ else if (config == config_autoconf) -+ info("%s the auto-configuration only\n", msg); - } - - /* Export configuration of selected devices and/or device type to file. */ -@@ -2619,7 +2676,7 @@ static exit_code_t import_device(struct - struct subtype *st = dev->subtype; - exit_code_t rc; - config_t config; -- int proc = 0, active, persistent; -+ int proc = 0, active, persistent, autoconf; - - if (SCOPE_ACTIVE(opts->config)) - active = (dev->active.exists || dev->active.definable); -@@ -2629,7 +2686,16 @@ static exit_code_t import_device(struct - persistent = dev->persistent.exists; - else - persistent = 0; -- config = get_config(active, persistent); -+ if (SCOPE_AUTOCONF(opts->config)) -+ autoconf = dev->autoconf.exists; -+ else -+ autoconf = 0; -+ -+ if (!active && !persistent && !autoconf) { -+ /* Nothing to import */ -+ return EXIT_OK; -+ } -+ config = get_config(active, persistent, autoconf); - - /* First check for prerequisite devices that need to be configured. */ - rc = cfg_prereqs(st, dev->id, opts, config, 0); -@@ -2656,17 +2722,9 @@ static bool import_device_selected(struc - if (!select_opts_dev_specified(select)) - return false; - -- /* --active */ -- if (opts->config == config_active) { -- if (!dev->active.exists && !dev->active.definable) -- return false; -- } -- -- /* --persistent */ -- if (opts->config == config_persistent) { -- if (!dev->persistent.exists) -- return false; -- } -+ /* Target configuration */ -+ if ((device_get_config(dev) & opts->config) == 0) -+ return false; - - /* Devtype */ - if (select->devtype && dt != select->devtype) ---- a/zdev/src/chzdev_usage.txt -+++ b/zdev/src/chzdev_usage.txt -@@ -55,5 +55,6 @@ OPTIONS - --dry-run Display changes without applying - --base PATH Use PATH as base for accessing files - --no-settle Do not wait for udev to settle -+ --auto-conf Apply changes to auto-configuration only - -V, --verbose Print additional run-time information - -q, --quiet Print only minimal run-time information ---- a/zdev/src/dasd.c -+++ b/zdev/src/dasd.c -@@ -316,34 +316,34 @@ static struct attrib dasd_attr_safe_offl - * DASD subtype methods. - */ - --/* Check if use_diag setting can be correctly applied. */ --static exit_code_t check_use_diag(struct device *dev, config_t config) -+static bool _check_use_diag(struct setting_list *list) - { - struct setting *u; -- int zvm = is_zvm(); - -- if (SCOPE_ACTIVE(config)) { -- u = setting_list_find(dev->active.settings, -- dasd_attr_use_diag.name); -- if (u && u->modified) { -- if (u->value && atoi(u->value) == 1 && !zvm) { -- delayed_warn("Cannot set 'use_diag=1' on " -- "non-z/VM system\n"); -- return EXIT_INVALID_CONFIG; -- } -- } -- } -- if (SCOPE_PERSISTENT(config)) { -- u = setting_list_find(dev->persistent.settings, -- dasd_attr_use_diag.name); -- if (u && u->modified) { -- if (u->value && atoi(u->value) == 1 && !zvm) { -- delayed_warn("Cannot set 'use_diag=1' on " -- "non-z/VM system\n"); -- return EXIT_INVALID_CONFIG; -- } -+ u = setting_list_find(list, dasd_attr_use_diag.name); -+ if (u && u->modified) { -+ if (u->value && atoi(u->value) == 1) { -+ delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n"); -+ return false; - } - } -+ return true; -+} -+ -+/* Check if use_diag setting can be correctly applied. */ -+static exit_code_t check_use_diag(struct device *dev, config_t config) -+{ -+ if (is_zvm()) -+ return EXIT_OK; -+ -+ if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings)) -+ return EXIT_INVALID_CONFIG; -+ if (SCOPE_PERSISTENT(config) && -+ !_check_use_diag(dev->persistent.settings)) -+ return EXIT_INVALID_CONFIG; -+ if (SCOPE_AUTOCONF(config) && -+ !_check_use_diag(dev->autoconf.settings)) -+ return EXIT_INVALID_CONFIG; - - return EXIT_OK; - } -@@ -376,6 +376,8 @@ static void dasd_st_add_modules(struct s - dasd_attr_use_diag.name, &changed, &aset); - setting_list_get_bool_state(dev->persistent.settings, - dasd_attr_use_diag.name, &changed, &pset); -+ setting_list_get_bool_state(dev->autoconf.settings, -+ dasd_attr_use_diag.name, &changed, &pset); - - if (aset || pset) - strlist_add_unique(modules, DASD_DIAG_MOD_NAME); ---- a/zdev/src/device.c -+++ b/zdev/src/device.c -@@ -40,6 +40,7 @@ struct device *device_new(struct subtype - - dev->active.settings = setting_list_new(); - dev->persistent.settings = setting_list_new(); -+ dev->autoconf.settings = setting_list_new(); - - return dev; - } -@@ -53,6 +54,7 @@ void device_free(struct device *dev) - free(dev->devid); - setting_list_free(dev->active.settings); - setting_list_free(dev->persistent.settings); -+ setting_list_free(dev->autoconf.settings); - free(dev); - } - -@@ -83,6 +85,15 @@ void device_print(struct device *dev, in - setting_list_print(dev->persistent.settings, level + 8); - else - printf("%*s\n", level + 8, ""); -+ -+ printf("%*sautoconf:\n", level + 4, ""); -+ printf("%*sexists=%d mod=%d deconf=%d\n", -+ level + 8, "", dev->autoconf.exists, dev->autoconf.modified, -+ dev->autoconf.deconfigured); -+ if (dev->autoconf.settings) -+ setting_list_print(dev->autoconf.settings, level + 8); -+ else -+ printf("%*s\n", level + 8, ""); - } - - static const void *device_hash_get_id(void *dev_ptr) -@@ -182,6 +193,10 @@ bool device_needs_writing(struct device - (dev->persistent.modified || dev->persistent.deconfigured || - setting_list_modified(dev->persistent.settings))) - return true; -+ if (SCOPE_AUTOCONF(config) && -+ (dev->autoconf.modified || dev->autoconf.deconfigured || -+ setting_list_modified(dev->autoconf.settings))) -+ return true; - - return false; - } -@@ -204,6 +219,8 @@ static exit_code_t apply_setting(struct - /* Check for activeonly. */ - if (!force && SCOPE_PERSISTENT(config) && a->activeonly) - goto err_activeonly_forceable; -+ if (!force && SCOPE_AUTOCONF(config) && a->activeonly) -+ goto err_activeonly_forceable; - /* Check for multiple values. */ - if (!force && !a->multi && strlist_find(processed, key)) - goto err_multi_forceable; -@@ -231,8 +248,15 @@ static exit_code_t apply_setting(struct - a, key, value); - } - -+ /* Apply to autoconf config. */ -+ if (SCOPE_AUTOCONF(config)) { -+ setting_list_apply_specified(dev->autoconf.settings, -+ a, key, value); -+ } -+ - /* Additional warning when trying to persist read-only setting. */ -- if (config == config_persistent) { -+ if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) || -+ SCOPE_AUTOCONF(config))) { - s = setting_list_find(dev->active.settings, key); - if (s && s->readonly) - warn_readonly = true; -@@ -341,6 +365,8 @@ void device_reset(struct device *dev, co - reset_device_state(&dev->active); - if (SCOPE_PERSISTENT(config)) - reset_device_state(&dev->persistent); -+ if (SCOPE_AUTOCONF(config)) -+ reset_device_state(&dev->autoconf); - dev->processed = 0; - } - -@@ -567,6 +593,12 @@ exit_code_t device_check_settings(struct - err)) - return EXIT_INVALID_CONFIG; - } -+ if (SCOPE_AUTOCONF(config)) { -+ if (!setting_list_check_conflict(dev->autoconf.settings, -+ config_autoconf, -+ err)) -+ return EXIT_INVALID_CONFIG; -+ } - - return EXIT_OK; - } -@@ -578,8 +610,27 @@ struct setting_list *device_get_setting_ - - if (config == config_active) - settings = dev->active.settings; -- else -+ else if (config == config_persistent) - settings = dev->persistent.settings; -+ else if (config == config_autoconf) -+ settings = dev->autoconf.settings; - - return settings; - } -+ -+/* Return configuration set in which device exists. */ -+config_t device_get_config(struct device *dev) -+{ -+ config_t config = 0; -+ -+ if (dev->active.exists || dev->active.definable) -+ config |= config_active; -+ -+ if (dev->persistent.exists) -+ config |= config_persistent; -+ -+ if (dev->autoconf.exists) -+ config |= config_autoconf; -+ -+ return config; -+} ---- a/zdev/src/export.c -+++ b/zdev/src/export.c -@@ -83,7 +83,7 @@ static bool is_exportable(struct setting - return true; - } - } -- if (SCOPE_PERSISTENT(config)) { -+ if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) { - if (setting_is_set(s)) - return true; - } -@@ -148,10 +148,9 @@ static int count_exportable(struct devic - struct setting *s; - int count; - -- if (config == config_active) -- list = dev->active.settings; -- else -- list = dev->persistent.settings; -+ list = device_get_setting_list(dev, config); -+ if (!list) -+ return 0; - count = 0; - - util_list_iterate(&list->list, s) { -@@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd - exit_code_t rc; - struct setting_list *settings; - -- if (config == config_all) { -- rc = export_write_device(fd, dev, config_active, first_ptr); -- if (rc) -- return rc; -- return export_write_device(fd, dev, config_persistent, -- first_ptr); -+ if (!SCOPE_SINGLE(config)) { -+ if (SCOPE_ACTIVE(config)) { -+ rc = export_write_device(fd, dev, config_active, -+ first_ptr); -+ if (rc) -+ return rc; -+ } -+ if (SCOPE_PERSISTENT(config)) { -+ rc = export_write_device(fd, dev, config_persistent, -+ first_ptr); -+ if (rc) -+ return rc; -+ } -+ if (SCOPE_AUTOCONF(config)) { -+ rc = export_write_device(fd, dev, config_autoconf, -+ first_ptr); -+ if (rc) -+ return rc; -+ } -+ return EXIT_OK; - } - - if (config == config_active) { -@@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd - !dev->subtype->support_definable) - return EXIT_OK; - settings = dev->active.settings; -- } else { -+ } else if (config == config_persistent) { - if (!dev->persistent.exists) - return EXIT_OK; - settings = dev->persistent.settings; -+ } else { -+ if (!dev->autoconf.exists) -+ return EXIT_OK; -+ settings = dev->autoconf.settings; - } - - write_header(fd, config, dev->subtype->name, dev->id, first_ptr); -@@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *f - exit_code_t rc; - struct setting_list *settings; - -- if (config == config_all) { -- rc = export_write_devtype(fd, dt, config_active, first_ptr); -- if (rc) -- return rc; -- return export_write_devtype(fd, dt, config_persistent, -- first_ptr); -+ if (!SCOPE_SINGLE(config)) { -+ if (SCOPE_ACTIVE(config)) { -+ rc = export_write_devtype(fd, dt, config_active, -+ first_ptr); -+ if (rc) -+ return rc; -+ } -+ if (SCOPE_PERSISTENT(config)) { -+ rc = export_write_devtype(fd, dt, config_persistent, -+ first_ptr); -+ if (rc) -+ return rc; -+ } -+ /* Scope autoconf not supported for devtype */ -+ return EXIT_OK; - } - - if (config == config_active) -@@ -379,6 +405,10 @@ static exit_code_t handle_header(const c - setting_list_clear(dev->persistent.settings); - dev->persistent.exists = 1; - } -+ if (SCOPE_AUTOCONF(hdr->config)) { -+ setting_list_clear(dev->autoconf.settings); -+ dev->autoconf.exists = 1; -+ } - } - - out: -@@ -397,13 +427,26 @@ static exit_code_t handle_setting(const - struct attrib **attribs, *a; - struct setting_list *list; - -- if (config == config_all) { -- rc = handle_setting(filename, lineno, key, value, dt, dev, -- config_active); -- if (rc) -- return rc; -- return handle_setting(filename, lineno, key, value, dt, dev, -- config_persistent); -+ if (!SCOPE_SINGLE(config)) { -+ if (SCOPE_ACTIVE(config)) { -+ rc = handle_setting(filename, lineno, key, value, dt, -+ dev, config_active); -+ if (rc) -+ return rc; -+ } -+ if (SCOPE_PERSISTENT(config)) { -+ rc = handle_setting(filename, lineno, key, value, dt, -+ dev, config_persistent); -+ if (rc) -+ return rc; -+ } -+ if (SCOPE_AUTOCONF(config)) { -+ rc = handle_setting(filename, lineno, key, value, dt, -+ dev, config_autoconf); -+ if (rc) -+ return rc; -+ } -+ return EXIT_OK; - } - - if (dt) { -@@ -452,7 +495,8 @@ static bool empty_device(struct device * - if (dev->subtype->support_definable) - return false; - if (util_list_is_empty(&dev->active.settings->list) && -- util_list_is_empty(&dev->persistent.settings->list)) -+ util_list_is_empty(&dev->persistent.settings->list) && -+ util_list_is_empty(&dev->autoconf.settings->list)) - return true; - return false; - } ---- a/zdev/src/firmware.c -+++ b/zdev/src/firmware.c -@@ -360,6 +360,8 @@ static void add_setting(const char *file - _add_setting(filename, dev, config_active, key, value); - if (SCOPE_PERSISTENT(config)) - _add_setting(filename, dev, config_persistent, key, value); -+ if (SCOPE_AUTOCONF(config)) -+ _add_setting(filename, dev, config_autoconf, key, value); - } - - /* Parse a single device setting in firmware format and apply it to the -@@ -477,6 +479,10 @@ static struct device *add_device(struct - setting_list_clear(dev->persistent.settings); - dev->persistent.exists = 1; - } -+ if (SCOPE_AUTOCONF(config)) { -+ setting_list_clear(dev->autoconf.settings); -+ dev->autoconf.exists = 1; -+ } - - return dev; - } ---- a/zdev/src/lszdev.c -+++ b/zdev/src/lszdev.c -@@ -59,6 +59,7 @@ struct options { - config_t config; - unsigned int active:1; - unsigned int persistent:1; -+ unsigned int auto_conf:1; - struct util_list *columns; /* List of struct strlist_node */ - unsigned int no_headings:1; - struct util_list *base; /* List of struct strlist_node */ -@@ -98,6 +99,7 @@ enum { - OPT_VERBOSE = 'V', - OPT_QUIET = 'q', - OPT_PAIRS = 'P', -+ OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__), - }; - - static struct opts_conflict conflict_list[] = { -@@ -150,6 +152,7 @@ static const struct option opt_list[] = - /* Options. */ - { "active", no_argument, NULL, OPT_ACTIVE }, - { "persistent", no_argument, NULL, OPT_PERSISTENT }, -+ { "auto-conf", no_argument, NULL, OPT_AUTO_CONF }, - { "columns", required_argument, NULL, OPT_COLUMNS }, - { "no-headings", no_argument, NULL, OPT_NO_HEADINGS }, - { "base", required_argument, NULL, OPT_BASE }, -@@ -623,6 +626,11 @@ static exit_code_t parse_options(struct - opts->persistent = 1; - break; - -+ case OPT_AUTO_CONF: -+ /* --auto-conf */ -+ opts->auto_conf = 1; -+ break; -+ - case OPT_COLUMNS: - /* --columns COLUMN */ - strlist_add_multi(opts->columns, optarg, ",", 0); -@@ -685,7 +693,15 @@ static exit_code_t parse_options(struct - goto out; - - /* Determine configuration set. */ -- opts->config = get_config(opts->active, opts->persistent); -+ if (!opts->active && !opts->persistent && !opts->auto_conf) { -+ /* Default display targets are active + persistent - note that -+ * autoconf data is still shown when available to make users -+ * aware of this type of data. */ -+ opts->config = config_active | config_persistent; -+ } else { -+ opts->config = get_config(opts->active, opts->persistent, -+ opts->auto_conf); -+ } - - /* Handle positional parameters. */ - rc = parse_positional(opts, argc, argv, optind); -@@ -725,6 +741,7 @@ enum dev_table_id { - dev_netdevs, - dev_exists, - dev_pers, -+ dev_auto, - dev_online, - dev_failed, - dev_modules, -@@ -744,6 +761,8 @@ static struct column *dev_table = COLUMN - "Device exists in the active configuration"), - COLUMN("PERS", align_left, dev_pers, 1, - "Device is configured persistently"), -+ COLUMN("AUTO", align_left, dev_auto, 0, -+ "Auto-configuration exists for device"), - COLUMN("FAILED", align_left, dev_failed, 0, - "Device is in error"), - COLUMN("NAMES", align_left, dev_names, 1, -@@ -762,21 +781,34 @@ static struct column *dev_table = COLUMN - "Path to specific attribute in active configuration") - ); - --static char *merge_str(const char *act, const char *pers) -+static char *merge_str(const char *act, const char *pers, const char *ac, -+ config_t config) - { - char *str; -+ size_t len; - -- if (act && pers) { -- if (strcmp(act, pers) == 0) -- str = misc_strdup(act); -- else -- str = misc_asprintf("%s/%s", act, pers); -- } else if (act) -- str = misc_strdup(act); -- else if (pers) -- str = misc_strdup(pers); -- else -- str = misc_strdup("-"); -+ act = act ? act : "-"; -+ pers = pers ? pers : "-"; -+ ac = ac ? ac : "-"; -+ -+ if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0) -+ return misc_strdup(act); -+ -+ len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4; -+ str = misc_malloc(len); -+ -+ if (SCOPE_ACTIVE(config)) -+ strcat(str, act); -+ if (SCOPE_PERSISTENT(config)) { -+ if (*str) -+ strcat(str, "/"); -+ strcat(str, pers); -+ } -+ if (SCOPE_AUTOCONF(config)) { -+ if (*str) -+ strcat(str, "/"); -+ strcat(str, ac); -+ } - - return str; - } -@@ -821,10 +853,9 @@ static char *get_attr(struct device *dev - struct setting_list *list; - struct setting *s; - -- if (config == config_active) -- list = dev->active.settings; -- else -- list = dev->persistent.settings; -+ list = device_get_setting_list(dev, config); -+ if (!list) -+ return NULL; - s = setting_list_find(list, name); - if (!s) { - if (config == config_active) { -@@ -841,7 +872,7 @@ static char *get_attr(struct device *dev - static char *dev_table_get_attr(struct device *dev, const char *attr, - config_t config) - { -- char *act = NULL, *pers = NULL, *str; -+ char *act = NULL, *pers = NULL, *ac = NULL, *str; - const char *name; - - name = strchr(attr, ':'); -@@ -853,10 +884,13 @@ static char *dev_table_get_attr(struct d - act = get_attr(dev, name, config_active); - if (SCOPE_PERSISTENT(config)) - pers = get_attr(dev, name, config_persistent); -+ if (SCOPE_AUTOCONF(config)) -+ ac = get_attr(dev, name, config_autoconf); - -- str = merge_str(act, pers); -+ str = merge_str(act, pers, ac, config); - free(act); - free(pers); -+ free(ac); - - return str; - } -@@ -904,7 +938,11 @@ static char *dev_table_get_value(void *i - return misc_strdup(YESNO(dev->active.exists || - dev->active.definable)); - case dev_pers: -+ if (!dev->persistent.exists && dev->autoconf.exists) -+ return misc_strdup("auto"); - return misc_strdup(YESNO(dev->persistent.exists)); -+ case dev_auto: -+ return misc_strdup(YESNO(dev->autoconf.exists)); - case dev_online: - return dev_table_get_online(dev, config_active); - case dev_failed: -@@ -942,6 +980,7 @@ static read_scope_t get_scope(struct opt - case dev_netdevs: - case dev_exists: - case dev_pers: -+ case dev_auto: - case dev_online: - case dev_modules: - continue; -@@ -960,14 +999,21 @@ static struct util_list *dev_table_build - struct util_list *selected, *devices = NULL; - struct selected_dev_node *sel; - struct device *dev; -- int active, persistent; -+ int active, persistent, autoconf; - read_scope_t scope; - exit_code_t rc; -+ config_t config = opts->config; - - scope = get_scope(opts); - selected = selected_dev_list_new(); -+ -+ /* Read auto-config data when no configuration set was specified to -+ * make user aware of auto-config data. */ -+ if (!opts->active && !opts->persistent && !opts->auto_conf) -+ config |= config_autoconf; -+ - rc = select_devices(opts->select, selected, 1, 0, opts->pairs, -- opts->config, scope, err_print); -+ config, scope, err_print); - if (rc) - goto out; - devices = ptrlist_new(); -@@ -987,7 +1033,8 @@ static struct util_list *dev_table_build - /* Only process existing devices. */ - active = dev->active.exists || dev->active.definable; - persistent = dev->persistent.exists; -- if (!active && !persistent) -+ autoconf = dev->autoconf.exists; -+ if (!active && !persistent && !autoconf) - continue; - - ptrlist_add(devices, dev); -@@ -1025,9 +1072,11 @@ static exit_code_t do_list_devices(struc - if (!items) - return EXIT_EMPTY_SELECTION; - -- /* Adjust columns visible depending on --active and --persistent. */ -+ /* Adjust columns visible depending on selected config set. */ - table_set_default(dev_table, dev_online, SCOPE_ACTIVE(opts->config)); - table_set_default(dev_table, dev_pers, SCOPE_PERSISTENT(opts->config)); -+ table_set_default(dev_table, dev_auto, SCOPE_AUTOCONF(opts->config) && -+ !SCOPE_PERSISTENT(opts->config)); - table_set_default(dev_table, dev_names, SCOPE_ACTIVE(opts->config)); - - /* Display table. */ -@@ -1057,17 +1106,20 @@ enum settings_table_id { - settings_readonly, - settings_active, - settings_persistent, -+ settings_autoconf, - }; - - static struct column *settings_table = COLUMN_ARRAY( - COLUMN("ATTRIBUTE", align_left, settings_attribute, 1, ""), - COLUMN("READONLY", align_left, settings_readonly, 1, ""), - COLUMN("ACTIVE", align_left, settings_active, 1, ""), -- COLUMN("PERSISTENT", align_left, settings_persistent, 1, "") -+ COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""), -+ COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "") - ); - - static struct util_list *settings_table_build(struct setting_list *active, - struct setting_list *persistent, -+ struct setting_list *autoconf, - bool readonly) - { - struct util_list *names, *items; -@@ -1088,6 +1140,10 @@ static struct util_list *settings_table_ - util_list_iterate(&persistent->list, s) - strlist_add(names, s->name); - } -+ if (autoconf && !readonly) { -+ util_list_iterate(&autoconf->list, s) -+ strlist_add(names, s->name); -+ } - strlist_sort_unique(names, str_cmp); - - /* Convert strlist to ptrlist. */ -@@ -1102,6 +1158,7 @@ static struct util_list *settings_table_ - struct settings_table_data { - struct setting_list *active; - struct setting_list *persistent; -+ struct setting_list *autoconf; - int pairs; - bool readonly; - }; -@@ -1124,12 +1181,17 @@ static char *settings_table_get_value(vo - case settings_persistent: - list = stdata->persistent; - break; -+ case settings_autoconf: -+ list = stdata->autoconf; -+ break; - default: - break; - } - if (list) { - s = setting_list_find(list, name); -- if (s && !(id == settings_persistent && s->derived)) { -+ if (s && -+ !((id == settings_persistent || id == settings_autoconf) && -+ s->derived)) { - if (stdata->pairs) - return misc_strdup(s->value); - else -@@ -1145,6 +1207,7 @@ static char *settings_table_get_value(vo - - static void settings_table_print(struct setting_list *active, - struct setting_list *persistent, -+ struct setting_list *autoconf, - struct options *opts, int ind, bool readonly, - bool neednl) - { -@@ -1154,7 +1217,7 @@ static void settings_table_print(struct - items = settings_table_build( - SCOPE_ACTIVE(opts->config) ? active : NULL, - SCOPE_PERSISTENT(opts->config) ? persistent : NULL, -- readonly); -+ autoconf, readonly); - if (util_list_is_empty(items)) { - if (!opts->pairs && !readonly) - indent(ind, "%sNo settings found\n", -@@ -1170,8 +1233,12 @@ static void settings_table_print(struct - SCOPE_ACTIVE(opts->config)); - table_set_default(settings_table, settings_persistent, - SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0); -+ table_set_default(settings_table, settings_autoconf, -+ (SCOPE_AUTOCONF(opts->config) || autoconf) && -+ !readonly ? 1 : 0); - data.active = active; - data.persistent = persistent; -+ data.autoconf = autoconf; - data.pairs = opts->pairs; - table_print(settings_table, settings_table_get_value, &data, items, - NULL, 1, opts->pairs, ind, 0); -@@ -1253,7 +1320,7 @@ static exit_code_t do_info_type(struct o - } - } else { - settings_table_print(dt->active_settings, -- dt->persistent_settings, opts, -+ dt->persistent_settings, NULL, opts, - INFO_INDENT, false, false); - } - -@@ -1280,7 +1347,7 @@ static void do_info_one_device(struct de - { - struct subtype *st = dev->subtype; - char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key; -- const char *id, *type, *exists, *persist, *prefix; -+ const char *id, *type, *exists, *persist, *ac, *prefix; - struct util_list *resources, *errors; - struct strlist_node *s; - bool first; -@@ -1299,6 +1366,7 @@ static void do_info_one_device(struct de - errors = subtype_get_errors(dev->subtype, dev->id); - exists = YESNO(dev->active.exists || dev->active.definable); - persist = YESNO(dev->persistent.exists); -+ ac = YESNO(dev->autoconf.exists); - - /* Print information. */ - if (opts->pairs) { -@@ -1316,6 +1384,8 @@ static void do_info_one_device(struct de - print_pair("ONLINE", online); - print_pair("EXISTS", exists); - print_pair("PERSISTENT", persist); -+ if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists) -+ print_pair("AUTOCONF", ac); - if (errors) { - util_list_iterate(errors, s) - print_pair("ERROR", s->str); -@@ -1341,6 +1411,8 @@ static void do_info_one_device(struct de - print_info("Online", online); - print_info("Exists", exists); - print_info("Persistent", persist); -+ if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists) -+ print_info("Auto-configured", ac); - if (errors) { - first = true; - util_list_iterate(errors, s) { -@@ -1382,11 +1454,17 @@ static void do_info_one_device(struct de - - settings_table_print(dev->active.exists ? dev->active.settings : NULL, - dev->persistent.exists ? dev->persistent.settings : -- NULL, opts, INFO_INDENT, false, !opts->pairs); -+ NULL, -+ dev->autoconf.exists ? dev->autoconf.settings : -+ NULL, -+ opts, INFO_INDENT, false, !opts->pairs); - - settings_table_print(dev->active.exists ? dev->active.settings : NULL, - dev->persistent.exists ? dev->persistent.settings : -- NULL, opts, INFO_INDENT, true, !opts->pairs); -+ NULL, -+ dev->autoconf.exists ? dev->autoconf.settings : -+ NULL, -+ opts, INFO_INDENT, true, !opts->pairs); - - strlist_free(errors); - free(online); -@@ -1404,9 +1482,10 @@ static exit_code_t do_info_devices(struc - struct util_list *selected; - struct selected_dev_node *sel; - struct device *dev; -- int found, active, persistent; -+ int found, active, persistent, autoconf; - exit_code_t rc, drc = EXIT_OK; - read_scope_t scope; -+ config_t config = opts->config; - - if (opts->info > 1) - scope = scope_all; -@@ -1415,7 +1494,13 @@ static exit_code_t do_info_devices(struc - - /* Get list of selected devices. */ - selected = selected_dev_list_new(); -- select_devices(opts->select, selected, 1, 0, opts->pairs, opts->config, -+ -+ /* Read auto-config data when no configuration set was specified to -+ * make user aware of auto-config data. */ -+ if (!opts->active && !opts->persistent && !opts->auto_conf) -+ config |= config_autoconf; -+ -+ select_devices(opts->select, selected, 1, 0, opts->pairs, config, - scope, err_print); - - /* Process selected devices. */ -@@ -1434,9 +1519,8 @@ static exit_code_t do_info_devices(struc - /* Only process existing devices. */ - active = dev->active.exists || dev->active.definable; - persistent = dev->persistent.exists; -- if ((opts->config == config_active && !active) || -- (opts->config == config_persistent && !persistent) || -- (opts->config == config_all && !active && !persistent)) -+ autoconf = dev->autoconf.exists; -+ if (!active && !persistent && !autoconf) - continue; - if (found > 0) - printf("\n"); ---- a/zdev/src/lszdev_usage.txt -+++ b/zdev/src/lszdev_usage.txt -@@ -41,5 +41,6 @@ OPTIONS - -n, --no-headings Do not print column headings - --base PATH Use PATH as base for accessing files - --pairs Produce output in KEY="VALUE" format -+ --auto-conf Only show auto-configuration data - -V, --verbose Print additional run-time information - -q, --quiet Print only minimal run-time information ---- a/zdev/src/misc.c -+++ b/zdev/src/misc.c -@@ -1107,14 +1107,18 @@ char *misc_readlink(const char *path) - } - - /* Determine configuration set. */ --config_t get_config(int active, int persistent) -+config_t get_config(int active, int persistent, int autoconf) - { -- if ((!active && !persistent) || (active && persistent)) -- return config_all; -- else if (active) -- return config_active; -- else -- return config_persistent; -+ config_t config = 0; -+ -+ if (active) -+ config |= config_active; -+ if (persistent) -+ config |= config_persistent; -+ if (autoconf) -+ config |= config_autoconf; -+ -+ return config; - } - - /* Determine if program is running under z/VM. */ -@@ -1248,11 +1252,12 @@ const char *config_to_str(config_t confi - return "active"; - case config_persistent: - return "persistent"; -+ case config_autoconf: -+ return "autoconf"; - case config_all: - return "all"; - } -- /* Should not happen. */ -- return ""; -+ return "multiple"; - } - - /* Convert textual config representation to config_t. */ -@@ -1262,6 +1267,8 @@ bool str_to_config(const char *str, conf - *config_ptr = config_active; - else if (strcasecmp(str, "persistent") == 0) - *config_ptr = config_persistent; -+ else if (strcasecmp(str, "autoconf") == 0) -+ *config_ptr = config_autoconf; - else if (strcasecmp(str, "all") == 0) - *config_ptr = config_all; - else ---- a/zdev/src/path.c -+++ b/zdev/src/path.c -@@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const ch - } - - /* Return path to udev rule. */ --char *path_get_udev_rule(const char *type, const char *id) -+char *path_get_udev_rule(const char *type, const char *id, bool vol) - { -+ const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES; -+ - if (id) { -- return path_get("%s/%s-%s-%s%s", PATH_UDEV_RULES, -+ return path_get("%s/%s-%s-%s%s", path, - UDEV_PREFIX, type, id, UDEV_SUFFIX); - } - -- return path_get("%s/%s-%s%s", PATH_UDEV_RULES, -+ return path_get("%s/%s-%s%s", path, - UDEV_PREFIX, type, UDEV_SUFFIX); - } - - /* Return path to directory containing all udev rules. */ --char *path_get_udev_rules(void) -+char *path_get_udev_rules(bool vol) - { -- return path_get("%s", PATH_UDEV_RULES); -+ const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES; -+ -+ return path_get("%s", path); - } - - /* Return path to the specified file in the proc file system. */ ---- a/zdev/src/qeth.c -+++ b/zdev/src/qeth.c -@@ -1207,7 +1207,7 @@ static exit_code_t check_layer2(struct d - { - struct setting *l; - int layer2_detected, layer2_active = -1, layer2_persistent = -1, -- layer2_modified = 0; -+ layer2_autoconf = -1, layer2_modified = 0; - exit_code_t rc = EXIT_OK; - - layer2_detected = detect_layer2(dev); -@@ -1231,13 +1231,25 @@ static exit_code_t check_layer2(struct d - if (rc) - goto out; - } -+ l = setting_list_find(dev->autoconf.settings, qeth_attr_layer2.name); -+ if (l) { -+ layer2_autoconf = atoi(l->value); -+ layer2_modified |= l->modified; -+ } else if (SCOPE_AUTOCONF(config)) { -+ rc = generate_layer2("autoconf", dev->autoconf.settings, -+ &layer2_autoconf, &layer2_modified); -+ if (rc) -+ goto out; -+ } - - /* Check correct layer2 setting. */ - if (layer2_detected != -1) { - if ((SCOPE_ACTIVE(config) && layer2_active != -1 && - layer2_active != layer2_detected) || - (SCOPE_PERSISTENT(config) && layer2_persistent != -1 && -- layer2_persistent != layer2_detected)) { -+ layer2_persistent != layer2_detected) || -+ (SCOPE_AUTOCONF(config) && layer2_autoconf != -1 && -+ layer2_autoconf != layer2_detected)) { - rc = layer2_mismatch(layer2_detected, layer2_modified); - if (rc) - goto out; -@@ -1256,14 +1268,25 @@ static exit_code_t check_layer2(struct d - if (rc) - goto out; - } -+ if (SCOPE_AUTOCONF(config)) { -+ rc = check_ineffective_settings(dev->autoconf.settings, -+ layer2_autoconf); -+ if (rc) -+ goto out; -+ } - /* check for conflicting layer2 attribute groups */ - if (SCOPE_ACTIVE(config)) { - rc = check_conflicting_settings(dev->active.settings); - if (rc) - goto out; - } -- if (SCOPE_PERSISTENT(config)) -+ if (SCOPE_PERSISTENT(config)) { - rc = check_conflicting_settings(dev->persistent.settings); -+ if (rc) -+ goto out; -+ } -+ if (SCOPE_AUTOCONF(config)) -+ rc = check_conflicting_settings(dev->autoconf.settings); - - out: - return rc; -@@ -1277,7 +1300,8 @@ static exit_code_t qeth_st_check_pre_con - - /* No need to check if device is deconfigured. */ - if ((SCOPE_ACTIVE(config) && dev->active.deconfigured) || -- (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured)) -+ (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured) || -+ (SCOPE_AUTOCONF(config) && dev->autoconf.deconfigured)) - return EXIT_OK; - - rc = check_layer2(dev, config); ---- a/zdev/src/select.c -+++ b/zdev/src/select.c -@@ -248,12 +248,13 @@ static void unblacklist_devices(struct s - bool select_match_state(struct device *dev, struct select_opts *select) - { - struct subtype *st = dev->subtype; -- int exists, configured, online; -+ int exists, configured, autoconf, online; - struct util_list *errors; - - exists = dev->active.exists || dev->active.definable; - configured = dev->persistent.exists; -- if (select->all && !(exists || configured)) -+ autoconf = dev->autoconf.exists; -+ if (select->all && !(exists || configured || autoconf)) - return false; - if (select->existing && !exists) - return false; -@@ -862,7 +863,8 @@ static exit_code_t select_nocreate(struc - select->offline || select->online || - SCOPE_ACTIVE(config), - select->configured || select->all || -- SCOPE_PERSISTENT(config)); -+ SCOPE_PERSISTENT(config), -+ select->all || SCOPE_AUTOCONF(config)); - - longrun_total = 0; - if (quiet) -@@ -870,7 +872,7 @@ static exit_code_t select_nocreate(struc - - /* Count devices. */ - verb("Scanning for devices in %s configuration%s:\n", -- config_to_str(id_config), id_config == config_all ? "s" : ""); -+ config_to_str(id_config), !SCOPE_SINGLE(id_config) ? "s" : ""); - for (i = 0; (dt = devtypes[i]); i++) { - if (select->devtype && dt != select->devtype) - continue; -@@ -1128,6 +1130,13 @@ static exit_code_t by_attr_cb(struct sub - - /* Check for attribute value in persistent configuration. */ - s = setting_list_find(dev->persistent.settings, cb_data->key); -+ if (s) { -+ match = setting_match_value(s, cb_data->value); -+ if (match) -+ goto out; -+ } -+ /* Check for attribute value in autoconf configuration. */ -+ s = setting_list_find(dev->autoconf.settings, cb_data->key); - if (s) - match = setting_match_value(s, cb_data->value); - ---- a/zdev/src/setting.c -+++ b/zdev/src/setting.c -@@ -646,7 +646,8 @@ static void add_changes(struct util_list - - /* Return a newly allocated string containing the setting changes found - * in PERS and ACT or NULL if no change was found. */ --char *setting_get_changes(struct setting_list *act, struct setting_list *pers) -+char *setting_get_changes(struct setting_list *act, struct setting_list *pers, -+ struct setting_list *ac) - { - struct util_list *out; - struct util_list *processed; -@@ -662,6 +663,17 @@ char *setting_get_changes(struct setting - if (s->removed) - strlist_add(out, "-%s", s->name); - else if (s->modified) -+ add_changes(out, s); -+ else -+ continue; -+ strlist_add(processed, s->name); -+ } -+ } -+ if (ac) { -+ util_list_iterate(&ac->list, s) { -+ if (s->removed) -+ strlist_add(out, "-%s", s->name); -+ else if (s->modified) - add_changes(out, s); - else - continue; ---- a/zdev/src/subtype.c -+++ b/zdev/src/subtype.c -@@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(st - return super->exists_persistent(st, id); - } - -+bool subtype_device_exists_autoconf(struct subtype *st, const char *id) -+{ -+ struct subtype *super = super_get(st, exists_autoconf, 1); -+ -+ return super->exists_autoconf(st, id); -+} -+ - void subtype_add_active_ids(struct subtype *st, struct util_list *ids) - { - struct subtype *super = super_get(st, add_active_ids, 1); -@@ -209,6 +216,13 @@ void subtype_add_persistent_ids(struct s - super->add_persistent_ids(st, ids); - } - -+void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids) -+{ -+ struct subtype *super = super_get(st, add_autoconf_ids, 1); -+ -+ super->add_autoconf_ids(st, ids); -+} -+ - exit_code_t subtype_device_read_active(struct subtype *st, struct device *dev, - read_scope_t scope) - { -@@ -226,6 +240,15 @@ exit_code_t subtype_device_read_persiste - return super->read_persistent(st, dev, scope); - } - -+exit_code_t subtype_device_read_autoconf(struct subtype *st, -+ struct device *dev, -+ read_scope_t scope) -+{ -+ struct subtype *super = super_get(st, read_autoconf, 1); -+ -+ return super->read_autoconf(st, dev, scope); -+} -+ - exit_code_t subtype_device_configure_active(struct subtype *st, - struct device *dev) - { -@@ -242,6 +265,14 @@ exit_code_t subtype_device_configure_per - return super->configure_persistent(st, dev); - } - -+exit_code_t subtype_device_configure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ struct subtype *super = super_get(st, configure_autoconf, 1); -+ -+ return super->configure_autoconf(st, dev); -+} -+ - exit_code_t subtype_device_deconfigure_active(struct subtype *st, - struct device *dev) - { -@@ -258,6 +289,14 @@ exit_code_t subtype_device_deconfigure_p - return super->deconfigure_persistent(st, dev); - } - -+exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ struct subtype *super = super_get(st, deconfigure_autoconf, 1); -+ -+ return super->deconfigure_autoconf(st, dev); -+} -+ - exit_code_t subtype_check_pre_configure(struct subtype *st, struct device *dev, - int prereq, config_t config) - { -@@ -299,7 +338,7 @@ void subtype_online_set(struct subtype * - int subtype_online_get(struct subtype *st, struct device *dev, config_t config) - { - struct subtype *super = super_get(st, online_get, 0); -- int act_online = 1, pers_online = 1; -+ int act_online = 1, pers_online = 1, auto_online = 1; - - if (super) - return super->online_get(st, dev, config); -@@ -310,8 +349,10 @@ int subtype_online_get(struct subtype *s - act_online = dev->active.exists; - if (SCOPE_PERSISTENT(config)) - pers_online = dev->persistent.exists; -+ if (SCOPE_AUTOCONF(config)) -+ auto_online = dev->autoconf.exists; - -- return MIN(act_online, pers_online); -+ return MIN(MIN(act_online, pers_online), auto_online); - } - - bool subtype_online_specified(struct subtype *st, struct device *dev, -@@ -495,6 +536,10 @@ bool subtype_device_exists(struct subtyp - if (!subtype_device_exists_persistent(st, id)) - return false; - } -+ if (SCOPE_AUTOCONF(config)) { -+ if (!subtype_device_exists_autoconf(st, id)) -+ return false; -+ } - - return true; - } -@@ -512,6 +557,8 @@ static struct util_list *get_ids(struct - } - if (SCOPE_PERSISTENT(config)) - subtype_add_persistent_ids(st, ids); -+ if (SCOPE_AUTOCONF(config)) -+ subtype_add_autoconf_ids(st, ids); - - /* Provide a sorted view. */ - strlist_sort_unique(ids, st->namespace->qsort_cmp); -@@ -683,6 +730,19 @@ static exit_code_t read_device(struct su - goto out; - } - -+ if (SCOPE_AUTOCONF(config)) { -+ if (subtype_device_exists_autoconf(st, id)) -+ rc = subtype_device_read_autoconf(st, dev, scope); -+ else if (defined) { -+ /* Need to copy detected settings to autoconf -+ * config. */ -+ setting_list_merge(dev->autoconf.settings, -+ dev->active.settings, false, false); -+ } -+ if (rc) -+ goto out; -+ } -+ - if (add) - device_list_add(st->devices, dev); - -@@ -756,6 +816,25 @@ exit_code_t subtype_write_device(struct - if (!rc) - namespace_set_modified(dev->subtype->namespace); - } -+ if (SCOPE_AUTOCONF(config)) { -+ if (dev->autoconf.deconfigured) { -+ /* Deconfigure device. */ -+ if (dev->autoconf.exists) { -+ rc = subtype_device_deconfigure_autoconf(st, -+ dev); -+ if (rc) -+ return rc; -+ } -+ } else if (dev->autoconf.exists) { -+ /* Configure device. */ -+ rc = subtype_device_configure_autoconf(st, dev); -+ if (rc) -+ return rc; -+ } -+ if (!rc) -+ namespace_set_modified(dev->subtype->namespace); -+ } -+ - - return EXIT_OK; - } ---- a/zdev/src/udev.c -+++ b/zdev/src/udev.c -@@ -360,7 +360,8 @@ static bool get_ids_cb(const char *filen - - /* Add the IDs for all devices of the specified subtype name for which a - * udev rule exists to strlist LIST. */ --void udev_get_device_ids(const char *type, struct util_list *list) -+void udev_get_device_ids(const char *type, struct util_list *list, -+ bool autoconf) - { - char *path, *prefix; - struct util_list *files; -@@ -369,7 +370,7 @@ void udev_get_device_ids(const char *typ - - prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type); - plen = strlen(prefix); -- path = path_get_udev_rules(); -+ path = path_get_udev_rules(autoconf); - files = strlist_new(); - if (!misc_read_dir(path, files, get_ids_cb, prefix)) - goto out; -@@ -388,12 +389,12 @@ out: - } - - /* Remove UDEV rule for device. */ --exit_code_t udev_remove_rule(const char *type, const char *id) -+exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf) - { - char *path; - exit_code_t rc = EXIT_OK; - -- path = path_get_udev_rule(type, id); -+ path = path_get_udev_rule(type, id, autoconf); - if (util_path_is_reg_file(path)) - rc = remove_file(path); - free(path); ---- a/zdev/src/udev_ccw.c -+++ b/zdev/src/udev_ccw.c -@@ -25,7 +25,7 @@ - #include "udev_ccw.h" - - /* Check if a udev rule for the specified ccw device exists. */ --bool udev_ccw_exists(const char *type, const char *id) -+bool udev_ccw_exists(const char *type, const char *id, bool autoconf) - { - char *path, *normid; - bool rc; -@@ -34,7 +34,7 @@ bool udev_ccw_exists(const char *type, c - if (!normid) - return false; - -- path = path_get_udev_rule(type, normid); -+ path = path_get_udev_rule(type, normid, autoconf); - rc = util_path_is_reg_file(path); - free(path); - free(normid); -@@ -88,15 +88,16 @@ static void udev_file_get_settings(struc - } - - /* Read the persistent configuration of a CCW device from a udev rule. */ --exit_code_t udev_ccw_read_device(struct device *dev) -+exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf) - { - struct subtype *st = dev->subtype; -- struct device_state *state = &dev->persistent; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - struct udev_file *file = NULL; - exit_code_t rc; - char *path; - -- path = path_get_udev_rule(st->name, dev->id); -+ path = path_get_udev_rule(st->name, dev->id, autoconf); - rc = udev_read_file(path, &file); - if (rc) - goto out; -@@ -128,12 +129,13 @@ static char *get_label_id(const char *pr - } - - /* Write the persistent configuration of a CCW device to a udev rule. */ --exit_code_t udev_ccw_write_device(struct device *dev) -+exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf) - { - struct subtype *st = dev->subtype; - struct ccw_subtype_data *data = st->data; - const char *type = st->name, *drv = data->ccwdrv, *id = dev->id; -- struct device_state *state = &dev->persistent; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - char *path, *cfg_label = NULL, *end_label = NULL; - struct util_list *list; - struct ptrlist_node *p; -@@ -142,7 +144,7 @@ exit_code_t udev_ccw_write_device(struct - FILE *fd; - - if (!state->exists) -- return udev_remove_rule(type, id); -+ return udev_remove_rule(type, id, autoconf); - - cfg_label = get_label_id("cfg", type, id); - end_label = get_label_id("end", type, id); -@@ -150,7 +152,7 @@ exit_code_t udev_ccw_write_device(struct - /* Apply attributes in correct order. */ - list = setting_list_get_sorted(state->settings); - -- path = path_get_udev_rule(type, id); -+ path = path_get_udev_rule(type, id, autoconf); - debug("Writing %s udev rule file %s\n", type, path); - if (!util_path_exists(path)) { - rc = path_create(path); -@@ -234,14 +236,18 @@ out: - } - - /* Write a udev rule to free devices from the cio-ignore blacklist. */ --exit_code_t udev_ccw_write_cio_ignore(const char *id_list) -+exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf) - { -- char *path, *curr = NULL; -+ char *path, *prefix, *curr = NULL; - FILE *fd; - exit_code_t rc = EXIT_OK; - -+ /* Ensure that autoconf version of cio-ignore is not masked -+ * by normal one. */ -+ prefix = autoconf ? "cio-ignore-autoconf" : "cio-ignore"; -+ - /* Create file. */ -- path = path_get_udev_rule("cio-ignore", NULL); -+ path = path_get_udev_rule(prefix, NULL, autoconf); - - if (!*id_list) { - /* Empty id_list string - remove file. */ ---- a/zdev/src/udev_ccwgroup.c -+++ b/zdev/src/udev_ccwgroup.c -@@ -25,34 +25,34 @@ - #include "udev_ccwgroup.h" - - static char *get_rule_path_by_devid(const char *type, -- struct ccwgroup_devid *devid) -+ struct ccwgroup_devid *devid, bool autoconf) - { - char *ccw_id, *path; - - ccw_id = ccw_devid_to_str(&devid->devid[0]); -- path = path_get_udev_rule(type, ccw_id); -+ path = path_get_udev_rule(type, ccw_id, autoconf); - free(ccw_id); - - return path; - } - --static char *get_rule_path(const char *type, const char *id) -+static char *get_rule_path(const char *type, const char *id, bool autoconf) - { - struct ccwgroup_devid devid; - - if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK) - return NULL; - -- return get_rule_path_by_devid(type, &devid); -+ return get_rule_path_by_devid(type, &devid, autoconf); - } - - /* Check if a udev rule for the specified CCWGROUP device exists. */ --bool udev_ccwgroup_exists(const char *type, const char *id) -+bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf) - { - char *path; - bool rc; - -- path = get_rule_path(type, id); -+ path = get_rule_path(type, id, autoconf); - if (!path) - return false; - rc = util_path_is_reg_file(path); -@@ -143,15 +143,16 @@ static void expand_id(struct device *dev - } - - /* Read the persistent configuration of a CCWGROUP device from a udev rule. */ --exit_code_t udev_ccwgroup_read_device(struct device *dev) -+exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf) - { - struct subtype *st = dev->subtype; -- struct device_state *state = &dev->persistent; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - struct udev_file *file = NULL; - exit_code_t rc; - char *path; - -- path = get_rule_path_by_devid(st->name, dev->devid); -+ path = get_rule_path_by_devid(st->name, dev->devid, autoconf); - rc = udev_read_file(path, &file); - if (rc) - goto out; -@@ -184,9 +185,11 @@ static char *get_label_id(const char *pr - } - - /* Write the persistent configuration of a CCWGROUP device to a udev rule. */ --exit_code_t udev_ccwgroup_write_device(struct device *dev) -+exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf) - { - struct subtype *st = dev->subtype; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - struct ccwgroup_subtype_data *data = st->data; - const char *type = st->name, *drv = data->ccwgroupdrv, *id = dev->id; - struct ccwgroup_devid devid; -@@ -200,21 +203,21 @@ exit_code_t udev_ccwgroup_write_device(s - FILE *fd; - unsigned int i; - -- if (!dev->persistent.exists) -- return udev_ccwgroup_remove_rule(type, id); -+ if (!state->exists) -+ return udev_ccwgroup_remove_rule(type, id, autoconf); - - if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK) - return EXIT_INVALID_ID; - - ccw_id = ccw_devid_to_str(&devid.devid[0]); -- path = get_rule_path(type, ccw_id); -+ path = get_rule_path(type, ccw_id, autoconf); - - group_label = get_label_id("group", type, ccw_id); - cfg_label = get_label_id("cfg", type, ccw_id); - end_label = get_label_id("end", type, ccw_id); - - /* Apply attributes in correct order. */ -- list = setting_list_get_sorted(dev->persistent.settings); -+ list = setting_list_get_sorted(state->settings); - - debug("Writing %s udev rule file %s\n", type, path); - if (!util_path_exists(path)) { -@@ -357,12 +360,13 @@ static exit_code_t get_ids_cb(const char - - /* Add the IDs for all devices of the specified subtype name for which a - * udev rule exists to strlist LIST. */ --void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list) -+void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list, -+ bool autoconf) - { - struct get_ids_cb_data cb_data; - char *path; - -- path = path_get_udev_rules(); -+ path = path_get_udev_rules(autoconf); - cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type); - cb_data.ids = list; - -@@ -374,7 +378,8 @@ void udev_ccwgroup_add_device_ids(const - } - - /* Remove UDEV rule for CCWGROUP device. */ --exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id) -+exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id, -+ bool autoconf) - { - char *partial_id, *path; - exit_code_t rc = EXIT_OK; -@@ -383,7 +388,7 @@ exit_code_t udev_ccwgroup_remove_rule(co - if (!partial_id) - return EXIT_INVALID_ID; - -- path = path_get_udev_rule(type, partial_id); -+ path = path_get_udev_rule(type, partial_id, autoconf); - if (util_path_is_reg_file(path)) - rc = remove_file(path); - free(path); ---- a/zdev/src/udev_zfcp_lun.c -+++ b/zdev/src/udev_zfcp_lun.c -@@ -369,14 +369,14 @@ static exit_code_t lun_cb(const char *pa - - /* Add the IDs for all zfcp lun devices for which a configuration exists to - * LIST. */ --void udev_zfcp_lun_add_device_ids(struct util_list *list) -+void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf) - { - struct lun_cb_data cb_data; - char *path; - - cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, ZFCP_LUN_NAME); - cb_data.list = list; -- path = path_get_udev_rules(); -+ path = path_get_udev_rules(autoconf); - - if (util_path_is_dir(path)) - path_for_each(path, lun_cb, &cb_data); -@@ -387,7 +387,7 @@ void udev_zfcp_lun_add_device_ids(struct - - /* Return path to zfcp lun udev rule file containing configuration data for - * all LUNs of a zfcp device. */ --static char *get_zfcp_lun_path(const char *id) -+static char *get_zfcp_lun_path(const char *id, bool autoconf) - { - char *copy, *e, *path; - -@@ -395,7 +395,7 @@ static char *get_zfcp_lun_path(const cha - e = strchr(copy, ':'); - if (e) - *e = 0; -- path = path_get_udev_rule(ZFCP_LUN_NAME, copy); -+ path = path_get_udev_rule(ZFCP_LUN_NAME, copy, autoconf); - free(copy); - - return path; -@@ -403,9 +403,9 @@ static char *get_zfcp_lun_path(const cha - - /* Return path to zfcp lun udev rule file containing configuration data for - * a single LUN. */ --static char *get_single_zfcp_lun_path(const char *id) -+static char *get_single_zfcp_lun_path(const char *id, bool autoconf) - { -- return path_get_udev_rule(ZFCP_LUN_NAME, id); -+ return path_get_udev_rule(ZFCP_LUN_NAME, id, autoconf); - } - - /* Apply the settings found in NODE to STATE. */ -@@ -437,20 +437,21 @@ static void zfcp_lun_node_to_state(struc - } - - /* Read the persistent configuration of a zfcp lun from a udev rule. */ --exit_code_t udev_zfcp_lun_read_device(struct device *dev) -+exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf) - { - struct subtype *st = dev->subtype; -- struct device_state *state = &dev->persistent; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - struct util_list *luns; - struct zfcp_lun_node *node; - exit_code_t rc = EXIT_OK; - char *path; - - /* Check for single lun file first then try multi lun file. */ -- path = get_single_zfcp_lun_path(dev->id); -+ path = get_single_zfcp_lun_path(dev->id, autoconf); - if (!util_path_exists(path)) { - free(path); -- path = get_zfcp_lun_path(dev->id); -+ path = get_zfcp_lun_path(dev->id, autoconf); - } - - /* Get previous rule data. */ -@@ -616,7 +617,7 @@ out: - * applies the corresponding parameters. If @single is set, update a single - * lun rule file, otherwise update a multi lun rule file. */ - static exit_code_t update_lun_rule(const char *id, struct device_state *state, -- bool single) -+ bool single, bool autoconf) - { - struct zfcp_lun_devid devid; - struct util_list *luns; -@@ -628,7 +629,8 @@ static exit_code_t update_lun_rule(const - rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print); - if (rc) - return rc; -- path = single ? get_single_zfcp_lun_path(id) : get_zfcp_lun_path(id); -+ path = single ? get_single_zfcp_lun_path(id, autoconf) : -+ get_zfcp_lun_path(id, autoconf); - - /* Get previous rule data. */ - luns = zfcp_lun_node_list_new(); -@@ -664,26 +666,28 @@ static exit_code_t update_lun_rule(const - - /* Write a udev-rule to configure the specified zfcp lun and associated - * device state. */ --exit_code_t udev_zfcp_lun_write_device(struct device *dev) -+exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf) - { - exit_code_t rc; -+ struct device_state *state = autoconf ? &dev->autoconf : -+ &dev->persistent; - -- rc = update_lun_rule(dev->id, &dev->persistent, true); -+ rc = update_lun_rule(dev->id, state, true, autoconf); - - /* We only want single lun rule files so remove any remaining - * references in multi lun rule files. */ -- update_lun_rule(dev->id, NULL, false); -+ update_lun_rule(dev->id, NULL, false, autoconf); - - return rc; - } - - /* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */ --exit_code_t udev_zfcp_lun_remove_rule(const char *id) -+exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf) - { - exit_code_t rc, rc2; - -- rc = update_lun_rule(id, NULL, true); -- rc2 = update_lun_rule(id, NULL, false); -+ rc = update_lun_rule(id, NULL, true, autoconf); -+ rc2 = update_lun_rule(id, NULL, false, autoconf); - - if (rc) - return rc; -@@ -692,7 +696,7 @@ exit_code_t udev_zfcp_lun_remove_rule(co - } - - /* Determine if a udev rule exists for configuring the specified zfcp lun. */ --bool udev_zfcp_lun_exists(const char *id) -+bool udev_zfcp_lun_exists(const char *id, bool autoconf) - { - struct zfcp_lun_devid devid; - char *path, *rule = NULL, *pattern = NULL; -@@ -702,7 +706,7 @@ bool udev_zfcp_lun_exists(const char *id - return false; - - /* Check for single lun rule file first. */ -- path = get_single_zfcp_lun_path(id); -+ path = get_single_zfcp_lun_path(id, autoconf); - if (util_path_exists(path)) { - rc = true; - goto out; -@@ -710,7 +714,7 @@ bool udev_zfcp_lun_exists(const char *id - free(path); - - /* Check multi lun rule file next. */ -- path = get_zfcp_lun_path(id); -+ path = get_zfcp_lun_path(id, autoconf); - rule = misc_read_text_file(path, 1, err_ignore); - if (!rule) - goto out; ---- a/zdev/src/zfcp_lun.c -+++ b/zdev/src/zfcp_lun.c -@@ -467,7 +467,14 @@ static exit_code_t zfcp_lun_st_read_pers - struct device *dev, - read_scope_t scope) - { -- return udev_zfcp_lun_read_device(dev); -+ return udev_zfcp_lun_read_device(dev, false); -+} -+ -+static exit_code_t zfcp_lun_st_read_autoconf(struct subtype *st, -+ struct device *dev, -+ read_scope_t scope) -+{ -+ return udev_zfcp_lun_read_device(dev, true); - } - - static exit_code_t zfcp_lun_add(struct device *dev) -@@ -564,7 +571,13 @@ static exit_code_t zfcp_lun_st_configure - static exit_code_t zfcp_lun_st_configure_persistent(struct subtype *st, - struct device *dev) - { -- return udev_zfcp_lun_write_device(dev); -+ return udev_zfcp_lun_write_device(dev, false); -+} -+ -+static exit_code_t zfcp_lun_st_configure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return udev_zfcp_lun_write_device(dev, true); - } - - static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st, -@@ -578,7 +591,13 @@ static exit_code_t zfcp_lun_st_deconfigu - static exit_code_t zfcp_lun_st_deconfigure_persistent(struct subtype *st, - struct device *dev) - { -- return udev_zfcp_lun_remove_rule(dev->id); -+ return udev_zfcp_lun_remove_rule(dev->id, false); -+} -+ -+static exit_code_t zfcp_lun_st_deconfigure_autoconf(struct subtype *st, -+ struct device *dev) -+{ -+ return udev_zfcp_lun_remove_rule(dev->id, true); - } - - static exit_code_t check_npiv(struct subtype *st, struct device *dev, -@@ -606,7 +625,8 @@ static exit_code_t check_npiv(struct sub - if (!allow_lun_scan) - goto out; - -- if (!(dev->active.deconfigured || dev->persistent.deconfigured)) { -+ if (!(dev->active.deconfigured || dev->persistent.deconfigured || -+ dev->autoconf.deconfigured)) { - delayed_info("Note: Auto LUN scan enabled - manual LUN " - "configuration is redundant for %s %s\n", - zfcp_host_subtype.devname, fcp_dev_id); -@@ -643,7 +663,8 @@ static exit_code_t zfcp_lun_st_check_pos - - /* Don't show note when an attribute was modified. */ - if (setting_list_modified(dev->active.settings) || -- setting_list_modified(dev->persistent.settings)) -+ setting_list_modified(dev->persistent.settings) || -+ setting_list_modified(dev->autoconf.settings)) - return EXIT_OK; - - /* Check for NPIV but don't route exit code to caller - we only -@@ -795,7 +816,12 @@ static bool zfcp_lun_st_exists_active(st - - static bool zfcp_lun_st_exists_persistent(struct subtype *st, const char *id) - { -- return udev_zfcp_lun_exists(id); -+ return udev_zfcp_lun_exists(id, false); -+} -+ -+static bool zfcp_lun_st_exists_autoconf(struct subtype *st, const char *id) -+{ -+ return udev_zfcp_lun_exists(id, true); - } - - static exit_code_t zfcp_lun_st_is_definable(struct subtype *st, const char *id, -@@ -889,7 +915,13 @@ static void zfcp_lun_st_add_active_ids(s - static void zfcp_lun_st_add_persistent_ids(struct subtype *st, - struct util_list *ids) - { -- udev_zfcp_lun_add_device_ids(ids); -+ udev_zfcp_lun_add_device_ids(ids, false); -+} -+ -+static void zfcp_lun_st_add_autoconf_ids(struct subtype *st, -+ struct util_list *ids) -+{ -+ udev_zfcp_lun_add_device_ids(ids, true); - } - - static exit_code_t add_sg_cb(const char *path, const char *filename, void *data) -@@ -1072,18 +1104,23 @@ struct subtype zfcp_lun_subtype = { - - .exists_active = &zfcp_lun_st_exists_active, - .exists_persistent = &zfcp_lun_st_exists_persistent, -+ .exists_autoconf = &zfcp_lun_st_exists_autoconf, - - .add_active_ids = &zfcp_lun_st_add_active_ids, - .add_persistent_ids = &zfcp_lun_st_add_persistent_ids, -+ .add_autoconf_ids = &zfcp_lun_st_add_autoconf_ids, - - .read_active = &zfcp_lun_st_read_active, - .read_persistent = &zfcp_lun_st_read_persistent, -+ .read_autoconf = &zfcp_lun_st_read_autoconf, - - .configure_active = &zfcp_lun_st_configure_active, - .configure_persistent = &zfcp_lun_st_configure_persistent, -+ .configure_autoconf = &zfcp_lun_st_configure_autoconf, - - .deconfigure_active = &zfcp_lun_st_deconfigure_active, - .deconfigure_persistent = &zfcp_lun_st_deconfigure_persistent, -+ .deconfigure_autoconf = &zfcp_lun_st_deconfigure_autoconf, - - .check_pre_configure = &zfcp_lun_st_check_pre_configure, - .check_post_configure = &zfcp_lun_st_check_post_configure, diff --git a/s390-tools-sles15sp1-06-zpcictl-Rephrase-man-page-entries-and-tool-output.patch b/s390-tools-sles15sp1-06-zpcictl-Rephrase-man-page-entries-and-tool-output.patch deleted file mode 100644 index b355098..0000000 --- a/s390-tools-sles15sp1-06-zpcictl-Rephrase-man-page-entries-and-tool-output.patch +++ /dev/null @@ -1,91 +0,0 @@ -Subject: zpcictl: Rephrase man page entries and tool output -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: d03be735366de57be0c642f6f21b06b1f2df6a6e -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Rephrase man page entries and tool output - - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.8 | 13 ++++++++----- - zpcictl/zpcictl.c | 9 +++++---- - 2 files changed, 13 insertions(+), 9 deletions(-) - ---- a/zpcictl/zpcictl.8 -+++ b/zpcictl/zpcictl.8 -@@ -1,4 +1,4 @@ --.\" Copyright 2017 IBM Corp. -+.\" Copyright IBM Corp. 2018 - .\" s390-tools is free software; you can redistribute it and/or modify - .\" it under the terms of the MIT license. See LICENSE for details. - .\" -@@ -30,9 +30,10 @@ zpcictl - Manage PCI devices on z System - . - . - .SH DESCRIPTION -+With - .B zpcictl --is a tool for managing PCI devices on the IBM z Systems platform. It is --especially used for reporting errorneous PCI devices to the service element. -+, you can manage PCI devices on the IBM z Systems platform. It is especially -+used for reporting erroneous PCI devices to the service element. - - .B Note: - For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent -@@ -44,7 +45,9 @@ for this to work. - .SH DEVICE - .B DEVICE - can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node --of an NVMe device (e.g. /dev/nvme0). -+of an NVMe device (e.g. -+.I /dev/nvme0 -+). - . - . - .SH OPTIONS -@@ -52,7 +55,7 @@ of an NVMe device (e.g. /dev/nvme0). - .OD reset "" "DEVICE" - Reset - .I DEVICE --and initiate a re-initialisation of the adapter. -+and initiate a re-initialization of the PCI device. - .PP - . - .OD deconfigure "" "DEVICE" ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -240,7 +240,7 @@ static int device_exists(char *dev) - static void get_device_info(struct zpci_device *pdev, char *dev) - { - if (!device_exists(dev)) -- errx(EXIT_FAILURE, "Device %s not found", dev); -+ errx(EXIT_FAILURE, "Could not find device %s", dev); - if (is_blk_dev(dev)) - errx(EXIT_FAILURE, "Unsupported device type %s", dev); - if (is_char_dev(dev)) { -@@ -254,9 +254,10 @@ static void get_device_info(struct zpci_ - pdev->fid = sysfs_read_value(pdev, "function_id"); - pdev->pchid = sysfs_read_value(pdev, "pchid"); - -- /* In case a slot address was specified, we still need to figure out -- * the device node for NVMe devices. Otherwise we won't be able to -- * collect S.M.A.R.T. data at a later point. -+ /* -+ * In case a slot address was specified, the device node for NVMe -+ * devices is still needed. Otherwise it won't be possible to collect -+ * S.M.A.R.T. data at a later point. - */ - if (!pdev->device && pdev->class == PCI_CLASS_NVME) - get_device_node(pdev); diff --git a/s390-tools-sles15sp1-07-cpumf-Add-IBM-z14-ZR1-to-the-CPU-Measurement-Facilit.patch b/s390-tools-sles15sp1-07-cpumf-Add-IBM-z14-ZR1-to-the-CPU-Measurement-Facilit.patch deleted file mode 100644 index 6a1d761..0000000 --- a/s390-tools-sles15sp1-07-cpumf-Add-IBM-z14-ZR1-to-the-CPU-Measurement-Facilit.patch +++ /dev/null @@ -1,41 +0,0 @@ -Subject: cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list -From: Hendrik Brueckner - -Summary: cpumf: Add CPU-MF hardware counters for z14 -Description: Add hardware counter definitions for IBM z14. -Upstream-ID: f642019bcc17370231666e772c7e4cec19f1dfdc -Problem-ID: KRN1608 - -Upstream-Description: - - cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list - - Signed-off-by: Thomas Richter - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Hendrik Brueckner ---- - cpumf/bin/cpumf_helper.in | 1 + - cpumf/data/cpum-cf-hw-counter.map | 1 + - 2 files changed, 2 insertions(+) - ---- a/cpumf/bin/cpumf_helper.in -+++ b/cpumf/bin/cpumf_helper.in -@@ -211,6 +211,7 @@ my $system_z_hwtype_map = { - 2964 => 'IBM z13', - 2965 => 'IBM z13s', - 3906 => 'IBM z14', -+ 3907 => 'IBM z14 ZR1', - }; - - sub get_hardware_type() ---- a/cpumf/data/cpum-cf-hw-counter.map -+++ b/cpumf/data/cpum-cf-hw-counter.map -@@ -26,4 +26,5 @@ - 2964 => 'cpum-cf-extended-z13.ctr', - 2965 => 'cpum-cf-extended-z13.ctr', - 3906 => 'cpum-cf-extended-z14.ctr', -+ 3907 => 'cpum-cf-extended-z14.ctr', - }; diff --git a/s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch b/s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch deleted file mode 100644 index 7134aa4..0000000 --- a/s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch +++ /dev/null @@ -1,155 +0,0 @@ -Subject: zdev: Integrate firmware auto-configuration with dracut -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: 3fb356ebd297e4384208b7688d49cb3eb8f5b3e1 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Integrate firmware auto-configuration with dracut - - Add a dracut hook that applies firmware-provided I/O configuration data - as auto-configuration during boot. This way, all I/O devices configured - by DPM are automatically brought online without further user - interaction. - - This mechanism is active by default. It can be deactivated by specifying - the following parameter on the kernel command line: - - rd.zdev=no-auto - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/dracut/95zdev/module-setup.sh | 19 ++++++++++---- - zdev/dracut/95zdev/parse-zdev.sh | 38 +++++++++++++++++++++++++++++ - zdev/dracut/Makefile | 3 ++ - 3 files changed, 55 insertions(+), 5 deletions(-) - ---- a/zdev/dracut/95zdev/module-setup.sh -+++ b/zdev/dracut/95zdev/module-setup.sh -@@ -9,7 +9,8 @@ - # 95zdev/module_setup.sh - # This module installs configuration files (udev rules and modprobe.conf - # files) required to enable the root device on s390. It will only work when --# the root device was configured using the chzdev tool. -+# the root device was configured using the chzdev tool. In addition, -+# a hook is installed to parse rd.zdev= kernel parameters. - # - - check() { -@@ -29,15 +30,23 @@ depends() { - } - - installkernel() { -- local _modules=$(lszdev --by-path / --columns MODULES --no-headings 2>/dev/null) -- -- [ -z "$_modules" ] && return 0 -- [ ! -z "$_modules" ] && instmods $_modules -+ # 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 \ -+ dasd_diag_mod zfcp - } - - install() { - local _tempfile - -+ # Ensure that required tools are available -+ inst_multiple chzdev lszdev vmcp -+ -+ # Hook to parse zdev kernel parameter -+ inst_hook cmdline 95 "$moddir/parse-zdev.sh" -+ -+ # Obtain root device configuration -+ - # Exit early if root device type is unknown - if ! lszdev --by-path / >/dev/null 2>&1 ; then - return 0 ---- /dev/null -+++ b/zdev/dracut/95zdev/parse-zdev.sh -@@ -0,0 +1,38 @@ -+#!/bin/sh -+# -+# Copyright IBM Corp. 2017 -+# -+# s390-tools is free software; you can redistribute it and/or modify -+# it under the terms of the MIT license. See LICENSE for details. -+# -+# 95zdev/parse-zdev.sh -+# Parse the kernel command line for rd.zdev kernel parameters. These -+# parameters are evaluated and used to configure z Systems specific devices. -+# -+# Format: -+# rd.zdev=no-auto -+# -+# where -+# -+# no-auto: Indicates that firmware-provided I/O configuration data -+# should not be applied. -+# -+ -+zdev_fw_file="/sys/firmware/sclp_sd/config/data" -+zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet" -+ -+if [ -e "$zdev_fw_file" ] ; then -+ zdev_auto=1 -+else -+ zdev_auto=0 -+fi -+ -+for zdev_arg in $(getargs rd.zdev); do -+ if [ "$zdev_arg" = "no-auto" ] ; then -+ zdev_auto=0 -+ fi -+done -+ -+if [ $zdev_auto -eq 1 ] ; then -+ chzdev --import "$zdev_fw_file" $zdev_base_args -+fi ---- a/zdev/dracut/Makefile -+++ b/zdev/dracut/Makefile -@@ -11,11 +11,14 @@ ZDEVDIR := 95zdev - # performs the following functions when dracut is run: - # - # - copy the persistent root device configuration to the initial ram disk -+# - install a boot-time hook to apply firmware-provided configuration data -+# to the system - # - ifeq ($(HAVE_DRACUT),1) - install: - $(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR) - $(INSTALL) -m 755 -d $(DESTDIR)$(MODDIR)/$(ZDEVDIR) - $(INSTALL) -m 755 $(ZDEVDIR)/module-setup.sh \ -+ $(ZDEVDIR)/parse-zdev.sh \ - $(DESTDIR)$(MODDIR)/$(ZDEVDIR)/ - endif diff --git a/s390-tools-sles15sp1-07-zpcictl-Use-fopen-instead-of-open-for-writes.patch b/s390-tools-sles15sp1-07-zpcictl-Use-fopen-instead-of-open-for-writes.patch deleted file mode 100644 index 2f8cc6a..0000000 --- a/s390-tools-sles15sp1-07-zpcictl-Use-fopen-instead-of-open-for-writes.patch +++ /dev/null @@ -1,55 +0,0 @@ -Subject: zpcictl: Use fopen() instead of open() for writes -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: 8f0496b26aae88e206ac9a95b317043e78d147b8 -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Use fopen() instead of open() for writes - - Be consistent with the rest of the code and use fopen() rather than - open(). - - Reviewed-by: Hendrik Brueckner - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.c | 14 ++++++++------ - 1 file changed, 8 insertions(+), 6 deletions(-) - ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -155,17 +155,19 @@ static unsigned int sysfs_read_value(str - - static void sysfs_write_data(struct zpci_report_error *report, char *slot) - { -+ size_t r_size; - char *path; -- int fd, rc; -+ FILE *fp; -+ -+ r_size = sizeof(*report); - - path = util_path_sysfs("bus/pci/devices/%s/report_error", slot); -- fd = open(path, O_WRONLY); -- if (!fd) -+ fp = fopen(path, "w"); -+ if (!fp) - fopen_err(path); -- rc = write(fd, report, sizeof(*report)); -- if (rc == -1) -+ if (fwrite(report, 1, r_size, fp) != r_size) - warnx("Could not write to file: %s: %s", path, strerror(errno)); -- if (close(fd)) -+ if (fclose(fp)) - warnx("Could not close file: %s: %s", path, strerror(errno)); - free(path); - } diff --git a/s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch b/s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch deleted file mode 100644 index a6ae078..0000000 --- a/s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch +++ /dev/null @@ -1,216 +0,0 @@ -Subject: zdev: Integrate firmware auto-configuration with initramfs-tools -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: 3c5644ccfd46aab27df6e0ed783e94a620bc3fe6 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Integrate firmware auto-configuration with initramfs-tools - - Add initramfs-tools scripts that apply firmware-provided I/O - configuration data as auto-configuration during boot. This way, all I/O - devices configured by DPM are automatically brought online without - further user interaction. - - This mechanism is active by default. It can be deactivated by specifying - the following parameter on the kernel command line: - - rd.zdev=no-auto - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - README.md | 1 - zdev/Makefile | 1 - zdev/initramfs/Makefile | 22 ++++++++ - zdev/initramfs/hooks/zdev | 39 +++++++++++++++ - zdev/initramfs/scripts/init-top/zdev | 67 +++++++++++++++++++++++++++ - 5 files changed, 130 insertions(+) - ---- a/README.md -+++ b/README.md -@@ -272,6 +272,7 @@ This table lists additional build or ins - | __COMPONENT__ | __OPTION__ | __TOOLS__ | - |----------------|:----------------:|:-------------------------------:| - | dracut | `HAVE_DRACUT` | zdev | -+| initramfs-tools| `HAVE_INITRAMFS` | zdev | - - The s390-tools build process uses "pkg-config" if available and hard-coded - compiler and linker options otherwise. ---- a/zdev/Makefile -+++ b/zdev/Makefile -@@ -8,6 +8,7 @@ install: all - $(MAKE) -C src install - $(MAKE) -C man install - $(MAKE) -C dracut install -+ $(MAKE) -C initramfs install - - clean: - $(MAKE) -C src clean ---- /dev/null -+++ b/zdev/initramfs/Makefile -@@ -0,0 +1,22 @@ -+# Common definitions -+include ../../common.mak -+ -+INITRAMFSDIR := /usr/share/initramfs-tools -+HOOKDIR := $(INITRAMFSDIR)/hooks -+INITTOP := $(INITRAMFSDIR)/scripts/init-top -+ -+# HAVE_INITRAMFS -+# -+# This install time parameter determines whether the zdev initramfs support is -+# installed (HAVE_INITRAMFS=1) or not (default). When installed, the module -+# performs the following functions when mkinitramfs is run: -+# -+# - install a boot-time hook to apply firmware-provided configuration data -+# to the system -+# -+ifeq ($(HAVE_INITRAMFS),1) -+install: -+ $(INSTALL) -m 755 -d $(DESTDIR)/$(HOOKDIR) $(DESTDIR)/$(INITTOP) -+ $(INSTALL) -m 755 hooks/zdev $(DESTDIR)/$(HOOKDIR) -+ $(INSTALL) -m 755 scripts/init-top/zdev $(DESTDIR)/$(INITTOP) -+endif ---- /dev/null -+++ b/zdev/initramfs/hooks/zdev -@@ -0,0 +1,39 @@ -+#!/bin/sh -+# -+# Copyright IBM Corp. 2016, 2017 -+# -+# s390-tools is free software; you can redistribute it and/or modify -+# it under the terms of the MIT license. See LICENSE for details. -+# -+# hooks/zdev -+# This hook script adds files required to apply firmware-provided I/O -+# configuration data during boot. -+# -+ -+PREREQ="" -+ -+prereqs() -+{ -+ echo "$PREREQ" -+} -+ -+case $1 in -+ prereqs) -+ prereqs -+ exit 0 -+ ;; -+esac -+ -+. /usr/share/initramfs-tools/hook-functions -+ -+# Add modules for all device types supported by chzdev (required for -+# auto-configuration) -+zdev_modules="lcs qeth qeth_l2 qeth_l3 dasd_mod dasd_eckd_mod dasd_fba_mod dasd_diag_mod zfcp" -+ -+for x in $zdev_modules ; do -+ manual_add_modules ${x} -+done -+ -+copy_exec /sbin/chzdev -+copy_exec /sbin/lszdev -+copy_exec /sbin/vmcp ---- /dev/null -+++ b/zdev/initramfs/scripts/init-top/zdev -@@ -0,0 +1,67 @@ -+#!/bin/sh -+# -+# Copyright IBM Corp. 2017 -+# -+# s390-tools is free software; you can redistribute it and/or modify -+# it under the terms of the MIT license. See LICENSE for details. -+# -+# scripts/init-top/zdev -+# Parse the kernel command line for rd.zdev kernel parameters. These -+# parameters are evaluated and used to configure z Systems specific devices. -+# -+# Format: -+# rd.zdev=no-auto -+# -+# where -+# -+# no-auto: Indicates that firmware-provided I/O configuration data -+# should not be applied. -+# -+ -+PREREQ="udev" -+ -+prereqs() -+{ -+ echo "$PREREQ" -+} -+ -+case $1 in -+prereqs) -+ prereqs -+ exit 0 -+ ;; -+esac -+ -+. /scripts/functions -+ -+zdev_fw_file="/sys/firmware/sclp_sd/config/data" -+zdev_base_args="--force --yes --no-root-update --no-settle --auto-conf --quiet" -+ -+if [ -e "$zdev_fw_file" ] ; then -+ zdev_auto=1 -+else -+ zdev_auto=0 -+fi -+ -+for x in $(cat /proc/cmdline); do -+ case ${x} in -+ rd.zdev=*) -+ zdev_arg=${x#*=} -+ if [ "$zdev_arg" = "no-auto" ] ; then -+ zdev_auto=0 -+ fi -+ ;; -+ esac -+done -+ -+if [ $zdev_auto -eq 1 ] ; then -+ log_begin_msg "Starting firmware auto-configuration" -+ chzdev --import "$zdev_fw_file" $zdev_base_args -+ log_end_msg -+ -+ # Repeat cold-plug after creating udev rules -+ udevadm control --reload -+ udevadm trigger --type=subsystems --action=add -+ udevadm trigger --action=add -+ udevadm settle || true -+fi diff --git a/s390-tools-sles15sp1-08-zpcictl-Read-device-link-to-obtain-device-address.patch b/s390-tools-sles15sp1-08-zpcictl-Read-device-link-to-obtain-device-address.patch deleted file mode 100644 index 5c1e2f4..0000000 --- a/s390-tools-sles15sp1-08-zpcictl-Read-device-link-to-obtain-device-address.patch +++ /dev/null @@ -1,77 +0,0 @@ -Subject: zpcictl: Read device link to obtain device address -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: e2a8d85916fb77d2a9b41253446973cd97107c42 -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Read device link to obtain device address - - The address sysfs attribute might not be present on some older kernel - levels. Read the device link instead using readlink() to obtain the - address. - - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.c | 27 ++++++++++++++++++--------- - 1 file changed, 18 insertions(+), 9 deletions(-) - ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -172,13 +172,16 @@ static void sysfs_write_data(struct zpci - free(path); - } - -+/* lstat() doesn't work for sysfs files, so we have to work with a fixed size */ -+#define READLINK_SIZE 256 -+ - static void sysfs_get_slot_addr(const char *dev, char *slot) - { -+ char device[READLINK_SIZE], *result; - unsigned int major, minor; - struct stat dev_stat; -- char addr[13]; -+ ssize_t len; - char *path; -- FILE *fp; - - if (stat(dev, &dev_stat) != 0) { - errx(EXIT_FAILURE, "Could not get stat information for %s: %s", -@@ -187,15 +190,21 @@ static void sysfs_get_slot_addr(const ch - major = major(dev_stat.st_rdev); - minor = minor(dev_stat.st_rdev); - -- path = util_path_sysfs("dev/char/%u:%u/address", major, minor); -- fp = fopen(path, "r"); -- if (!fp) -- fopen_err(path); -- fscanf(fp, "%s", addr); -- fclose(fp); -+ path = util_path_sysfs("dev/char/%u:%u/device", major, minor); -+ len = readlink(path, device, READLINK_SIZE - 1); - free(path); -+ if (len != -1) -+ device[len] = '\0'; -+ else -+ errx(EXIT_FAILURE, "Could not read device link for %s", dev); -+ -+ result = strrchr(device, '/'); -+ if (result) -+ result++; -+ else -+ result = device; - -- strcpy(slot, addr); -+ strcpy(slot, result); - } - - static void get_device_node(struct zpci_device *pdev) diff --git a/s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch b/s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch deleted file mode 100644 index 1c92216..0000000 --- a/s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch +++ /dev/null @@ -1,507 +0,0 @@ -Subject: zdev: Implement internal device attributes -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: c0392efa39e48cb12fdf3524b2f9e683e46f0f14 -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Implement internal device attributes - - This change adds base infrastructure for implementing internal device - attributes. In the context of the zdev tools, an internal device - attribute is a new type of device attribute with the following - characteristics: - - - Can be set and removed like normal device attributes - - Affects zdev-internal handling only - - Does not correspond to an actual device attribute, that is - it has no representation in SysFS - - Can not be set in the active configuration - - Name starts with "zdev:" to prevent conflicts with actual - device attributes - - Values for internal device attributes are stored in udev rules alongside - the normal persistent configuration of a device. They are encoded as - udev environment variables. Note that they have no further effect on - udev processing. - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/include/attrib.h | 2 - zdev/include/internal.h | 20 +++++++++ - zdev/include/misc.h | 1 - zdev/include/udev.h | 7 +++ - zdev/src/Makefile | 4 - - zdev/src/device.c | 15 +++++++ - zdev/src/internal.c | 25 ++++++++++++ - zdev/src/misc.c | 15 +++++++ - zdev/src/udev.c | 32 +++++++++++++++ - zdev/src/udev_ccw.c | 16 +++++++ - zdev/src/udev_ccwgroup.c | 11 +++++ - zdev/src/udev_zfcp_lun.c | 80 ++++++++++++++++++++++++++++++++++++--- - 12 files changed, 220 insertions(+), 8 deletions(-) - ---- a/zdev/include/attrib.h -+++ b/zdev/include/attrib.h -@@ -189,6 +189,7 @@ struct value_map { - * in the persistent configuration - * @nounload: (Device type attributes only) This attribute can be set while - * the corresponding kernel module remains loaded. -+ * @internal: This attribute only affects internal handling - * @order: A number indicating the order in which to apply attribute - * @order_cmp: A function determining if a setting for this attribute should - * be applied before (-1) or after (1) another setting, or -@@ -216,6 +217,7 @@ struct attrib { - unsigned int activerem :1; - unsigned int defunset :1; - unsigned int nounload :1; -+ unsigned int internal :1; - - /* Optional */ - int order; ---- /dev/null -+++ b/zdev/include/internal.h -@@ -0,0 +1,20 @@ -+/* -+ * zdev - Modify and display the persistent configuration of devices -+ * -+ * Copyright IBM Corp. 2017 -+ * -+ * 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 INTERNAL_H -+#define INTERNAL_H -+ -+#include -+ -+#define INTERNAL_ATTR_PREFIX "zdev:" -+ -+const char *internal_get_name(const char *name); -+bool internal_by_name(const char *name); -+ -+#endif /* INTERNAL_H */ ---- a/zdev/include/misc.h -+++ b/zdev/include/misc.h -@@ -183,6 +183,7 @@ bool str_to_config(const char *, config_ - char *quote_str(const char *, int); - char *unquote_str(const char *); - char *shrink_str(const char *); -+char *misc_strrstr(const char *haystack, const char *needle); - - struct util_list *strlist_new(void); - void strlist_free(struct util_list *); ---- a/zdev/include/udev.h -+++ b/zdev/include/udev.h -@@ -13,6 +13,9 @@ - #include "lib/util_list.h" - #include "exit_code.h" - -+struct attrib; -+struct setting_list; -+ - extern int udev_need_settle; - extern int udev_no_settle; - -@@ -46,4 +49,8 @@ exit_code_t udev_remove_rule(const char - - void udev_settle(void); - -+void udev_add_internal_from_entry(struct setting_list *list, -+ struct udev_entry_node *entry, -+ struct attrib **attribs); -+ - #endif /* UDEV_H */ ---- a/zdev/src/Makefile -+++ b/zdev/src/Makefile -@@ -8,7 +8,7 @@ ALL_CPPFLAGS += -I ../include -std=gnu99 - chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \ - export.o hash.o inuse.o misc.o namespace.o opts.o path.o \ - root.o select.o setting.o subtype.o table.o table_attribs.o \ -- table_types.o net.o firmware.o -+ table_types.o net.o firmware.o internal.o - - # Devtype Helpers - chzdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \ -@@ -38,7 +38,7 @@ chzdev_objects += generic_ccw.o - lszdev_objects += attrib.o lszdev.o device.o devnode.o devtype.o exit_code.o \ - export.o hash.o inuse.o misc.o namespace.o opts.o path.o \ - root.o select.o setting.o subtype.o table.o table_types.o \ -- net.o -+ net.o internal.o - - # Devtype Helpers - lszdev_objects += blkinfo.o ccw.o ccwgroup.o findmnt.o modprobe.o module.o \ ---- a/zdev/src/device.c -+++ b/zdev/src/device.c -@@ -16,6 +16,7 @@ - #include "attrib.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "namespace.h" - #include "setting.h" -@@ -221,6 +222,9 @@ static exit_code_t apply_setting(struct - goto err_activeonly_forceable; - if (!force && SCOPE_AUTOCONF(config) && a->activeonly) - goto err_activeonly_forceable; -+ /* Check for internal. */ -+ if (config == config_active && a->internal) -+ goto err_int_noactive; - /* Check for multiple values. */ - if (!force && !a->multi && strlist_find(processed, key)) - goto err_multi_forceable; -@@ -230,6 +234,9 @@ static exit_code_t apply_setting(struct - goto err_unknown; - if (!force) - goto err_unknown_forceable; -+ /* Check for internal. */ -+ if (config == config_active && internal_by_name(key)) -+ goto err_int_noactive; - } - - strlist_add(processed, "%s", key); -@@ -294,6 +301,11 @@ err_activeonly_forceable: - delayed_forceable("Attribute '%s' should only be changed in the active " - "config\n", a->name); - return EXIT_INVALID_SETTING; -+ -+err_int_noactive: -+ delayed_err("Internal attribute '%s' cannot be set in the active config\n", -+ key); -+ return EXIT_INVALID_SETTING; - } - - /* Apply device settings from strlist to device. */ -@@ -542,6 +554,9 @@ exit_code_t device_write_active_settings - s = p->ptr; - if (!s->modified || s->removed) - continue; -+ if ((s->attrib && s->attrib->internal) || -+ internal_by_name(s->name)) -+ continue; - - path = subtype_get_active_attrib_path(st, dev, s->name); - if (!path) { ---- /dev/null -+++ b/zdev/src/internal.c -@@ -0,0 +1,25 @@ -+/* -+ * zdev - Modify and display the persistent configuration of devices -+ * -+ * Copyright IBM Corp. 2017 -+ * -+ * 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 -+ -+#include "internal.h" -+#include "misc.h" -+ -+/* Return identifier of internal attribute with specified @name. */ -+const char *internal_get_name(const char *name) -+{ -+ return name + sizeof(INTERNAL_ATTR_PREFIX) - 1; -+} -+ -+/* Check if attribute is internal by name. */ -+bool internal_by_name(const char *name) -+{ -+ return starts_with(name, INTERNAL_ATTR_PREFIX); -+} ---- a/zdev/src/misc.c -+++ b/zdev/src/misc.c -@@ -1717,3 +1717,18 @@ void debug_init(int argc, char *argv[]) - fprintf(stderr, "%s\"%s\"", i > 0 ? ", " : "", argv[i]); - fprintf(stderr, "\n"); - } -+ -+/* Return the last occurrence of @needle in @haystack, or %NULL if @needle -+ * was not found. */ -+char *misc_strrstr(const char *haystack, const char *needle) -+{ -+ char *result, *next; -+ -+ result = strstr(haystack, needle); -+ if (result) { -+ while ((next = strstr(result + 1, needle))) -+ result = next; -+ } -+ -+ return result; -+} ---- a/zdev/src/udev.c -+++ b/zdev/src/udev.c -@@ -409,3 +409,35 @@ void udev_settle(void) - return; - misc_system(err_ignore, "%s settle", PATH_UDEVADM); - } -+ -+/* Extract internal attribute settings from @entry and add to @list. -+ * Associate corresponding attribute if found in @attribs. */ -+void udev_add_internal_from_entry(struct setting_list *list, -+ struct udev_entry_node *entry, -+ struct attrib **attribs) -+{ -+ char *copy, *name, *end, *u; -+ struct attrib *a; -+ -+ /* ENV{zdev_var}="1" */ -+ copy = misc_strdup(entry->key); -+ -+ /* Find attribute name start. */ -+ name = strchr(copy, '{'); -+ end = strrchr(copy, '}'); -+ if (!name || !end) -+ goto out; -+ *end = 0; -+ name++; -+ -+ /* zdev_ => zdev: */ -+ u = strchr(name, '_'); -+ if (u) -+ *u = ':'; -+ -+ a = attrib_find(attribs, name); -+ setting_list_apply_actual(list, a, name, entry->value); -+ -+out: -+ free(copy); -+} ---- a/zdev/src/udev_ccw.c -+++ b/zdev/src/udev_ccw.c -@@ -18,6 +18,7 @@ - #include "attrib.h" - #include "ccw.h" - #include "device.h" -+#include "internal.h" - #include "misc.h" - #include "path.h" - #include "setting.h" -@@ -49,6 +50,12 @@ static void add_setting_from_entry(struc - char *copy, *name, *end; - struct attrib *a; - -+ /* ENV{zdev_var}="1" */ -+ if (starts_with(entry->key, "ENV{zdev_") && -+ strcmp(entry->op, "=") == 0) { -+ udev_add_internal_from_entry(list, entry, attribs); -+ return; -+ } - /* ATTR{[ccw/0.0.37bf]online}=1 */ - if (strncmp(entry->key, "ATTR{[ccw/", 10) != 0 || - strcmp(entry->op, "=") != 0) -@@ -190,7 +197,14 @@ exit_code_t udev_ccw_write_device(struct - s = p->ptr; - if (s->removed) - continue; -- fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, s->value); -+ if ((s->attrib && s->attrib->internal) || -+ internal_by_name(s->name)) { -+ fprintf(fd, "ENV{zdev_%s}=\"%s\"\n", -+ internal_get_name(s->name), s->value); -+ } else { -+ fprintf(fd, "ATTR{[ccw/%s]%s}=\"%s\"\n", id, s->name, -+ s->value); -+ } - } - - /* Write udev rule epilog. */ ---- a/zdev/src/udev_ccwgroup.c -+++ b/zdev/src/udev_ccwgroup.c -@@ -18,6 +18,7 @@ - #include "attrib.h" - #include "ccwgroup.h" - #include "device.h" -+#include "internal.h" - #include "misc.h" - #include "path.h" - #include "setting.h" -@@ -68,6 +69,12 @@ static void add_setting_from_entry(struc - char *copy, *name, *end; - struct attrib *a; - -+ /* ENV{zdev_var}="1" */ -+ if (starts_with(entry->key, "ENV{zdev_") && -+ strcmp(entry->op, "=") == 0) { -+ udev_add_internal_from_entry(list, entry, attribs); -+ return; -+ } - /* ATTR{[ccwgroup/0.0.f5f0]online}=1 */ - if (strncmp(entry->key, "ATTR{[ccwgroup/", 10) != 0 || - strcmp(entry->op, "=") != 0) -@@ -282,6 +289,10 @@ exit_code_t udev_ccwgroup_write_device(s - fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", - ccw_id, s->name, str->str); - } -+ } else if ((s->attrib && s->attrib->internal) || -+ internal_by_name(s->name)) { -+ fprintf(fd, "ENV{zdev_%s}=\"%s\"\n", -+ internal_get_name(s->name), s->value); - } else { - fprintf(fd, "ATTR{[ccwgroup/%s]%s}=\"%s\"\n", ccw_id, - s->name, s->value); ---- a/zdev/src/udev_zfcp_lun.c -+++ b/zdev/src/udev_zfcp_lun.c -@@ -18,6 +18,7 @@ - - #include "attrib.h" - #include "device.h" -+#include "internal.h" - #include "misc.h" - #include "path.h" - #include "scsi.h" -@@ -128,7 +129,7 @@ static bool zfcp_lun_devid_from_entry(st - struct udev_entry_node *entry) - { - struct zfcp_lun_devid id; -- char *copy = NULL, *s; -+ char *copy = NULL, *s, *e, *u; - int i; - bool rc = false; - -@@ -182,6 +183,28 @@ static bool zfcp_lun_devid_from_entry(st - goto out; - } - -+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/ -+ if (starts_with(entry->key, "ENV{zdev_")) { -+ copy = misc_strdup(entry->key); -+ -+ /* Find ID start (last __) and end (last }). */ -+ s = misc_strrstr(copy, "__"); -+ e = strrchr(copy, '}'); -+ if (!s || !e) -+ goto out; -+ *e = 0; -+ s += 2; -+ /* Convert variable name to ID format. */ -+ for (i = 0, u = s; (u = strchr(u, '_')); i++, u++) { -+ if (i < 2) -+ *u = '.'; -+ else -+ *u = ':'; -+ } -+ rc = zfcp_lun_parse_devid(&id, s, err_ignore) == EXIT_OK ? -+ true : false; -+ } -+ - out: - free(copy); - if (rc) -@@ -211,11 +234,46 @@ static struct zfcp_lun_node *zfcp_lun_no - return node; - } - -+static void add_internal_setting_from_entry(struct udev_entry_node *entry, -+ struct zfcp_lun_node *node) -+{ -+ char *copy, *name, *end, *u; -+ struct attrib *a; -+ -+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/ -+ copy = misc_strdup(entry->key); -+ -+ /* Find attribute name start and end. */ -+ name = strchr(copy, '{'); -+ end = misc_strrstr(copy, "__"); -+ if (!name || !end) -+ goto out; -+ *end = 0; -+ name++; -+ -+ /* zdev_ => zdev: */ -+ u = strchr(name, '_'); -+ if (u) -+ *u = ':'; -+ -+ a = attrib_find(zfcp_lun_subtype.dev_attribs, name); -+ setting_list_apply_actual(node->fc_settings, a, name, entry->value); -+ -+out: -+ free(copy); -+} -+ - static void add_fc_setting_from_entry(struct udev_entry_node *entry, - struct zfcp_lun_node *node) - { - char *copy, *s, *e; - -+ /*ENV{zdev_var__0_0_1941_0x500507630510c1ae_0x402340d400000000}="1"*/ -+ if (starts_with(entry->key, "ENV{zdev_") && -+ strcmp(entry->op, "=") == 0) { -+ add_internal_setting_from_entry(entry, node); -+ return; -+ } - /*ATTR{[ccw/0.0.1941]0x500507630510c1ae/0x402340d400000000/failed}="0"*/ - if (!starts_with(entry->key, "ATTR{[ccw/")) - return; -@@ -490,7 +548,7 @@ static struct zfcp_lun_node *state_to_zf - s->value); - setting_list_add(node->scsi_settings, n); - } else { -- n = setting_new(NULL, s->name, s->value); -+ n = setting_new(s->attrib, s->name, s->value); - setting_list_add(node->fc_settings, n); - } - } -@@ -580,9 +638,21 @@ static exit_code_t write_luns_rule(const - node->id.lun); - - util_list_iterate(&node->fc_settings->list, s) { -- fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 "/0x%016" -- PRIx64 "/%s}=\"%s\"\n", hba_id, node->id.wwpn, -- node->id.lun, s->name, s->value); -+ if ((s->attrib && s->attrib->internal) || -+ internal_by_name(s->name)) { -+ fprintf(fd, "ENV{zdev_%s__%x_%x_%04x_0x%016" -+ PRIx64 "_0x%016" PRIx64 "}=\"%s\"\n", -+ internal_get_name(s->name), -+ node->id.fcp_dev.cssid, -+ node->id.fcp_dev.ssid, -+ node->id.fcp_dev.devno, node->id.wwpn, -+ node->id.lun, s->value); -+ } else { -+ fprintf(fd, "ATTR{[ccw/%s]0x%016" PRIx64 -+ "/0x%016" PRIx64 "/%s}=\"%s\"\n", -+ hba_id, node->id.wwpn, node->id.lun, -+ s->name, s->value); -+ } - } - last_node = node; - } diff --git a/s390-tools-sles15sp1-09-zpcictl-Make-device-node-for-NVMe-optional.patch b/s390-tools-sles15sp1-09-zpcictl-Make-device-node-for-NVMe-optional.patch deleted file mode 100644 index eaa780b..0000000 --- a/s390-tools-sles15sp1-09-zpcictl-Make-device-node-for-NVMe-optional.patch +++ /dev/null @@ -1,124 +0,0 @@ -Subject: zpcictl: Make device node for NVMe optional -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: 342c6a3707315514f0f886fabb532f6c8b59b694 -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Make device node for NVMe optional - - At the moment, if we specify the slot address of an NVMe device but - can't find the corresponding device node, the execution is terminated. - - This is a bit harsh as the device node is rather optional and only - necessary to collect S.M.A.R.T. data. We should still be able to issue - the error reporting, even if we couldn't determine the device node. - - Therefore, make sure the device node for NVMe devices is optional by - changing various error messages to warnings. - Change sysfs_get_slot_addr() to have a return value and work with that - accordingly. - Also make sure, that execution is terminated when a valid device node - was specified but no matching slot address was determined. The slot - address is necessary to issue the error reporting commands. - - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.c | 30 ++++++++++++++++++++---------- - 1 file changed, 20 insertions(+), 10 deletions(-) - ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -104,6 +104,9 @@ static char *collect_smart_data(struct z - char *cmd; - FILE *fd; - -+ if (!pdev->device) -+ return NULL; -+ - util_asprintf(&cmd, SMARTCTL_CMDLINE, pdev->device); - fd = popen(cmd, "r"); - if (!fd) -@@ -175,7 +178,7 @@ static void sysfs_write_data(struct zpci - /* lstat() doesn't work for sysfs files, so we have to work with a fixed size */ - #define READLINK_SIZE 256 - --static void sysfs_get_slot_addr(const char *dev, char *slot) -+static int sysfs_get_slot_addr(const char *dev, char *slot) - { - char device[READLINK_SIZE], *result; - unsigned int major, minor; -@@ -184,8 +187,9 @@ static void sysfs_get_slot_addr(const ch - char *path; - - if (stat(dev, &dev_stat) != 0) { -- errx(EXIT_FAILURE, "Could not get stat information for %s: %s", -- dev, strerror(errno)); -+ warnx("Could not get stat information for %s: %s", -+ dev, strerror(errno)); -+ return 0; - } - major = major(dev_stat.st_rdev); - minor = minor(dev_stat.st_rdev); -@@ -193,18 +197,21 @@ static void sysfs_get_slot_addr(const ch - path = util_path_sysfs("dev/char/%u:%u/device", major, minor); - len = readlink(path, device, READLINK_SIZE - 1); - free(path); -- if (len != -1) -+ if (len != -1) { - device[len] = '\0'; -- else -- errx(EXIT_FAILURE, "Could not read device link for %s", dev); -+ } else { -+ warnx("Could not read device link for %s", dev); -+ return 0; -+ } - - result = strrchr(device, '/'); - if (result) - result++; - else - result = device; -- - strcpy(slot, result); -+ -+ return 1; - } - - static void get_device_node(struct zpci_device *pdev) -@@ -219,12 +226,13 @@ static void get_device_node(struct zpci_ - if (count == -1) { - warnx("Could not read directory %s: %s", path, strerror(errno)); - free(path); -- exit(EXIT_FAILURE); -+ return; - } - - for (i = 0; i < count; i++) { - util_asprintf(&dev, "/dev/%s", de_vec[i]->d_name); -- sysfs_get_slot_addr(dev, slot); -+ if (!sysfs_get_slot_addr(dev, slot)) -+ continue; - if (strcmp(slot, pdev->slot) == 0) { - pdev->device = dev; - break; -@@ -255,7 +263,9 @@ static void get_device_info(struct zpci_ - if (is_blk_dev(dev)) - errx(EXIT_FAILURE, "Unsupported device type %s", dev); - if (is_char_dev(dev)) { -- sysfs_get_slot_addr(dev, pdev->slot); -+ if (!sysfs_get_slot_addr(dev, pdev->slot)) -+ errx(EXIT_FAILURE, -+ "Could not determine slot address for %s", dev); - pdev->device = dev; - } else { - strcpy(pdev->slot, dev); diff --git a/s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch b/s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch deleted file mode 100644 index 9de2443..0000000 --- a/s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch +++ /dev/null @@ -1,505 +0,0 @@ -Subject: zdev: Implement support for early device configuration -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: 156450f359bb13776fac2130a1cac00a48c2deda -Problem-ID: LS1604 - -Upstream-Description: - - zdev: Implement support for early device configuration - - Enable user to specify that a device should be configured early, that is - during the initial RAM-disk boot phase. This may be necessary, e.g. to - override auto-configuration for a device which is also applied during - that boot phase. It may also be used to manually specify devices that - are required to access the root file system, such as networking devices. - - Users can mark devices as requiring early configuration by specifying - a value of 1 for the newly added internal attribute zdev:early: - - # chzdev dasd-eckd 0.0.1234 -p zdev:early=1 - - This can be changed back by removing the attribute setting, or by - setting the attribute value to 0: - - # chzdev dasd-eckd 0.0.1234 -p -r zdev:early - - or - - # chzdev dasd-eckd 0.0.1234 -p zdev:early=0 - - Signed-off-by: Peter Oberparleiter - Signed-off-by: Jan Höppner - - -Signed-off-by: Peter Oberparleiter ---- - zdev/dracut/95zdev/module-setup.sh | 21 +------ - zdev/include/internal.h | 5 + - zdev/initramfs/hooks/zdev | 19 ++++++ - zdev/man/chzdev.8 | 29 ++++++++++ - zdev/src/chzdev.c | 4 - - zdev/src/ctc.c | 2 - zdev/src/dasd.c | 3 + - zdev/src/generic_ccw.c | 2 - zdev/src/internal.c | 13 ++++ - zdev/src/lcs.c | 2 - zdev/src/qeth.c | 2 - zdev/src/root.c | 82 ++++++++++++++++++++++------- - zdev/src/zfcp_host.c | 2 - zdev/src/zfcp_lun.c | 2 - 14 files changed, 152 insertions(+), 36 deletions(-) - ---- a/zdev/dracut/95zdev/module-setup.sh -+++ b/zdev/dracut/95zdev/module-setup.sh -@@ -45,23 +45,12 @@ install() { - # Hook to parse zdev kernel parameter - inst_hook cmdline 95 "$moddir/parse-zdev.sh" - -- # Obtain root device configuration -- -- # Exit early if root device type is unknown -- if ! lszdev --by-path / >/dev/null 2>&1 ; then -- return 0 -- fi -- -+ # Obtain early + root device configuration - _tempfile=$(mktemp --tmpdir dracut-zdev.XXXXXX) -- -- if chzdev --export - --persistent --by-path / >/dev/null 2>&1 ; then -- # Use persistent configuration -- chzdev --export "$_tempfile" --persistent --by-path / --quiet --type -- else -- # Use active configuration -- chzdev --export "$_tempfile" --active --by-path / --quiet --type -- sed -i -e 's/active/persistent/g' "$_tempfile" -- fi -+ chzdev --export "$_tempfile" --persistent --by-path / --quiet \ -+ --type 2>/dev/null -+ chzdev --export - --persistent --by-attrib "zdev:early=1" --quiet \ -+ --type 2>/dev/null >> "$_tempfile" - - # Apply via --import to prevent other devices from being configured - chzdev --import "$_tempfile" --persistent --base "/etc=$initdir/etc" \ ---- a/zdev/include/internal.h -+++ b/zdev/include/internal.h -@@ -12,7 +12,12 @@ - - #include - -+#include "attrib.h" -+ - #define INTERNAL_ATTR_PREFIX "zdev:" -+#define INTERNAL_ATTR_EARLY INTERNAL_ATTR_PREFIX "early" -+ -+extern struct attrib internal_attr_early; - - const char *internal_get_name(const char *name); - bool internal_by_name(const char *name); ---- a/zdev/initramfs/hooks/zdev -+++ b/zdev/initramfs/hooks/zdev -@@ -10,7 +10,8 @@ - # configuration data during boot. - # - --PREREQ="" -+# Needs to run after udev or resulting udev rules could be overwritten -+PREREQ="udev" - - prereqs() - { -@@ -37,3 +38,19 @@ done - copy_exec /sbin/chzdev - copy_exec /sbin/lszdev - copy_exec /sbin/vmcp -+ -+_tempfile=$(mktemp --tmpdir initramfs-zdev.XXXXXX) -+ -+# Obtain early + root device configuration -+chzdev --export "$_tempfile" --persistent --by-path / \ -+ --by-attrib "zdev:early=1" --quiet --type 2>/dev/null -+ -+# Apply via --import to prevent other devices from being configured. -+# Rename the resulting cio-ignore rule to ensure that it does not override -+# the one copied by the initramfs udev hook to /lib/udev. -+chzdev --import "$_tempfile" --persistent \ -+ --base "/etc/udev/rules.d/41-cio-ignore.rules=$DESTDIR/etc/udev/rules.d/41-cio-ignore-root.rules" \ -+ --base "/etc=$DESTDIR/etc" --yes --quiet --no-root-update --force \ -+ >/dev/null -+ -+rm -f "$_tempfile" ---- a/zdev/man/chzdev.8 -+++ b/zdev/man/chzdev.8 -@@ -334,6 +334,35 @@ a specific attribute. - .PP - . - . -+.SS "Special settings" -+The following special settings affect how devices are handled by chzdev: -+.PP -+. -+.BR zdev:early =0|1 -+.RS 4 -+Control in which stage of the boot process a device is activated: -+.TP 4 -+.B 0 -+Device is activated normally during boot (default). -+.PP -+.TP 4 -+.B 1 -+Device is activated early in the boot process, by the initial RAM-disk. -+.PP -+Specify a value of 1 for this attribute in any of the following situations: -+.TP 4 -+\(bu -+To ensure that your settings override auto-configuration settings. -+.PP -+.TP 4 -+\(bu -+To ensure that a device required to access the root file system is correctly -+enabled during boot. An example would be a networking device, or a device that -+is intended to extend a logical volume that provides the root file system. -+.PP -+.RE -+. -+. - .SH ACTIONS - You can use one of the action options listed below to specify the - .B main tool action ---- a/zdev/src/chzdev.c -+++ b/zdev/src/chzdev.c -@@ -3025,8 +3025,8 @@ int main(int argc, char *argv[]) - - if ((pers_mod_devs || pers_mod_devtypes) && !opts.no_root_check && - !dryrun) { -- /* If the root device/device type has been modified, additional -- * work might be necessary. */ -+ /* If the root device/device type or early devices have been -+ * modified, additional work might be necessary. */ - rc = root_check(); - if (rc && !drc) - drc = rc; ---- a/zdev/src/ctc.c -+++ b/zdev/src/ctc.c -@@ -17,6 +17,7 @@ - #include "ctc_auto.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "namespace.h" - #include "path.h" -@@ -425,6 +426,7 @@ static struct subtype ctc_subtype = { - &ccw_attr_online, - &ctc_attr_buffer, - &ctc_attr_protocol, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - .support_definable = 1, ---- a/zdev/src/dasd.c -+++ b/zdev/src/dasd.c -@@ -16,6 +16,7 @@ - #include "dasd.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "modprobe.h" - #include "module.h" -@@ -616,6 +617,7 @@ struct subtype dasd_subtype_eckd = { - &dasd_attr_reservation_policy, - &dasd_attr_last_known_reservation_state, - &dasd_attr_safe_offline, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - -@@ -651,6 +653,7 @@ struct subtype dasd_subtype_fba = { - &dasd_attr_reservation_policy, - &dasd_attr_last_known_reservation_state, - &dasd_attr_safe_offline, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - ---- a/zdev/src/generic_ccw.c -+++ b/zdev/src/generic_ccw.c -@@ -17,6 +17,7 @@ - #include "devnode.h" - #include "devtype.h" - #include "generic_ccw.h" -+#include "internal.h" - #include "namespace.h" - #include "path.h" - #include "subtype.h" -@@ -182,6 +183,7 @@ static struct subtype generic_ccw_subtyp - .dev_attribs = ATTRIB_ARRAY( - &ccw_attr_online, - &ccw_attr_cmb_enable, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - .generic = 1, ---- a/zdev/src/internal.c -+++ b/zdev/src/internal.c -@@ -9,9 +9,22 @@ - - #include - -+#include "attrib.h" - #include "internal.h" - #include "misc.h" - -+struct attrib internal_attr_early = { -+ .name = INTERNAL_ATTR_EARLY, -+ .title = "Activate device early during boot", -+ .desc = "Control the time of activation of a device:\n" -+ " 0: Device is activated normally during boot\n" -+ " 1: Device is activated early in the boot process, by the\n" -+ " initial RAM-disk\n", -+ .defval = "0", -+ .accept = ACCEPT_ARRAY(ACCEPT_RANGE(0, 1)), -+ .internal = 1, -+}; -+ - /* Return identifier of internal attribute with specified @name. */ - const char *internal_get_name(const char *name) - { ---- a/zdev/src/lcs.c -+++ b/zdev/src/lcs.c -@@ -15,6 +15,7 @@ - #include "ccwgroup.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "lcs.h" - #include "lcs_auto.h" - #include "misc.h" -@@ -362,6 +363,7 @@ static struct subtype lcs_subtype = { - &ccw_attr_online, - &lcs_attr_lancmd_timeout, - &lcs_attr_recover, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - .support_definable = 1, ---- a/zdev/src/qeth.c -+++ b/zdev/src/qeth.c -@@ -15,6 +15,7 @@ - #include "ccwgroup.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "namespace.h" - #include "nic.h" -@@ -1445,6 +1446,7 @@ struct subtype qeth_subtype_qeth = { - &qeth_attr_vnicc_takeover_learning, - &qeth_attr_vnicc_bridge_invisible, - &qeth_attr_vnicc_rx_bcast, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - .support_definable = 1, ---- a/zdev/src/root.c -+++ b/zdev/src/root.c -@@ -8,11 +8,13 @@ - */ - - #include -+#include - - #include "lib/util_path.h" - - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "path.h" - #include "root.h" -@@ -20,31 +22,78 @@ - #include "setting.h" - #include "subtype.h" - --/* Determine if the root device was modified. If it was modified, run the -- * corresponding root-install scripts. */ -+static bool is_early_removed(struct device *dev) -+{ -+ struct setting *s; -+ -+ s = setting_list_find(dev->persistent.settings, -+ internal_attr_early.name); -+ if (!s || !s->modified) -+ return false; -+ if (!s->actual_value || strcmp(s->actual_value, "1") != 0) -+ return false; -+ if (s->removed || strcmp(s->value, "0") == 0) -+ return true; -+ return false; -+} -+ -+static void add_early_removed(struct util_list *selected) -+{ -+ int i, j; -+ struct devtype *dt; -+ struct subtype *st; -+ struct device *dev; -+ -+ for (i = 0; devtypes[i]; i++) { -+ dt = devtypes[i]; -+ for (j = 0; dt->subtypes[j]; j++) { -+ st = dt->subtypes[j]; -+ util_list_iterate(&st->devices->hash.list, dev) { -+ if (is_early_removed(dev)) { -+ selected_dev_list_add(selected, dt, st, -+ dev->id, NULL, EXIT_OK); -+ } -+ } -+ } -+ } -+} -+ -+/* Determine if initial RAM-disk needs updating. If so, run the corresponding -+ * scripts if available. */ - exit_code_t root_check(void) - { - struct util_list *selected, *params, *mod = NULL; - struct selected_dev_node *sel; - struct device *dev; - char *params_str; -- exit_code_t rc; -+ exit_code_t rc = EXIT_OK; - struct strlist_node *s; - struct devtype *dt; -+ struct select_opts *select; - -- debug("Checking for modified root device configuration\n"); -+ debug("Checking for required initial RAM-disk update\n"); - -- /* Get list of devices that provide the root device. */ -+ /* Get list of devices that provide the root device or require -+ * early configuration. */ - selected = selected_dev_list_new(); -- rc = select_by_path(NULL, selected, config_active, scope_mandatory, -- NULL, NULL, PATH_ROOT, err_ignore); -- if (rc) { -+ /* First add devices that had zdev:early removed or changed to 0. -+ * The subsequent call to select_devices() will filter out any -+ * duplicates. */ -+ add_early_removed(selected); -+ /* Now add devices required for root file system. */ -+ if (select_by_path(NULL, selected, config_active, scope_mandatory, -+ NULL, NULL, PATH_ROOT, err_ignore)) { - /* Running from an unknown root device is not an error. */ - verb("Note: Could not determine if root device configuration " - "needs to be updated\n"); -- rc = 0; -- goto out; - } -+ /* Finally add devices with zdev:early=1. */ -+ select = select_opts_new(); -+ strlist_add(&select->by_attr, "%s=1", INTERNAL_ATTR_EARLY); -+ select_devices(select, selected, 1, 0, 0, -+ config_active | config_persistent, scope_mandatory, -+ err_ignore); -+ select_opts_free(select); - - /* Determine if any of the devices or device types has been modified. */ - mod = strlist_new(); -@@ -68,19 +117,18 @@ exit_code_t root_check(void) - - if (util_list_is_empty(mod)) - goto out; -- info("Note: Some of the changes affect devices providing the root " -- "file system:\n"); -+ info("Note: The initial RAM-disk must be updated for these changes to take effect:\n"); - util_list_iterate(mod, s) - info(" - %s\n", s->str); -- info(" Additional steps such as rebuilding the RAM-disk might be " -- "required.\n"); - - /* Check if script is available. */ -- if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) -+ if (!util_path_is_reg_file(PATH_ROOT_SCRIPT)) { -+ warn("A manual update of the initial RAM-disk is required.\n"); - goto out; -+ } - - /* Ask for confirmation. */ -- if (!confirm("Update persistent root device configuration now?")) { -+ if (!confirm("Update initial RAM-disk now?")) { - rc = EXIT_ABORTED; - goto out; - } -@@ -97,7 +145,7 @@ exit_code_t root_check(void) - /* Run update command. */ - if (misc_system(err_delayed_print, "%s %s", PATH_ROOT_SCRIPT, - params_str) != 0) { -- error("Failure while updating root device configuration\n"); -+ error("Failure while updating initial RAM-disk\n"); - delayed_print(DELAY_INDENT); - rc = EXIT_RUNTIME_ERROR; - } ---- a/zdev/src/zfcp_host.c -+++ b/zdev/src/zfcp_host.c -@@ -17,6 +17,7 @@ - #include "ccw.h" - #include "device.h" - #include "devtype.h" -+#include "internal.h" - #include "misc.h" - #include "path.h" - #include "setting.h" -@@ -247,6 +248,7 @@ struct subtype zfcp_host_subtype = { - &zfcp_host_attr_failed, - &zfcp_host_attr_port_remove, - &zfcp_host_attr_port_rescan, -+ &internal_attr_early, - ), - .unknown_dev_attribs = 1, - ---- a/zdev/src/zfcp_lun.c -+++ b/zdev/src/zfcp_lun.c -@@ -21,6 +21,7 @@ - #include "devnode.h" - #include "devtype.h" - #include "misc.h" -+#include "internal.h" - #include "namespace.h" - #include "path.h" - #include "scsi.h" -@@ -1097,6 +1098,7 @@ struct subtype zfcp_lun_subtype = { - &zfcp_lun_attr_scsi_timeout, - &zfcp_lun_attr_scsi_state, - &zfcp_lun_attr_scsi_delete, -+ &internal_attr_early, - ), - .prefixes = STRING_ARRAY(SCSI_ATTR_PREFIX), - .unknown_dev_attribs = 1, diff --git a/s390-tools-sles15sp1-10-zpcictl-Change-wording-of-man-page-and-help-output.patch b/s390-tools-sles15sp1-10-zpcictl-Change-wording-of-man-page-and-help-output.patch deleted file mode 100644 index 1c728e9..0000000 --- a/s390-tools-sles15sp1-10-zpcictl-Change-wording-of-man-page-and-help-output.patch +++ /dev/null @@ -1,143 +0,0 @@ -Subject: zpcictl: Change wording of man-page and help output -From: Jan Hoeppner - -Summary: zpcictl: Add tool to manage PCI devices -Description: Use the zpcictl tool to manage PCI devices on the IBM Z - platform. Initial functions include generating firmware - error logs, resetting PCI devices, and preparing a device - for further repair actions. -Upstream-ID: aaaebb2030c80151ecac528f22cb9a52752b868c -Problem-ID: RAS1703 - -Upstream-Description: - - zpcictl: Change wording of man-page and help output - - Signed-off-by: Jan Höppner - - -Signed-off-by: Jan Hoeppner ---- - zpcictl/zpcictl.8 | 38 +++++++++++++++----------------------- - zpcictl/zpcictl.c | 15 ++++++++------- - 2 files changed, 23 insertions(+), 30 deletions(-) - ---- a/zpcictl/zpcictl.8 -+++ b/zpcictl/zpcictl.8 -@@ -20,7 +20,7 @@ - .TH zpcictl 8 "Oct 2018" s390-tools zpcictl - . - .SH NAME --zpcictl - Manage PCI devices on z Systems -+zpcictl - Manage PCI devices on IBM Z - . - . - .SH SYNOPSIS -@@ -30,50 +30,42 @@ zpcictl - Manage PCI devices on z System - . - . - .SH DESCRIPTION --With -+Use - .B zpcictl --, you can manage PCI devices on the IBM z Systems platform. It is especially --used for reporting erroneous PCI devices to the service element. -+to manage PCI devices on the IBM Z platform. In particular, -+use this command to report defective PCI devices to the service element. - - .B Note: - For NVMe devices additional data (such as S.M.A.R.T. data) is collected and sent --with any error handling action. The smartmontools are required to be installed --for this to work. -+with any error handling action. For this extendend data collection, the -+smartmontools must be installed. - .PP - . - . - .SH DEVICE --.B DEVICE --can be either the PCI slot address (e.g. 0000:00:00.0) or the main device node --of an NVMe device (e.g. -+A PCI slot address (e.g. 0000:00:00.0) or the main device node of an NVMe -+device (e.g. - .I /dev/nvme0 - ). - . - . - .SH OPTIONS --.SS Error Handling -+.SS Error Handling Options - .OD reset "" "DEVICE" --Reset --.I DEVICE --and initiate a re-initialization of the PCI device. -+Reset and re-initialize the PCI device. - .PP - . - .OD deconfigure "" "DEVICE" --De-configure --.I DEVICE --and prepare for any repair action. This action will move the --PCI device from a configured to a reserved state. -+Deconfigure the PCI device and prepare for any repair action. This action -+changes the status of the PCI device from configured to reserved. - .PP - . - .OD report-error "" "DEVICE" --Report any device error for --.IR DEVICE . --The --.I DEVICE --is marked as erroneous and no further action is initiated on it. -+Report any device error for the PCI device. -+The device is marked as defective but no further action is taken. - .PP - . --.SS Misc -+.SS General Options - .OD help "h" "" - Print usage information, then exit. - .PP ---- a/zpcictl/zpcictl.c -+++ b/zpcictl/zpcictl.c -@@ -27,8 +27,9 @@ - #define SMARTCTL_CMDLINE "smartctl -x %s 2>/dev/null" - - static const struct util_prg prg = { -- .desc = "Use zpcictl to manage PCI devices on s390\n" -- "DEVICE is the slot id or node of the device (e.g. /dev/nvme0)", -+ .desc = "Use zpcictl to manage PCI devices on IBM Z\n" -+ "DEVICE is the slot ID or node of the device " -+ "(e.g. 0000:00:00.0 or /dev/nvme0)", - .args = "DEVICE", - .copyright_vec = { - { -@@ -46,23 +47,23 @@ static const struct util_prg prg = { - #define OPT_REPORT_ERR 130 - - static struct util_opt opt_vec[] = { -- UTIL_OPT_SECTION("ERROR HANDLING"), -+ UTIL_OPT_SECTION("ERROR HANDLING OPTIONS"), - { - .option = { "reset", no_argument, NULL, OPT_RESET }, -- .desc = "Reset device", -+ .desc = "Reset the device", - .flags = UTIL_OPT_FLAG_NOSHORT, - }, - { - .option = { "deconfigure", no_argument, NULL, OPT_DECONF }, -- .desc = "De-configure device and prepare for any repair action", -+ .desc = "Deconfigure the device to prepare for any repair action", - .flags = UTIL_OPT_FLAG_NOSHORT, - }, - { - .option = { "report-error", no_argument, NULL, OPT_REPORT_ERR }, -- .desc = "Report device error to service element (SE)", -+ .desc = "Report a device error to the service element (SE)", - .flags = UTIL_OPT_FLAG_NOSHORT, - }, -- UTIL_OPT_SECTION("MISC"), -+ UTIL_OPT_SECTION("GENERAL OPTIONS"), - UTIL_OPT_HELP, - UTIL_OPT_VERSION, - UTIL_OPT_END diff --git a/s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch b/s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch deleted file mode 100644 index 4f51a0a..0000000 --- a/s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch +++ /dev/null @@ -1,50 +0,0 @@ -Subject: zdev: Add support for handling I/O configuration data -From: Peter Oberparleiter - -Summary: zdev: Add support for handling I/O configuration data -Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode - can access a firmware-generated I/O configuration data file that - contains s390-specific information about available I/O devices - such as qeth device numbers and parameters, and FCP device IDs. - - This data file is intended to remove the need for users to - manually enter the corresponding device data during installation. - - Linux kernels with the corresponding support make the I/O - configuration data available at the following location: - - /sys/firmware/sclp_sd/config/data - - This patch set adds support for handling this data file using the - chzdev and lszdev tools: - - - I/O configuration data can be applied using chzdev's --import - option - - Initial RAM-Disk scripts automatically apply the - I/O configuration data to the system configuration - - lszdev can be used to display the applied auto-configuration - data - - chzdev can be used to manually override the - auto-configuration data - -Upstream-ID: - -Problem-ID: LS1604 - -Signed-off-by: Peter Oberparleiter ---- - zdev/src/zdev-root-update.dracut | 6 ------ - 1 file changed, 6 deletions(-) - ---- a/zdev/src/zdev-root-update.dracut -+++ b/zdev/src/zdev-root-update.dracut -@@ -20,10 +20,4 @@ dracut -f || { - exit 1 - } - --echo "Installing IPL record" --zipl --noninteractive || { -- echo "${TOOLNAME}: Error: Could not install IPL record" >&2 -- exit 1 --} -- - exit 0 diff --git a/s390-tools-sles15sp1-dbginfo-gather-nvme-related-data.patch b/s390-tools-sles15sp1-dbginfo-gather-nvme-related-data.patch deleted file mode 100644 index d16f4b0..0000000 --- a/s390-tools-sles15sp1-dbginfo-gather-nvme-related-data.patch +++ /dev/null @@ -1,75 +0,0 @@ -Subject: dbginfo: gather nvme related data -From: Sebastian Ott - -Summary: s390-tools/dbginfo: Collect NVMe-related debug data -Description: Collect SMART (Self-Monitoring, Analysis and Reporting Technology) - data in dbginfo.sh . -Upstream-ID: b9e47e356bbfc92e41b758e74606baacbab33ee4 -Problem-ID: RAS1702 - -Upstream-Description: - - dbginfo: gather nvme related data - - Signed-off-by: Sebastian Ott - Signed-off-by: Stefan Haberland - - -Signed-off-by: Sebastian Ott ---- - scripts/dbginfo.sh | 26 +++++++++++++++++++++++++- - 1 file changed, 25 insertions(+), 1 deletion(-) - ---- a/scripts/dbginfo.sh -+++ b/scripts/dbginfo.sh -@@ -182,11 +182,14 @@ readonly OUTPUT_FILE_XML="${WORKPATH}dom - # File that includes the docker inspect output - readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_inspect.out" - -+# File that includes nvme related information -+readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out" -+ - # Mount point of the debug file system - readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug" - - # The amount of steps running the whole collections --readonly COLLECTION_COUNT=11 -+readonly COLLECTION_COUNT=12 - - # The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1) - readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1) -@@ -829,6 +832,25 @@ collect_docker() { - } - - ######################################## -+collect_nvme() { -+ local NVME -+ -+ pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting nvme output" -+ call_run_command "nvme list" "${OUTPUT_FILE_NVME}" -+ -+ for NVME in /dev/nvme[0-9]*; do -+ if [ -c $NVME ]; then -+ call_run_command "smartctl -x $NVME" "${OUTPUT_FILE_NVME}" -+ call_run_command "nvme fw-log $NVME" "${OUTPUT_FILE_NVME}" -+ call_run_command "nvme smart-log $NVME" "${OUTPUT_FILE_NVME}" -+ call_run_command "nvme error-log $NVME" "${OUTPUT_FILE_NVME}" -+ fi -+ done -+ -+ pr_log_stdout " " -+} -+ -+######################################## - post_processing() { - local file_mtime - local file_mtime_epoche -@@ -1120,6 +1142,8 @@ collect_domain_xml - - collect_docker - -+collect_nvme -+ - post_processing - - create_package diff --git a/s390-tools-sles15sp1-qethqoat-add-OSA-Express7S-support.patch b/s390-tools-sles15sp1-qethqoat-add-OSA-Express7S-support.patch deleted file mode 100644 index 286d274..0000000 --- a/s390-tools-sles15sp1-qethqoat-add-OSA-Express7S-support.patch +++ /dev/null @@ -1,65 +0,0 @@ -Subject: [PATCH] [FEAT NET1711] qethqoat: add OSA-Express7S support -From: Julian Wiedmann - -Summary: qethqoat: add OSA-Express7S support -Description: Add the missing identifiers to report the correct card name and - link speed. -Upstream-ID: 20145b6d06debd47944bff0a471d17e5eba07010 -Problem-ID: NET1711 - -Upstream-Description: - - qethqoat: add OSA-Express7S support - - Add the missing identifiers to report the card name and link speed. - - Signed-off-by: Julian Wiedmann - Signed-off-by: Jan Höppner - - -Signed-off-by: Julian Wiedmann ---- - qethqoat/qethqoat.c | 6 ++++++ - qethqoat/qethqoat.h | 2 ++ - 2 files changed, 8 insertions(+) - ---- a/qethqoat/qethqoat.c -+++ b/qethqoat/qethqoat.c -@@ -208,6 +208,9 @@ static void print_physical(struct qeth_q - case OAT_OSA_GEN_OSAE6S: - osagen = "OSA-Express6S"; - break; -+ case OAT_OSA_GEN_OSAE7S: -+ osagen = "OSA-Express7S"; -+ break; - default: - sprintf(tmp, "unknown (0x%x)", phdr->osa_gen); - osagen = tmp; -@@ -239,6 +242,9 @@ static void print_physical(struct qeth_q - case OAT_PORT_SPEED_10gbs_full: - speed = "10 Gb/s / full duplex"; - break; -+ case OAT_PORT_SPEED_25gbs_full: -+ speed = "25 Gb/s / full duplex"; -+ break; - case OAT_PORT_SPEED_UNKNOWN: - speed = "unknown / unknown"; - break; ---- a/qethqoat/qethqoat.h -+++ b/qethqoat/qethqoat.h -@@ -58,6 +58,7 @@ struct qeth_qoat_physical { - #define OAT_OSA_GEN_OSAE4S 0x02 - #define OAT_OSA_GEN_OSAE5S 0x03 - #define OAT_OSA_GEN_OSAE6S 0x04 -+#define OAT_OSA_GEN_OSAE7S 0x05 - __u8 osa_gen; - #define OAT_PORT_SPEED_UNKNOWN 0x00 - #define OAT_PORT_SPEED_10mbs_half 0x01 -@@ -68,6 +69,7 @@ struct qeth_qoat_physical { - #define OAT_PORT_SPEED_1000mbs_full 0x06 - #define OAT_PORT_SPEED_NA 0x07 - #define OAT_PORT_SPEED_10gbs_full 0x08 -+#define OAT_PORT_SPEED_25gbs_full 0x0A - __u8 port_speed; - #define OAT_PORT_MEDIA_COPPER 0x01 - #define OAT_PORT_MEDIA_MULTI_MODE 0x02 diff --git a/s390-tools-sles15sp1-zcrypt-refine-lszcrypt-man-page.patch b/s390-tools-sles15sp1-zcrypt-refine-lszcrypt-man-page.patch deleted file mode 100644 index 24ce8d5..0000000 --- a/s390-tools-sles15sp1-zcrypt-refine-lszcrypt-man-page.patch +++ /dev/null @@ -1,102 +0,0 @@ -From e9c030f2026b1b8e0399679600845c298aeb508d Mon Sep 17 00:00:00 2001 -From: Harald Freudenberger -Date: Mon, 21 Jan 2019 09:07:00 +0100 -Subject: zcrypt: refine lszcrypt man page -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Added some explanations about the columns shown with the -lszcrypt verbose output. - -Signed-off-by: Harald Freudenberger -Signed-off-by: Jan Höppner ---- - zconf/zcrypt/lszcrypt.8 | 64 ++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 63 insertions(+), 1 deletion(-) - -diff --git a/zconf/zcrypt/lszcrypt.8 b/zconf/zcrypt/lszcrypt.8 -index 826e109..bd235ec 100644 ---- a/zconf/zcrypt/lszcrypt.8 -+++ b/zconf/zcrypt/lszcrypt.8 -@@ -10,7 +10,7 @@ - .\" nroff -man lszcrypt.8 - .\" to process this source - .\" --.TH LSZCRYPT 8 "OCT 2017" "s390-tools" -+.TH LSZCRYPT 8 "JAN 2019" "s390-tools" - .SH NAME - lszcrypt \- display zcrypt device and configuration information - .SH SYNOPSIS -@@ -111,6 +111,68 @@ Displays help text and exits. - .TP 8 - .B -v, --version - Displays version information and exits. -+.SH VERBOSE LISTING DETAILS -+Some of the columns showing up in verbose listing mode may need some -+explanation: -+.TP -+.B TYPE and HWTYPE -+The HWTYPE is a numeric value showing which type of hardware the zcrypt -+device driver presumes that this crypto card is. The currently known values -+are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5 and 12=CEX6. -+.br -+The TYPE is a human readable value showing the hardware type and the basic -+function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So -+for example CEX6P means a CEX6 card in EP11 Coprocessor mode. -+.TP -+.B REQUESTS -+This is the counter value of successful processed requests on card or queue -+level. Successful here means the request was processed without any failure -+in the whole processing chain. -+.TP -+.B PENDING -+The underlying firmware and hardware layer usually provide some queuing -+space for requests. When this queue is already filled up, the zcrypt device -+driver maintains a software queue of pending requests. The sum of these -+both values is displayed here and shows the amount of requests waiting for -+processing on card or queue level. -+.TP -+.B FUNCTIONS -+This column shows firmware and hardware function details: -+.br -+S - APSC available: card/queue can handle requests with the special bit -+enabled. -+.br -+M - Accelerator card/queue with support for RSA ME with up to 4k key size. -+.br -+C - Accelerator card/queue with support for RSA CRT with up to 4k key size. -+.br -+D - Card/queue is providing CCA functions (this is the CCA Coprocessor mode). -+.br -+A - Card/queue is providing Accelerator functions (this is the Accelerator mode). -+.br -+X - Card/queue is providing EP11 functions (this is the EP11 Coprocessor mode). -+.br -+N - APXA available (ability to address more than 16 crypto cards and domains). -+.br -+F - Full function support (opposed to restricted function support, see below). -+.br -+R - Restricted function support. The F and R flag both reflect if a -+hypervisor is somehow restricting this crypto resource in a virtual -+environment. Dependent on the hypervisor configuration the crypto requests -+may be filtered by the hypervisor to allow only a subset of functions -+within the virtual runtime environment. For example a shared CCA -+Coprocessor may be restricted by the hypervisor to allow only clear key -+operations within the guests. -+.TP -+.B DRIVER -+.br -+Shows which card or queue device driver currently handles this crypto -+resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX6 -+hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware), -+cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved -+for use by kvm hypervisor for kvm guests and not accessible to host -+applications). It is also valid to have no driver handling a queue which is -+shown as a -no-driver- entry. - .SH EXAMPLES - .TP - .B lszcrypt --- -2.13.7 - diff --git a/s390-tools-sles15sp1-zdev-Also-include-the-ctc-driver-in-the-initrd.patch b/s390-tools-sles15sp1-zdev-Also-include-the-ctc-driver-in-the-initrd.patch deleted file mode 100644 index 9b9977c..0000000 --- a/s390-tools-sles15sp1-zdev-Also-include-the-ctc-driver-in-the-initrd.patch +++ /dev/null @@ -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 - } - diff --git a/s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch b/s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch deleted file mode 100644 index 37bf18f..0000000 --- a/s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch +++ /dev/null @@ -1,70 +0,0 @@ -Subject: zdev: qeth BridgePort and VNICC attribute conflict -From: Hans Wippel - -Description: zdev: qeth BridgePort and VNICC attribute conflict -Symptom: chzdev cannot set VNICC attributes due to a conflict with - BridgePort attributes. -Problem: Existing conflict checking always assumes a BridgePort and a - VNICC attribute are active. -Solution: Introduce a function that determines if BridgePort or VNICC - attributes are active and use only active attributes for conflict - checking. -Reproduction: Set VNICC attribute with chzdev w/o active BridgePort attributes. -Upstream-ID: df01c470c2a680a924ccdba3b6657af4669002b2 -Problem-ID: 172409 - - -Signed-off-by: Hans Wippel ---- - zdev/src/qeth.c | 33 +++++++++++++++++++++++++++++++++ - 1 file changed, 33 insertions(+) - ---- a/zdev/src/qeth.c -+++ b/zdev/src/qeth.c -@@ -1171,6 +1171,37 @@ static exit_code_t check_ineffective_set - return rc; - } - -+/* Check if a possibly conflicting setting is active in the configuration */ -+static bool conflict_setting_active(struct setting *s) -+{ -+ enum qeth_attr_group_type t; -+ -+ t = get_attr_group_type(s); -+ if (t != group_bridge && t != group_vnicc) { -+ /* Check BridgePort and VNICC attributes only */ -+ return false; -+ } -+ if (s->specified) { -+ /* Specified on the command line: We are strict here and do not -+ * allow to specify VNICC and BridgePort attributes in the same -+ * command to avoid issues when attributes are enabled/disabled -+ * in the wrong order. Example: disable VNICC and enable -+ * BridgePort in the same command would result in an error -+ * because BridgePort attributes are set first. -+ */ -+ return true; -+ } -+ if (attrib_match_default(s->attrib, s->value)) { -+ /* Not active if set to default value */ -+ return false; -+ } -+ if (s->actual_value && strncmp(s->actual_value, "n/a", 3) == 0) { -+ /* Not active if in n/a state (conflicting attribute set) */ -+ return false; -+ } -+ return true; -+} -+ - /* Check if there are conflicting attribute settings */ - static exit_code_t check_conflicting_settings(struct setting_list *list) - { -@@ -1182,6 +1213,8 @@ static exit_code_t check_conflicting_set - util_list_iterate(&list->list, s) { - if (s->removed) - continue; -+ if (!conflict_setting_active(s)) -+ continue; - t = get_attr_group_type(s); - if (t == group_bridge && (!bridge || !bridge->specified)) - bridge = s; diff --git a/s390-tools-sles15sp1-zkey-Enhance-error-message-about-missing-CCA-library.patch b/s390-tools-sles15sp1-zkey-Enhance-error-message-about-missing-CCA-library.patch deleted file mode 100644 index 047b957..0000000 --- a/s390-tools-sles15sp1-zkey-Enhance-error-message-about-missing-CCA-library.patch +++ /dev/null @@ -1,85 +0,0 @@ -Subject: zkey: Enhance error message about missing CCA library. -From: Ingo Franzki - -Description: zkey: Enhance error message about missing CCA library. -Symptom: "zkey-cryptsetup reencipher" fails with missing - library and confusing error message. -Problem: The "zkey reencipher" command as well as the "zkey-cryptsetup - reencipher" command requires the IBM CCA Host Libraries and - Tools package to be installed. This is a closed source - library that is not distributed by the distributions, but - must be downloaded separately from an IBM web page. -Solution: Enhance the error message to point to the web page where - the package can be downloaded. -Reproduction: Run the "zkey-cryptsetup reencipher" or "zkey reencipher" - command without having installed the IBM CCA Host Libraries - and Tools package. -Upstream-ID: - -Problem-ID: 173878 - -Signed-off-by: Ingo Franzki ---- - zkey/pkey.c | 13 +++++++++---- - zkey/zkey-cryptsetup.1 | 3 ++- - zkey/zkey.1 | 3 ++- - 3 files changed, 13 insertions(+), 6 deletions(-) - ---- a/zkey/pkey.c -+++ b/zkey/pkey.c -@@ -48,6 +48,7 @@ - * 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 - -@@ -71,16 +72,20 @@ int load_cca_library(void **lib_csulcca, - /* Load the CCA library */ - *lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW); - if (*lib_csulcca == NULL) { -- warnx("%s\nEnsure that the IBM CCA Host Libraries and " -- "Tools are installed properly", dlerror()); -+ 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) { -- warnx("%s\nEnsure that the IBM CCA Host Libraries and " -- "Tools are installed properly", dlerror()); -+ 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; ---- a/zkey/zkey-cryptsetup.1 -+++ b/zkey/zkey-cryptsetup.1 -@@ -182,7 +182,8 @@ behave in the same way as with \fBcrypts - .PP - .B Note: - The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) --to be installed. -+to be installed. For the supported environments and downloads, see: -+\fIhttp://www.ibm.com/security/cryptocards\fP - . - . - . ---- a/zkey/zkey.1 -+++ b/zkey/zkey.1 -@@ -282,7 +282,8 @@ a staged re-enciphering for the \fBOLD\f - .PP - .B Note: - The \fBreencipher\fP command requires the CCA host library (libcsulcca.so) --to be installed. -+to be installed. For the supported environments and downloads, see: -+\fIhttp://www.ibm.com/security/cryptocards\fP - . - .SS "Import existing AES secure keys into the secure key repository" - . diff --git a/s390-tools-sles15sp2-01-zkey-Separate-and-rework-CCA-host-library-loading.patch b/s390-tools-sles15sp2-01-zkey-Separate-and-rework-CCA-host-library-loading.patch new file mode 100644 index 0000000..4fa72df --- /dev/null +++ b/s390-tools-sles15sp2-01-zkey-Separate-and-rework-CCA-host-library-loading.patch @@ -0,0 +1,795 @@ +Subject: zkey: Separate and rework CCA host library loading +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + ++#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) diff --git a/s390-tools-sles15sp2-02-zkey-Move-utility-functions-into-separate-source-fil.patch b/s390-tools-sles15sp2-02-zkey-Move-utility-functions-into-separate-source-fil.patch new file mode 100644 index 0000000..6c379bd --- /dev/null +++ b/s390-tools-sles15sp2-02-zkey-Move-utility-functions-into-separate-source-fil.patch @@ -0,0 +1,297 @@ +Subject: zkey: Move utility functions into separate source file +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 + + #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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 diff --git a/s390-tools-sles15sp2-03-zkey-Add-utility-function-to-get-the-serial-number-o.patch b/s390-tools-sles15sp2-03-zkey-Add-utility-function-to-get-the-serial-number-o.patch new file mode 100644 index 0000000..af6965a --- /dev/null +++ b/s390-tools-sles15sp2-03-zkey-Add-utility-function-to-get-the-serial-number-o.patch @@ -0,0 +1,112 @@ +Subject: zkey: Add utility function to get the serial number of a crypto card +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-04-zkey-Add-utility-function-to-get-the-mkvp-of-a-crypt.patch b/s390-tools-sles15sp2-04-zkey-Add-utility-function-to-get-the-mkvp-of-a-crypt.patch new file mode 100644 index 0000000..b04274d --- /dev/null +++ b/s390-tools-sles15sp2-04-zkey-Add-utility-function-to-get-the-mkvp-of-a-crypt.patch @@ -0,0 +1,213 @@ +Subject: zkey: Add utility function to get the mkvp of a crypto card +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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: ++ * AES CUR: ++ * AES OLD: ++ * with ++ * : 'empty' or 'partial' or 'full' ++ * , : 'valid' or 'invalid' ++ * , , 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 diff --git a/s390-tools-sles15sp2-05-zkey-add-function-to-iterate-over-all-available-CCA-.patch b/s390-tools-sles15sp2-05-zkey-add-function-to-iterate-over-all-available-CCA-.patch new file mode 100644 index 0000000..7059fa4 --- /dev/null +++ b/s390-tools-sles15sp2-05-zkey-add-function-to-iterate-over-all-available-CCA-.patch @@ -0,0 +1,197 @@ +Subject: zkey: add function to iterate over all available CCA APQNs +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 + #include + #include + #include +@@ -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 diff --git a/s390-tools-sles15sp2-06-zkey-Add-function-to-print-the-MKVPs-of-APQNs.patch b/s390-tools-sles15sp2-06-zkey-Add-function-to-print-the-MKVPs-of-APQNs.patch new file mode 100644 index 0000000..5ab337b --- /dev/null +++ b/s390-tools-sles15sp2-06-zkey-Add-function-to-print-the-MKVPs-of-APQNs.patch @@ -0,0 +1,131 @@ +Subject: zkey: Add function to print the MKVPs of APQNs +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch b/s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch new file mode 100644 index 0000000..0c45ee8 --- /dev/null +++ b/s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch @@ -0,0 +1,271 @@ +Subject: zkey: Add function to cross check APQNs for valid master keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-08-zkey-Add-function-to-obtain-the-mkvp-of-a-secure-key.patch b/s390-tools-sles15sp2-08-zkey-Add-function-to-obtain-the-mkvp-of-a-secure-key.patch new file mode 100644 index 0000000..5ee0265 --- /dev/null +++ b/s390-tools-sles15sp2-08-zkey-Add-function-to-obtain-the-mkvp-of-a-secure-key.patch @@ -0,0 +1,74 @@ +Subject: zkey: Add function to obtain the mkvp of a secure key +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-09-zkey-Display-MKVP-when-validating-a-secure-key.patch b/s390-tools-sles15sp2-09-zkey-Display-MKVP-when-validating-a-secure-key.patch new file mode 100644 index 0000000..25f7aac --- /dev/null +++ b/s390-tools-sles15sp2-09-zkey-Display-MKVP-when-validating-a-secure-key.patch @@ -0,0 +1,176 @@ +Subject: zkey: Display MKVP when validating a secure key +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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, diff --git a/s390-tools-sles15sp2-10-zkey-Cross-check-APQNs-when-generating-secure-keys.patch b/s390-tools-sles15sp2-10-zkey-Cross-check-APQNs-when-generating-secure-keys.patch new file mode 100644 index 0000000..9433f76 --- /dev/null +++ b/s390-tools-sles15sp2-10-zkey-Cross-check-APQNs-when-generating-secure-keys.patch @@ -0,0 +1,91 @@ +Subject: zkey: Cross check APQNs when generating secure keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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(); + } diff --git a/s390-tools-sles15sp2-11-zkey-Cross-check-APQNs-when-validating-secure-keys.patch b/s390-tools-sles15sp2-11-zkey-Cross-check-APQNs-when-validating-secure-keys.patch new file mode 100644 index 0000000..4515d22 --- /dev/null +++ b/s390-tools-sles15sp2-11-zkey-Cross-check-APQNs-when-validating-secure-keys.patch @@ -0,0 +1,123 @@ +Subject: zkey: Cross check APQNs when validating secure keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-12-zkey-Cross-check-APQNs-when-importing-secure-keys.patch b/s390-tools-sles15sp2-12-zkey-Cross-check-APQNs-when-importing-secure-keys.patch new file mode 100644 index 0000000..9afe279 --- /dev/null +++ b/s390-tools-sles15sp2-12-zkey-Cross-check-APQNs-when-importing-secure-keys.patch @@ -0,0 +1,85 @@ +Subject: zkey: Cross check APQNs when importing secure keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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); diff --git a/s390-tools-sles15sp2-13-zkey-Cross-check-APQNs-when-changing-APQN-associatio.patch b/s390-tools-sles15sp2-13-zkey-Cross-check-APQNs-when-changing-APQN-associatio.patch new file mode 100644 index 0000000..f78244b --- /dev/null +++ b/s390-tools-sles15sp2-13-zkey-Cross-check-APQNs-when-changing-APQN-associatio.patch @@ -0,0 +1,86 @@ +Subject: zkey: Cross check APQNs when changing APQN associations +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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) { diff --git a/s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch b/s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch new file mode 100644 index 0000000..5a208f2 --- /dev/null +++ b/s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch @@ -0,0 +1,455 @@ +Subject: zkey: Add function to select a specific CCA adapter +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 diff --git a/s390-tools-sles15sp2-15-zkey-Add-function-to-select-a-CCA-adapter-by-mkvp.patch b/s390-tools-sles15sp2-15-zkey-Add-function-to-select-a-CCA-adapter-by-mkvp.patch new file mode 100644 index 0000000..cb40529 --- /dev/null +++ b/s390-tools-sles15sp2-15-zkey-Add-function-to-select-a-CCA-adapter-by-mkvp.patch @@ -0,0 +1,162 @@ +Subject: zkey: Add function to select a CCA adapter by mkvp +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-16-zkey-Select-CCA-adapter-when-re-enciphering.patch b/s390-tools-sles15sp2-16-zkey-Select-CCA-adapter-when-re-enciphering.patch new file mode 100644 index 0000000..b9f6f7b --- /dev/null +++ b/s390-tools-sles15sp2-16-zkey-Select-CCA-adapter-when-re-enciphering.patch @@ -0,0 +1,397 @@ +Subject: zkey: Select CCA adapter when re-enciphering +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 + #include + ++#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; + } diff --git a/s390-tools-sles15sp2-17-zkey-cryptsetup-Add-to-new-and-from-old-options.patch b/s390-tools-sles15sp2-17-zkey-cryptsetup-Add-to-new-and-from-old-options.patch new file mode 100644 index 0000000..0758cf7 --- /dev/null +++ b/s390-tools-sles15sp2-17-zkey-cryptsetup-Add-to-new-and-from-old-options.patch @@ -0,0 +1,289 @@ +Subject: zkey-cryptsetup: Add --to-new and --from-old options +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-18-zkey-Display-key-type-with-list-and-validate-command.patch b/s390-tools-sles15sp2-18-zkey-Display-key-type-with-list-and-validate-command.patch new file mode 100644 index 0000000..45cf874 --- /dev/null +++ b/s390-tools-sles15sp2-18-zkey-Display-key-type-with-list-and-validate-command.patch @@ -0,0 +1,202 @@ +Subject: zkey: Display key type with list and validate commands +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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"); diff --git a/s390-tools-sles15sp2-19-zkey-Allow-to-filter-list-output-by-key-type.patch b/s390-tools-sles15sp2-19-zkey-Allow-to-filter-list-output-by-key-type.patch new file mode 100644 index 0000000..af776c3 --- /dev/null +++ b/s390-tools-sles15sp2-19-zkey-Allow-to-filter-list-output-by-key-type.patch @@ -0,0 +1,331 @@ +Subject: zkey: Allow to filter list output by key type +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-20-zkey-Allow-to-specify-the-key-type-with-the-generate.patch b/s390-tools-sles15sp2-20-zkey-Allow-to-specify-the-key-type-with-the-generate.patch new file mode 100644 index 0000000..dcc8d7a --- /dev/null +++ b/s390-tools-sles15sp2-20-zkey-Allow-to-specify-the-key-type-with-the-generate.patch @@ -0,0 +1,348 @@ +Subject: zkey: Allow to specify the key type with the generate command +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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) { diff --git a/s390-tools-sles15sp2-21-zkey-Preparations-for-introducing-a-new-key-type.patch b/s390-tools-sles15sp2-21-zkey-Preparations-for-introducing-a-new-key-type.patch new file mode 100644 index 0000000..a799ab8 --- /dev/null +++ b/s390-tools-sles15sp2-21-zkey-Preparations-for-introducing-a-new-key-type.patch @@ -0,0 +1,665 @@ +Subject: zkey: Preparations for introducing a new key type +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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, diff --git a/s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch b/s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch new file mode 100644 index 0000000..5e3df6c --- /dev/null +++ b/s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch @@ -0,0 +1,452 @@ +Subject: zkey: Introduce the CCA-AESCIPHER key type +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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, diff --git a/s390-tools-sles15sp2-23-zkey-Add-wrappers-for-the-new-IOCTLs-with-fallback-t.patch b/s390-tools-sles15sp2-23-zkey-Add-wrappers-for-the-new-IOCTLs-with-fallback-t.patch new file mode 100644 index 0000000..a79d97e --- /dev/null +++ b/s390-tools-sles15sp2-23-zkey-Add-wrappers-for-the-new-IOCTLs-with-fallback-t.patch @@ -0,0 +1,278 @@ +Subject: zkey: Add wrappers for the new IOCTLs with fallback to the old once +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch b/s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch new file mode 100644 index 0000000..f2cbd56 --- /dev/null +++ b/s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch @@ -0,0 +1,439 @@ +Subject: zkey: Add helper functions to build lists of APQNs +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-25-zkey-Add-support-for-generating-AES-CIPHER-keys.patch b/s390-tools-sles15sp2-25-zkey-Add-support-for-generating-AES-CIPHER-keys.patch new file mode 100644 index 0000000..ec41a28 --- /dev/null +++ b/s390-tools-sles15sp2-25-zkey-Add-support-for-generating-AES-CIPHER-keys.patch @@ -0,0 +1,542 @@ +Subject: zkey: Add support for generating AES CIPHER keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; + } diff --git a/s390-tools-sles15sp2-26-zkey-Add-support-for-validating-AES-CIPHER-keys.patch b/s390-tools-sles15sp2-26-zkey-Add-support-for-validating-AES-CIPHER-keys.patch new file mode 100644 index 0000000..a37e90d --- /dev/null +++ b/s390-tools-sles15sp2-26-zkey-Add-support-for-validating-AES-CIPHER-keys.patch @@ -0,0 +1,425 @@ +Subject: zkey: Add support for validating AES CIPHER keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-27-zkey-Add-support-for-re-enciphering-AES-CIPHER-keys.patch b/s390-tools-sles15sp2-27-zkey-Add-support-for-re-enciphering-AES-CIPHER-keys.patch new file mode 100644 index 0000000..970025a --- /dev/null +++ b/s390-tools-sles15sp2-27-zkey-Add-support-for-re-enciphering-AES-CIPHER-keys.patch @@ -0,0 +1,194 @@ +Subject: zkey: Add support for re-enciphering AES CIPHER keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-28-zkey-Check-crypto-card-level-during-APQN-cross-check.patch b/s390-tools-sles15sp2-28-zkey-Check-crypto-card-level-during-APQN-cross-check.patch new file mode 100644 index 0000000..e765c10 --- /dev/null +++ b/s390-tools-sles15sp2-28-zkey-Check-crypto-card-level-during-APQN-cross-check.patch @@ -0,0 +1,361 @@ +Subject: zkey: Check crypto card level during APQN cross checking +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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) { diff --git a/s390-tools-sles15sp2-29-zkey-Add-helper-function-to-query-the-CCA-firmware-v.patch b/s390-tools-sles15sp2-29-zkey-Add-helper-function-to-query-the-CCA-firmware-v.patch new file mode 100644 index 0000000..c95a443 --- /dev/null +++ b/s390-tools-sles15sp2-29-zkey-Add-helper-function-to-query-the-CCA-firmware-v.patch @@ -0,0 +1,101 @@ +Subject: zkey: Add helper function to query the CCA firmware version +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-30-zkey-Add-helper-function-to-convert-secure-keys-betw.patch b/s390-tools-sles15sp2-30-zkey-Add-helper-function-to-convert-secure-keys-betw.patch new file mode 100644 index 0000000..65da9e0 --- /dev/null +++ b/s390-tools-sles15sp2-30-zkey-Add-helper-function-to-convert-secure-keys-betw.patch @@ -0,0 +1,279 @@ +Subject: zkey: Add helper function to convert secure keys between key types +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-31-zkey-Add-helper-function-to-restrict-export-of-secur.patch b/s390-tools-sles15sp2-31-zkey-Add-helper-function-to-restrict-export-of-secur.patch new file mode 100644 index 0000000..a1742c8 --- /dev/null +++ b/s390-tools-sles15sp2-31-zkey-Add-helper-function-to-restrict-export-of-secur.patch @@ -0,0 +1,182 @@ +Subject: zkey: Add helper function to restrict export of secure keys +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-32-zkey-Add-helper-function-to-check-an-AES-CIPHER-key.patch b/s390-tools-sles15sp2-32-zkey-Add-helper-function-to-check-an-AES-CIPHER-key.patch new file mode 100644 index 0000000..467ad07 --- /dev/null +++ b/s390-tools-sles15sp2-32-zkey-Add-helper-function-to-check-an-AES-CIPHER-key.patch @@ -0,0 +1,192 @@ +Subject: zkey: Add helper function to check an AES CIPHER key +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 diff --git a/s390-tools-sles15sp2-33-zkey-Add-key-checks-when-importing-a-CCA-AESCIPHER-k.patch b/s390-tools-sles15sp2-33-zkey-Add-key-checks-when-importing-a-CCA-AESCIPHER-k.patch new file mode 100644 index 0000000..3e11e0a --- /dev/null +++ b/s390-tools-sles15sp2-33-zkey-Add-key-checks-when-importing-a-CCA-AESCIPHER-k.patch @@ -0,0 +1,225 @@ +Subject: zkey: Add key checks when importing a CCA-AESCIPHER key +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; + } diff --git a/s390-tools-sles15sp2-34-zkey-Add-convert-command-to-convert-keys-from-one-ty.patch b/s390-tools-sles15sp2-34-zkey-Add-convert-command-to-convert-keys-from-one-ty.patch new file mode 100644 index 0000000..3023efb --- /dev/null +++ b/s390-tools-sles15sp2-34-zkey-Add-convert-command-to-convert-keys-from-one-ty.patch @@ -0,0 +1,679 @@ +Subject: zkey: Add 'convert' command to convert keys from one type to another +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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 " ++ "--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 ' 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=\fP or run ++command \fBzkey crypttab --volumes \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 --master-key-file ++\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 diff --git a/s390-tools-sles15sp2-35-zkey-Allow-zkey-cryptsetup-setkey-to-set-different-k.patch b/s390-tools-sles15sp2-35-zkey-Allow-zkey-cryptsetup-setkey-to-set-different-k.patch new file mode 100644 index 0000000..8da0631 --- /dev/null +++ b/s390-tools-sles15sp2-35-zkey-Allow-zkey-cryptsetup-setkey-to-set-different-k.patch @@ -0,0 +1,63 @@ +Subject: zkey: Allow 'zkey-cryptsetup setkey' to set different key types +From: Ingo Franzki + +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 + Reviewed-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Ingo Franzki +--- + 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; diff --git a/s390-tools-sles15sp2-Close-file-descriptor-when-checking-for-read-only.patch b/s390-tools-sles15sp2-Close-file-descriptor-when-checking-for-read-only.patch new file mode 100644 index 0000000..188b54f --- /dev/null +++ b/s390-tools-sles15sp2-Close-file-descriptor-when-checking-for-read-only.patch @@ -0,0 +1,10 @@ +--- s390-tools-2.11.0/libdasd/dasd_ioctl.c 2019-09-06 08:13:09.000000000 -0400 ++++ s390-tools-2.11.0/libdasd/dasd_ioctl.c 2019-11-25 14:03:25.452391000 -0500 +@@ -149,6 +149,7 @@ + fd = dasd_open_device(device, O_RDWR); + RUN_IOCTL(fd, BLKROGET, &val); + *ro = (val != 0) ? true : false; ++ dasd_close_device(fd); + + return 0; + } diff --git a/s390-tools-sles15sp2-zcrypt-CEX7S-exploitation-support.patch b/s390-tools-sles15sp2-zcrypt-CEX7S-exploitation-support.patch new file mode 100644 index 0000000..7c1bcea --- /dev/null +++ b/s390-tools-sles15sp2-zcrypt-CEX7S-exploitation-support.patch @@ -0,0 +1,131 @@ +Subject: zcrypt: CEX7S exploitation support +From: Harald Freudenberger + +Summary: s390-tools: CEX7S exploitation support +Description: CEX7S exploitation support to lszcrypt, chzcrypt + and zcryptstats. +Upstream-ID: 4fc0c3cfefb8fb23a83ef629ac3f4a967fc0e77f +Problem-ID: SEC1808 + +Upstream-Description: + + zcrypt: CEX7S exploitation support + + This patch adds CEX7S exploitation support to lszcrypt and chzcrypt. + + Signed-off-by: Harald Freudenberger + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Harald Freudenberger +--- + zconf/zcrypt/chzcrypt.8 | 4 ++-- + zconf/zcrypt/chzcrypt.c | 4 ++-- + zconf/zcrypt/lszcrypt.8 | 8 ++++---- + zconf/zcrypt/lszcrypt.c | 11 ++++++----- + 4 files changed, 14 insertions(+), 13 deletions(-) + +--- a/zconf/zcrypt/chzcrypt.8 ++++ b/zconf/zcrypt/chzcrypt.8 +@@ -1,8 +1,8 @@ +-.\" Copyright 2017 IBM Corp. ++.\" Copyright 2019 IBM Corp. + .\" s390-tools is free software; you can redistribute it and/or modify + .\" it under the terms of the MIT license. See LICENSE for details. + .\" +-.TH CHZCRYPT 8 "OCT 2017" "s390-tools" ++.TH CHZCRYPT 8 "AUG 2019" "s390-tools" + .SH NAME + chzcrypt \- modify zcrypt configuration + .SH SYNOPSIS +--- a/zconf/zcrypt/chzcrypt.c ++++ b/zconf/zcrypt/chzcrypt.c +@@ -1,7 +1,7 @@ + /* + * chzcrypt - Tool to modify zcrypt configuration + * +- * Copyright IBM Corp. 2008, 2017 ++ * Copyright IBM Corp. 2008, 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. +@@ -47,7 +47,7 @@ const struct util_prg prg = { + { + .owner = "IBM Corp.", + .pub_first = 2008, +- .pub_last = 2017, ++ .pub_last = 2019, + }, + UTIL_PRG_COPYRIGHT_END + } +--- a/zconf/zcrypt/lszcrypt.8 ++++ b/zconf/zcrypt/lszcrypt.8 +@@ -1,6 +1,6 @@ + .\" lszcrypt.8 + .\" +-.\" Copyright 2017 IBM Corp. ++.\" Copyright 2019 IBM Corp. + .\" s390-tools is free software; you can redistribute it and/or modify + .\" it under the terms of the MIT license. See LICENSE for details. + .\" +@@ -10,7 +10,7 @@ + .\" nroff -man lszcrypt.8 + .\" to process this source + .\" +-.TH LSZCRYPT 8 "JAN 2019" "s390-tools" ++.TH LSZCRYPT 8 "AUG 2019" "s390-tools" + .SH NAME + lszcrypt \- display zcrypt device and configuration information + .SH SYNOPSIS +@@ -118,7 +118,7 @@ explanation: + .B TYPE and HWTYPE + The HWTYPE is a numeric value showing which type of hardware the zcrypt + device driver presumes that this crypto card is. The currently known values +-are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5 and 12=CEX6. ++are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6 and 13=CEX7. + .br + The TYPE is a human readable value showing the hardware type and the basic + function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So +@@ -167,7 +167,7 @@ operations within the guests. + .B DRIVER + .br + Shows which card or queue device driver currently handles this crypto +-resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX6 ++resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX7 + hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware), + cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved + for use by kvm hypervisor for kvm guests and not accessible to host +--- a/zconf/zcrypt/lszcrypt.c ++++ b/zconf/zcrypt/lszcrypt.c +@@ -1,7 +1,7 @@ + /** + * lszcrypt - Display zcrypt devices and configuration settings + * +- * Copyright IBM Corp. 2008, 2018 ++ * Copyright IBM Corp. 2008, 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. +@@ -86,7 +86,7 @@ const struct util_prg prg = { + { + .owner = "IBM Corp.", + .pub_first = 2008, +- .pub_last = 2018, ++ .pub_last = 2019, + }, + UTIL_PRG_COPYRIGHT_END + } +@@ -302,9 +302,10 @@ static void show_capability(const char * + printf("%s\n", CAP_CCA); + printf("%s", CAP_RNG); + break; +- case 10: +- case 11: +- case 12: ++ case 10: /* CEX4S */ ++ case 11: /* CEX5S */ ++ case 12: /* CEX6S */ ++ case 13: /* CEX7S */ + if (func_val & MASK_ACCEL) { + if (func_val & MASK_RSA4K) + printf("%s", CAP_RSA4K); diff --git a/s390-tools-sles15sp2-zcryptstats-Add-support-for-CEX7.patch b/s390-tools-sles15sp2-zcryptstats-Add-support-for-CEX7.patch new file mode 100644 index 0000000..dcd75c8 --- /dev/null +++ b/s390-tools-sles15sp2-zcryptstats-Add-support-for-CEX7.patch @@ -0,0 +1,78 @@ +Subject: zcryptstats: Add support for CEX7 +From: Harald Freudenberger + +Summary: s390-tools: CEX7S exploitation support +Description: CEX7S exploitation support to lszcrypt, chzcrypt + and zcryptstats. +Upstream-ID: e15e8a1bfa15e2179f30c6fe2e937ddd1a5e53c1 +Problem-ID: SEC1808 + +Upstream-Description: + + zcryptstats: Add support for CEX7 + + Add the CEX7 crypto card to the list of known crypto cards. + + Signed-off-by: Ingo Franzki + Signed-off-by: Jan Hoeppner + + +Signed-off-by: Harald Freudenberger +--- + zconf/zcrypt/zcryptstats.c | 23 +++++++++++++---------- + 1 file changed, 13 insertions(+), 10 deletions(-) + +--- a/zconf/zcrypt/zcryptstats.c ++++ b/zconf/zcrypt/zcryptstats.c +@@ -147,8 +147,9 @@ struct chsc_cmb_area { + #define CRYPTO_TYPE_CEX4S 10 + #define CRYPTO_TYPE_CEX5S 11 + #define CRYPTO_TYPE_CEX6S 12 ++#define CRYPTO_TYPE_CEX7S 13 + +-#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX6S ++#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX7S + + struct crypto_counter { + const char *name; +@@ -235,8 +236,8 @@ const struct crypto_mode mode_pcica[1] = + .counters = counter_pcica }, + }; + +-#define NUM_CEX456_MODES 11 +-const struct crypto_mode mode_cex456[NUM_CEX456_MODES] = { ++#define NUM_CEX4567_MODES 11 ++const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = { + { 0 }, + { 0 }, + { 0 }, +@@ -256,7 +257,7 @@ const struct crypto_mode mode_cex456[NUM + .counters = counter_ep11 }, + }; + +-#define NUM_CRYPTO_TYPES 13 ++#define NUM_CRYPTO_TYPES 14 + const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = { + { 0 }, + { 0 }, +@@ -275,12 +276,14 @@ const struct crypto_type crypto_types[NU + .modes = mode_accel }, + { .name = "CEX3C", .num_modes = NUM_COPROC_MODES, + .modes = mode_coproc }, +- { .name = "CEX4", .num_modes = NUM_CEX456_MODES, +- .modes = mode_cex456 }, +- { .name = "CEX5", .num_modes = NUM_CEX456_MODES, +- .modes = mode_cex456 }, +- { .name = "CEX6", .num_modes = NUM_CEX456_MODES, +- .modes = mode_cex456 }, ++ { .name = "CEX4", .num_modes = NUM_CEX4567_MODES, ++ .modes = mode_cex4567 }, ++ { .name = "CEX5", .num_modes = NUM_CEX4567_MODES, ++ .modes = mode_cex4567 }, ++ { .name = "CEX6", .num_modes = NUM_CEX4567_MODES, ++ .modes = mode_cex4567 }, ++ { .name = "CEX7", .num_modes = NUM_CEX4567_MODES, ++ .modes = mode_cex4567 }, + }; + + diff --git a/s390-tools.changes b/s390-tools.changes index 48e833b..905c259 100644 --- a/s390-tools.changes +++ b/s390-tools.changes @@ -1,6 +1,161 @@ +------------------------------------------------------------------- +Fri Oct 11 15:30:19 UTC 2019 - Mark Post + +- Upgraded to version 2.11.0 (jsc#7831) +- Updated the cputype script and read_values program to recognize + machine types up through the new z15. +- Added the following patches (bsc#1151859) + * s390-tools-sles15sp2-01-zkey-Separate-and-rework-CCA-host-library-loading.patch + * s390-tools-sles15sp2-02-zkey-Move-utility-functions-into-separate-source-fil.patch + * s390-tools-sles15sp2-03-zkey-Add-utility-function-to-get-the-serial-number-o.patch + * s390-tools-sles15sp2-04-zkey-Add-utility-function-to-get-the-mkvp-of-a-crypt.patch + * s390-tools-sles15sp2-05-zkey-add-function-to-iterate-over-all-available-CCA-.patch + * s390-tools-sles15sp2-06-zkey-Add-function-to-print-the-MKVPs-of-APQNs.patch + * s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch + * s390-tools-sles15sp2-08-zkey-Add-function-to-obtain-the-mkvp-of-a-secure-key.patch + * s390-tools-sles15sp2-09-zkey-Display-MKVP-when-validating-a-secure-key.patch + * s390-tools-sles15sp2-10-zkey-Cross-check-APQNs-when-generating-secure-keys.patch + * s390-tools-sles15sp2-11-zkey-Cross-check-APQNs-when-validating-secure-keys.patch + * s390-tools-sles15sp2-12-zkey-Cross-check-APQNs-when-importing-secure-keys.patch + * s390-tools-sles15sp2-13-zkey-Cross-check-APQNs-when-changing-APQN-associatio.patch + * s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch + * s390-tools-sles15sp2-15-zkey-Add-function-to-select-a-CCA-adapter-by-mkvp.patch + * s390-tools-sles15sp2-16-zkey-Select-CCA-adapter-when-re-enciphering.patch + * s390-tools-sles15sp2-17-zkey-cryptsetup-Add-to-new-and-from-old-options.patch +- Added the following patches (bsc#1151858) + * s390-tools-sles15sp2-18-zkey-Display-key-type-with-list-and-validate-command.patch + * s390-tools-sles15sp2-19-zkey-Allow-to-filter-list-output-by-key-type.patch + * s390-tools-sles15sp2-20-zkey-Allow-to-specify-the-key-type-with-the-generate.patch + * s390-tools-sles15sp2-21-zkey-Preparations-for-introducing-a-new-key-type.patch + * s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch + * s390-tools-sles15sp2-23-zkey-Add-wrappers-for-the-new-IOCTLs-with-fallback-t.patch + * s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch + * s390-tools-sles15sp2-25-zkey-Add-support-for-generating-AES-CIPHER-keys.patch + * s390-tools-sles15sp2-26-zkey-Add-support-for-validating-AES-CIPHER-keys.patch + * s390-tools-sles15sp2-27-zkey-Add-support-for-re-enciphering-AES-CIPHER-keys.patch + * s390-tools-sles15sp2-28-zkey-Check-crypto-card-level-during-APQN-cross-check.patch + * s390-tools-sles15sp2-29-zkey-Add-helper-function-to-query-the-CCA-firmware-v.patch + * s390-tools-sles15sp2-30-zkey-Add-helper-function-to-convert-secure-keys-betw.patch + * s390-tools-sles15sp2-31-zkey-Add-helper-function-to-restrict-export-of-secur.patch + * s390-tools-sles15sp2-32-zkey-Add-helper-function-to-check-an-AES-CIPHER-key.patch + * s390-tools-sles15sp2-33-zkey-Add-key-checks-when-importing-a-CCA-AESCIPHER-k.patch + * s390-tools-sles15sp2-34-zkey-Add-convert-command-to-convert-keys-from-one-ty.patch + * s390-tools-sles15sp2-35-zkey-Allow-zkey-cryptsetup-setkey-to-set-different-k.patch +- Added the following patches (bsc#1153757) + * s390-tools-sles15sp2-zcrypt-CEX7S-exploitation-support.patch + * s390-tools-sles15sp2-zcryptstats-Add-support-for-CEX7.patch +- Added s390-tools-sles15sp2-Close-file-descriptor-when-checking-for-read-only.patch +- Forward-ported the following patches to work with the restructuring IBM did for + this version + * dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch + * s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch + * s390-tools-sles15-Allow-multiple-device-arguments.patch + * s390-tools-sles15-Format-devices-in-parallel.patch + * s390-tools-sles15-Implement-f-for-backwards-compability.patch + * s390-tools-sles15-Implement-Y-yast_mode.patch +- Removed the following obsolete patches: + * s390-tools-sles15-1-lstape-fix-output-with-SCSI-lin_tape-and-multiple-pa.patch + * s390-tools-sles15-2-lstape-fix-to-prefer-sysfs-to-find-lin_tape-device-n.patch + * s390-tools-sles15-3-lstape-fix-output-without-SCSI-generic-sg.patch + * s390-tools-sles15-4-lsluns-fix-to-prevent-error-messages-if-there-are-no.patch + * s390-tools-sles15-5-lstape-fix-to-prevent-error-messages-if-there-are-no.patch + * s390-tools-sles15-6-lstape-fix-description-of-type-and-devbusid-filter-f.patch + * s390-tools-sles15-7-lstape-fix-SCSI-output-description-in-man-page.patch + * s390-tools-sles15-8-lstape-fix-SCSI-HBA-CCW-device-bus-ID-e.g.-for-virti.patch + * s390-tools-sles15-cpi-add-unit-install-section.patch + * s390-tools-sles15-cpuplugd-Improve-systemctl-start-error-handling.patch + * s390-tools-sles15-dbginfo-add-data-for-ps-cpprot.patch + * s390-tools-sles15-Drop-device_id-parameter.patch + * s390-tools-sles15-Fix-truncation-warning.patch + * s390-tools-sles15-Fixup-dasdfmt_get_volser.patch + * s390-tools-sles15-Fixup-device-name-handling.patch + * s390-tools-sles15-hmcdrvfs-fix-parsing-of-link-count.patch + * s390-tools-sles15-iucvterm-include-ctype-for-toupper.patch + * s390-tools-sles15-lsluns-clarify-discovery-use-case-relation-to-NPIV-a.patch + * s390-tools-sles15-lsluns-complement-alternative-tools-with-lszdev.patch + * s390-tools-sles15-lsluns-document-restriction-to-zfcp-only-systems.patch + * s390-tools-sles15-lsluns-do-not-print-confusing-messages-when-a-filter.patch + * s390-tools-sles15-lsluns-do-not-scan-all-if-filters-match-nothing.patch + * s390-tools-sles15-lsluns-enhance-usage-statement-and-man-page.patch + * s390-tools-sles15-lsluns-fix-flawed-formatting-of-man-page.patch + * s390-tools-sles15-lsluns-point-out-IBM-Storwize-configuration-requirem.patch + * s390-tools-sles15-mon_procd-fix-parsing-of-proc-pid-stat.patch + * s390-tools-sles15-mon_tools-Improve-systemctl-start-error-handling.patch + * s390-tools-sles15sp1-0001-zkey-Add-properties-file-handling-routines.patch + * s390-tools-sles15sp1-0002-zkey-Add-build-dependency-to-OpenSSL-libcrypto.patch + * s390-tools-sles15sp1-0003-zkey-Add-helper-functions-for-comma-separated-string.patch + * s390-tools-sles15sp1-0004-zkey-Externalize-secure-key-back-end-functions.patch + * s390-tools-sles15sp1-0005-zkey-Add-keystore-implementation.patch + * s390-tools-sles15sp1-0006-zkey-Add-keystore-related-commands.patch + * s390-tools-sles15sp1-0007-zkey-Create-key-repository-and-group-during-make-ins.patch + * s390-tools-sles15sp1-0008-zkey-Man-page-updates.patch + * s390-tools-sles15sp1-0009-zkey-let-packaging-create-the-zkeyadm-group-and-perm.patch + * s390-tools-sles15sp1-0010-zkey-Update-README-to-add-info-about-packaging-requi.patch + * s390-tools-sles15sp1-0011-zkey-Typo-in-message.patch + * s390-tools-sles15sp1-0012-zkey-Fix-memory-leak.patch + * s390-tools-sles15sp1-0013-zkey-Fix-APQN-validation-routine.patch + * s390-tools-sles15sp1-0014-zkey-Fix-generate-and-import-leaving-key-in-an-incon.patch + * s390-tools-sles15sp1-0015-zkey-Add-zkey-cryptsetup-tool.patch + * s390-tools-sles15sp1-0016-zkey-Add-man-page-for-zkey-cryptsetup.patch + * s390-tools-sles15sp1-0017-zkey-Add-build-dependency-for-libcryptsetup-and-json.patch + * s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch + * s390-tools-sles15sp1-0019-zkey-Add-volume-type-property-to-support-LUKS2-volum.patch + * s390-tools-sles15sp1-01-chzcrypt-Corrections-at-the-chzcrypt-man-page.patch + * s390-tools-sles15sp1-01-cpumf-Add-extended-counter-defintion-files-for-IBM-z.patch + * s390-tools-sles15sp1-01-lszcrypt-CEX6S-exploitation.patch + * s390-tools-sles15sp1-01-util_path-add-function-to-check-if-a-path-exists.patch + * s390-tools-sles15sp1-01-zcryptctl-new-tool-zcryptctl-for-multiple-zcrypt-node.patch + * s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch + * s390-tools-sles15sp1-01-zkey-Include-sbin-into-PATH-when-executing-commands.patch + * s390-tools-sles15sp1-02-cpumf-z14-split-counter-sets-according-to-CFVN-CSVN-.patch + * s390-tools-sles15sp1-02-lszcrypt-fix-date-and-wrong-indentation.patch + * s390-tools-sles15sp1-02-lszcrypt-support-for-alternate-zcrypt-device-drivers.patch + * s390-tools-sles15sp1-02-util_path-Add-description-for-util_path_exists.patch + * s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch + * s390-tools-sles15sp1-03-cpumf-cpumf_helper-read-split-counter-sets-part-2-2.patch + * s390-tools-sles15sp1-03-util_path-Make-true-false-handling-consistent-with-o.patch + * s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch + * s390-tools-sles15sp1-04-cpumf-correct-z14-counter-number.patch + * s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch + * s390-tools-sles15sp1-04-zpcictl-Introduce-new-tool-zpcictl.patch + * s390-tools-sles15sp1-05-cpumf-add-missing-Description-tag-for-z13-z14-ctr-12.patch + * s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch + * s390-tools-sles15sp1-05-zpcictl-include-sys-sysmacros.h-to-avoid-minor-major.patch + * s390-tools-sles15sp1-06-cpumf-correct-counter-name-for-z13-and-z14.patch + * s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch + * s390-tools-sles15sp1-06-zpcictl-Rephrase-man-page-entries-and-tool-output.patch + * s390-tools-sles15sp1-07-cpumf-Add-IBM-z14-ZR1-to-the-CPU-Measurement-Facilit.patch + * s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch + * s390-tools-sles15sp1-07-zpcictl-Use-fopen-instead-of-open-for-writes.patch + * s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch + * s390-tools-sles15sp1-08-zpcictl-Read-device-link-to-obtain-device-address.patch + * s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch + * s390-tools-sles15sp1-09-zpcictl-Make-device-node-for-NVMe-optional.patch + * s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch + * s390-tools-sles15sp1-10-zpcictl-Change-wording-of-man-page-and-help-output.patch + * s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch + * s390-tools-sles15sp1-dbginfo-gather-nvme-related-data.patch + * s390-tools-sles15sp1-qethqoat-add-OSA-Express7S-support.patch + * s390-tools-sles15sp1-zcrypt-refine-lszcrypt-man-page.patch + * s390-tools-sles15sp1-zdev-Also-include-the-ctc-driver-in-the-initrd.patch + * s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch + * s390-tools-sles15sp1-zkey-Enhance-error-message-about-missing-CCA-library.patch + * s390-tools-sles15-zdev-Enable-running-chzdev-from-unknown-root-devices.patch + * s390-tools-sles15-zdev-Fix-zdev-dracut-module-aborting-on-unknown-root.patch + * s390-tools-sles15-zdev-Use-correct-path-to-vmcp-binary.patch + * s390-tools-sles15-ziomon-re-add-missing-line.patch + * s390-tools-sles15-zipl-remove-invalid-dasdview-command-line-option.patch + +------------------------------------------------------------------- +Mon Jul 22 18:27:28 UTC 2019 - Mark Post + +- Added s390-tools-sles15sp1-ziomon-fix-utilization-data-recording-with-multi-dig.patch + ziomon: fix utilization recording with multi-digit scsi hosts + (bsc#1141876) + ------------------------------------------------------------------- Thu Feb 21 19:38:18 UTC 2019 - mpost@suse.com - + - Now that IBM has the package on github, use a full source URL. - Change Pre-Req to Requires(pre) and (post), and remove dracut. - Changed the group for the hmcdrvfs package from Base:System to @@ -3139,4 +3294,3 @@ Fri Jul 13 18:31:30 CEST 2001 - mls@suse.de Fri Jul 13 16:15:33 CEST 2001 - bk@suse.de - new package based on s390utils - diff --git a/s390-tools.spec b/s390-tools.spec index 082984f..51623a6 100644 --- a/s390-tools.spec +++ b/s390-tools.spec @@ -22,7 +22,7 @@ %endif Name: s390-tools -Version: 2.1.0 +Version: 2.11.0 Release: 0 Summary: S/390 tools like zipl and dasdfmt License: MIT @@ -86,108 +86,57 @@ Source98: zfcp_disk_configure.8 Source99: zfcp_host_configure.8 ### -Patch1: s390-tools-sles12-zipl_boot_msg.patch -Patch2: s390-tools-sles12-sysconfig-compatible-dumpconf.patch -Patch3: s390-tools-sles12-create-filesystem-links.patch -Patch4: s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch -Patch5: s390-tools-sles15-Fixup-dasdfmt_get_volser.patch -Patch6: s390-tools-sles15-Fixup-device-name-handling.patch -Patch7: s390-tools-sles15-Drop-device_id-parameter.patch -Patch8: s390-tools-sles15-Allow-multiple-device-arguments.patch -Patch9: s390-tools-sles15-Format-devices-in-parallel.patch -Patch10: s390-tools-sles15-Implement-Y-yast_mode.patch -Patch11: s390-tools-sles15-Implement-f-for-backwards-compability.patch -Patch12: dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch -Patch13: 59-dasd.rules-wait_for.patch -Patch14: s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch -Patch15: s390-tools-sles15-Fix-truncation-warning.patch -Patch16: s390-tools-sles15-iucvterm-include-ctype-for-toupper.patch -Patch17: s390-tools-sles15-zdev-Use-correct-path-to-vmcp-binary.patch -Patch18: s390-tools-sles15-cpi-add-unit-install-section.patch -Patch19: s390-tools-sles15-zipl-remove-invalid-dasdview-command-line-option.patch -Patch20: s390-tools-sles15-ziomon-re-add-missing-line.patch -Patch21: s390-tools-sles15-cpuplugd-Improve-systemctl-start-error-handling.patch -Patch22: s390-tools-sles15-mon_tools-Improve-systemctl-start-error-handling.patch -Patch23: s390-tools-sles15-lsluns-do-not-scan-all-if-filters-match-nothing.patch -Patch24: s390-tools-sles15-lsluns-do-not-print-confusing-messages-when-a-filter.patch -Patch25: s390-tools-sles15-lsluns-fix-flawed-formatting-of-man-page.patch -Patch26: s390-tools-sles15-lsluns-enhance-usage-statement-and-man-page.patch -Patch27: s390-tools-sles15-lsluns-clarify-discovery-use-case-relation-to-NPIV-a.patch -Patch28: s390-tools-sles15-lsluns-point-out-IBM-Storwize-configuration-requirem.patch -Patch29: s390-tools-sles15-lsluns-document-restriction-to-zfcp-only-systems.patch -Patch30: s390-tools-sles15-lsluns-complement-alternative-tools-with-lszdev.patch -Patch31: s390-tools-sles15-zdev-Enable-running-chzdev-from-unknown-root-devices.patch -Patch32: s390-tools-sles15-zdev-Fix-zdev-dracut-module-aborting-on-unknown-root.patch -Patch33: s390-tools-sles15-hmcdrvfs-fix-parsing-of-link-count.patch -Patch34: s390-tools-sles15-dbginfo-add-data-for-ps-cpprot.patch -Patch35: s390-tools-sles15-mon_procd-fix-parsing-of-proc-pid-stat.patch -Patch36: s390-tools-sles15-1-lstape-fix-output-with-SCSI-lin_tape-and-multiple-pa.patch -Patch37: s390-tools-sles15-2-lstape-fix-to-prefer-sysfs-to-find-lin_tape-device-n.patch -Patch38: s390-tools-sles15-3-lstape-fix-output-without-SCSI-generic-sg.patch -Patch39: s390-tools-sles15-4-lsluns-fix-to-prevent-error-messages-if-there-are-no.patch -Patch40: s390-tools-sles15-5-lstape-fix-to-prevent-error-messages-if-there-are-no.patch -Patch41: s390-tools-sles15-6-lstape-fix-description-of-type-and-devbusid-filter-f.patch -Patch42: s390-tools-sles15-7-lstape-fix-SCSI-output-description-in-man-page.patch -Patch43: s390-tools-sles15-8-lstape-fix-SCSI-HBA-CCW-device-bus-ID-e.g.-for-virti.patch -Patch44: s390-tools-sles15sp1-0001-zkey-Add-properties-file-handling-routines.patch -Patch45: s390-tools-sles15sp1-0002-zkey-Add-build-dependency-to-OpenSSL-libcrypto.patch -Patch46: s390-tools-sles15sp1-0003-zkey-Add-helper-functions-for-comma-separated-string.patch -Patch47: s390-tools-sles15sp1-0004-zkey-Externalize-secure-key-back-end-functions.patch -Patch48: s390-tools-sles15sp1-0005-zkey-Add-keystore-implementation.patch -Patch49: s390-tools-sles15sp1-0006-zkey-Add-keystore-related-commands.patch -Patch50: s390-tools-sles15sp1-0007-zkey-Create-key-repository-and-group-during-make-ins.patch -Patch51: s390-tools-sles15sp1-0008-zkey-Man-page-updates.patch -Patch52: s390-tools-sles15sp1-0009-zkey-let-packaging-create-the-zkeyadm-group-and-perm.patch -Patch53: s390-tools-sles15sp1-0010-zkey-Update-README-to-add-info-about-packaging-requi.patch -Patch54: s390-tools-sles15sp1-0011-zkey-Typo-in-message.patch -Patch55: s390-tools-sles15sp1-0012-zkey-Fix-memory-leak.patch -Patch56: s390-tools-sles15sp1-0013-zkey-Fix-APQN-validation-routine.patch -Patch57: s390-tools-sles15sp1-0014-zkey-Fix-generate-and-import-leaving-key-in-an-incon.patch -Patch58: s390-tools-sles15sp1-0015-zkey-Add-zkey-cryptsetup-tool.patch -Patch59: s390-tools-sles15sp1-0016-zkey-Add-man-page-for-zkey-cryptsetup.patch -Patch60: s390-tools-sles15sp1-0017-zkey-Add-build-dependency-for-libcryptsetup-and-json.patch -Patch61: s390-tools-sles15sp1-0018-zkey-Add-key-verification-pattern-property.patch -Patch62: s390-tools-sles15sp1-0019-zkey-Add-volume-type-property-to-support-LUKS2-volum.patch -Patch63: s390-tools-sles15sp1-01-lszcrypt-CEX6S-exploitation.patch -Patch64: s390-tools-sles15sp1-02-lszcrypt-fix-date-and-wrong-indentation.patch -Patch65: s390-tools-sles15sp1-01-chzcrypt-Corrections-at-the-chzcrypt-man-page.patch -Patch66: s390-tools-sles15sp1-02-lszcrypt-support-for-alternate-zcrypt-device-drivers.patch -Patch67: s390-tools-sles15sp1-01-zcryptctl-new-tool-zcryptctl-for-multiple-zcrypt-node.patch -Patch68: s390-tools-sles15sp1-01-cpumf-Add-extended-counter-defintion-files-for-IBM-z.patch -Patch69: s390-tools-sles15sp1-02-cpumf-z14-split-counter-sets-according-to-CFVN-CSVN-.patch -Patch70: s390-tools-sles15sp1-03-cpumf-cpumf_helper-read-split-counter-sets-part-2-2.patch -Patch71: s390-tools-sles15sp1-04-cpumf-correct-z14-counter-number.patch -Patch72: s390-tools-sles15sp1-05-cpumf-add-missing-Description-tag-for-z13-z14-ctr-12.patch -Patch73: s390-tools-sles15sp1-06-cpumf-correct-counter-name-for-z13-and-z14.patch -Patch74: s390-tools-sles15sp1-07-cpumf-Add-IBM-z14-ZR1-to-the-CPU-Measurement-Facilit.patch -Patch75: s390-tools-sles15sp1-01-util_path-add-function-to-check-if-a-path-exists.patch -Patch76: s390-tools-sles15sp1-02-util_path-Add-description-for-util_path_exists.patch -Patch77: s390-tools-sles15sp1-03-util_path-Make-true-false-handling-consistent-with-o.patch -Patch78: s390-tools-sles15sp1-04-zpcictl-Introduce-new-tool-zpcictl.patch -Patch79: s390-tools-sles15sp1-05-zpcictl-include-sys-sysmacros.h-to-avoid-minor-major.patch -Patch80: s390-tools-sles15sp1-06-zpcictl-Rephrase-man-page-entries-and-tool-output.patch -Patch81: s390-tools-sles15sp1-07-zpcictl-Use-fopen-instead-of-open-for-writes.patch -Patch82: s390-tools-sles15sp1-08-zpcictl-Read-device-link-to-obtain-device-address.patch -Patch83: s390-tools-sles15sp1-09-zpcictl-Make-device-node-for-NVMe-optional.patch -Patch84: s390-tools-sles15sp1-10-zpcictl-Change-wording-of-man-page-and-help-output.patch -Patch85: s390-tools-sles15sp1-dbginfo-gather-nvme-related-data.patch -Patch86: s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch -Patch87: s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch -Patch88: s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch -Patch89: s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch -Patch90: s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch -Patch91: s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch -Patch92: s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch -Patch93: s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch -Patch94: s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch -Patch95: s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch -Patch96: s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch -Patch97: s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch -Patch98: s390-tools-sles15sp1-qethqoat-add-OSA-Express7S-support.patch -Patch99: s390-tools-sles15sp1-01-zkey-Include-sbin-into-PATH-when-executing-commands.patch -Patch100: s390-tools-sles15sp1-zkey-Enhance-error-message-about-missing-CCA-library.patch -Patch101: s390-tools-sles15sp1-zdev-Also-include-the-ctc-driver-in-the-initrd.patch -Patch102: s390-tools-sles15sp1-zcrypt-refine-lszcrypt-man-page.patch +Patch1: s390-tools-sles15sp2-01-zkey-Separate-and-rework-CCA-host-library-loading.patch +Patch2: s390-tools-sles15sp2-02-zkey-Move-utility-functions-into-separate-source-fil.patch +Patch3: s390-tools-sles15sp2-03-zkey-Add-utility-function-to-get-the-serial-number-o.patch +Patch4: s390-tools-sles15sp2-04-zkey-Add-utility-function-to-get-the-mkvp-of-a-crypt.patch +Patch5: s390-tools-sles15sp2-05-zkey-add-function-to-iterate-over-all-available-CCA-.patch +Patch6: s390-tools-sles15sp2-06-zkey-Add-function-to-print-the-MKVPs-of-APQNs.patch +Patch7: s390-tools-sles15sp2-07-zkey-Add-function-to-cross-check-APQNs-for-valid-mas.patch +Patch8: s390-tools-sles15sp2-08-zkey-Add-function-to-obtain-the-mkvp-of-a-secure-key.patch +Patch9: s390-tools-sles15sp2-09-zkey-Display-MKVP-when-validating-a-secure-key.patch +Patch10: s390-tools-sles15sp2-10-zkey-Cross-check-APQNs-when-generating-secure-keys.patch +Patch11: s390-tools-sles15sp2-11-zkey-Cross-check-APQNs-when-validating-secure-keys.patch +Patch12: s390-tools-sles15sp2-12-zkey-Cross-check-APQNs-when-importing-secure-keys.patch +Patch13: s390-tools-sles15sp2-13-zkey-Cross-check-APQNs-when-changing-APQN-associatio.patch +Patch14: s390-tools-sles15sp2-14-zkey-Add-function-to-select-a-specific-CCA-adapter.patch +Patch15: s390-tools-sles15sp2-15-zkey-Add-function-to-select-a-CCA-adapter-by-mkvp.patch +Patch16: s390-tools-sles15sp2-16-zkey-Select-CCA-adapter-when-re-enciphering.patch +Patch17: s390-tools-sles15sp2-17-zkey-cryptsetup-Add-to-new-and-from-old-options.patch +Patch18: s390-tools-sles15sp2-18-zkey-Display-key-type-with-list-and-validate-command.patch +Patch19: s390-tools-sles15sp2-19-zkey-Allow-to-filter-list-output-by-key-type.patch +Patch20: s390-tools-sles15sp2-20-zkey-Allow-to-specify-the-key-type-with-the-generate.patch +Patch21: s390-tools-sles15sp2-21-zkey-Preparations-for-introducing-a-new-key-type.patch +Patch22: s390-tools-sles15sp2-22-zkey-Introduce-the-CCA-AESCIPHER-key-type.patch +Patch23: s390-tools-sles15sp2-23-zkey-Add-wrappers-for-the-new-IOCTLs-with-fallback-t.patch +Patch24: s390-tools-sles15sp2-24-zkey-Add-helper-functions-to-build-lists-of-APQNs.patch +Patch25: s390-tools-sles15sp2-25-zkey-Add-support-for-generating-AES-CIPHER-keys.patch +Patch26: s390-tools-sles15sp2-26-zkey-Add-support-for-validating-AES-CIPHER-keys.patch +Patch27: s390-tools-sles15sp2-27-zkey-Add-support-for-re-enciphering-AES-CIPHER-keys.patch +Patch28: s390-tools-sles15sp2-28-zkey-Check-crypto-card-level-during-APQN-cross-check.patch +Patch29: s390-tools-sles15sp2-29-zkey-Add-helper-function-to-query-the-CCA-firmware-v.patch +Patch30: s390-tools-sles15sp2-30-zkey-Add-helper-function-to-convert-secure-keys-betw.patch +Patch31: s390-tools-sles15sp2-31-zkey-Add-helper-function-to-restrict-export-of-secur.patch +Patch32: s390-tools-sles15sp2-32-zkey-Add-helper-function-to-check-an-AES-CIPHER-key.patch +Patch33: s390-tools-sles15sp2-33-zkey-Add-key-checks-when-importing-a-CCA-AESCIPHER-k.patch +Patch34: s390-tools-sles15sp2-34-zkey-Add-convert-command-to-convert-keys-from-one-ty.patch +Patch35: s390-tools-sles15sp2-35-zkey-Allow-zkey-cryptsetup-setkey-to-set-different-k.patch +Patch36: s390-tools-sles15sp2-zcrypt-CEX7S-exploitation-support.patch +Patch37: s390-tools-sles15sp2-zcryptstats-Add-support-for-CEX7.patch + +# SUSE patches +Patch900: s390-tools-sles12-zipl_boot_msg.patch +Patch901: s390-tools-sles12-sysconfig-compatible-dumpconf.patch +Patch902: s390-tools-sles12-create-filesystem-links.patch +Patch903: s390-tools-sles12-update-by_id-links-on-change-and-add-action.patch +Patch904: s390-tools-sles15-Allow-multiple-device-arguments.patch +Patch905: s390-tools-sles15-Format-devices-in-parallel.patch +Patch906: s390-tools-sles15-Implement-Y-yast_mode.patch +Patch907: s390-tools-sles15-Implement-f-for-backwards-compability.patch +Patch908: dasdfmt-retry-BIODASDINFO-if-device-is-busy.patch +Patch909: 59-dasd.rules-wait_for.patch +Patch910: s390-tools-sles12-fdasd-skip-partition-check-and-BLKRRPART-ioctl.patch +Patch911: s390-tools-sles15sp2-Close-file-descriptor-when-checking-for-read-only.patch BuildRequires: dracut BuildRequires: fuse-devel @@ -286,13 +235,22 @@ gcc -static -o read_values ${OPT_FLAGS} %{SOURCE86} -lqc %install mkdir -p %{buildroot}/boot/zipl -mkdir -p %{buildroot}%{_sysconfdir}//zkey/repository +mkdir -p %{buildroot}%{_sysconfdir}/zkey/repository %make_install \ ZFCPDUMP_DIR=%{_prefix}/lib/s390-tools/zfcpdump \ DISTRELEASE=%{release} \ SYSTEMDSYSTEMUNITDIR=%{_unitdir} \ HAVE_DRACUT=1 +# The make install command puts things in /etc/sysconfig and not the +# fillup-templates directory. Let's try moving them where they belong +mkdir -p %{buildroot}%{_fillupdir} +pushd %{buildroot}%{_sysconfdir}/sysconfig/ +for sysconffile in * + do mv -vi $sysconffile %{buildroot}%{_fillupdir}/sysconfig.$sysconffile + done +popd + install -m 755 read_values %{buildroot}/%{_bindir}/ install -m644 -t %{buildroot}/%{_mandir}/man8 %{SOURCE87} @@ -304,10 +262,6 @@ install -D -m644 etc/udev/rules.d/40-z90crypt.rules %{buildroot}%{_prefix}/lib/u install -D -m644 etc/udev/rules.d/57-osasnmpd.rules %{buildroot}%{_prefix}/lib/udev/rules.d/57-osasnmpd.rules install -D -m644 etc/udev/rules.d/59-dasd.rules %{buildroot}%{_prefix}/lib/udev/rules.d/59-dasd.rules install -D -m644 etc/udev/rules.d/90-cpi.rules %{buildroot}%{_prefix}/lib/udev/rules.d/90-cpi.rules -install -D -m644 etc/sysconfig/cpi %{buildroot}%{_fillupdir}/sysconfig.cpi -install -D -m644 etc/sysconfig/dumpconf %{buildroot}%{_fillupdir}/sysconfig.dumpconf -install -D -m644 etc/sysconfig/mon_fsstatd %{buildroot}%{_fillupdir}/sysconfig.mon_fsstatd -install -D -m644 etc/sysconfig/mon_procd %{buildroot}%{_fillupdir}/sysconfig.mon_procd mv iucvterm/doc/ts-shell/iucvconn_on_login %{buildroot}%{_bindir}/iucvconn_on_login install -D -m644 %{SOURCE26} %{buildroot}/%{_unitdir}/cio_ignore.service install -D -m755 %{SOURCE27} %{buildroot}%{_prefix}/lib/systemd/scripts/setup_cio_ignore.sh @@ -368,7 +322,7 @@ if [ ! -d %{_bindir} ]; then rm -f %{_bindir} mkdir -p %{_bindir} fi -install -D -m755 %{SOURCE24} usr/bin/cputype +install -D -m755 %{SOURCE24} %{buildroot}%{_bindir}/cputype install -m644 -t %{buildroot}/%{_mandir}/man8 %{SOURCE25}