From: Thomas Huth <thuth@redhat.com>
To: Zhuoying Cai <zycai@linux.ibm.com>,
richard.henderson@linaro.org, david@redhat.com,
pbonzini@redhat.com
Cc: walling@linux.ibm.com, jjherne@linux.ibm.com,
jrossi@linux.ibm.com, fiuczy@linux.ibm.com, pasic@linux.ibm.com,
borntraeger@linux.ibm.com, farman@linux.ibm.com,
iii@linux.ibm.com, qemu-s390x@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [PATCH v2 17/25] pc-bios/s390-ccw: Add signature verification for secure IPL in audit mode
Date: Tue, 20 May 2025 12:25:20 +0200 [thread overview]
Message-ID: <53616ccd-3fb5-41e9-bd6a-0a0243b1a392@redhat.com> (raw)
In-Reply-To: <20250508225042.313672-18-zycai@linux.ibm.com>
On 09/05/2025 00.50, Zhuoying Cai wrote:
> Enable secure IPL in audit mode, which performs signature verification,
> but any error does not terminate the boot process. Only warnings will be
> logged to the console instead.
>
> Add a comp_len variable to store the length of a segment in
> zipl_load_segment. comp_len variable is necessary to store the
> calculated segment length and is used during signature verification.
> Return the length on success, or a negative return code on failure.
>
> Secure IPL in audit mode requires at least one certificate provided in
> the key store along with necessary facilities (Secure IPL Facility,
> Certificate Store Facility and secure IPL extension support).
>
> Note: Secure IPL in audit mode is implemented for the SCSI scheme of
> virtio-blk/virtio-scsi devices.
>
> Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
> ---
> pc-bios/s390-ccw/Makefile | 3 +-
> pc-bios/s390-ccw/bootmap.c | 192 +++++++++++++++++++++++++++++++++-
> pc-bios/s390-ccw/bootmap.h | 9 ++
> pc-bios/s390-ccw/main.c | 9 ++
> pc-bios/s390-ccw/s390-ccw.h | 14 +++
> pc-bios/s390-ccw/sclp.c | 44 ++++++++
> pc-bios/s390-ccw/sclp.h | 6 ++
> pc-bios/s390-ccw/secure-ipl.c | 175 +++++++++++++++++++++++++++++++
> pc-bios/s390-ccw/secure-ipl.h | 109 +++++++++++++++++++
> 9 files changed, 558 insertions(+), 3 deletions(-)
> create mode 100644 pc-bios/s390-ccw/secure-ipl.c
> create mode 100644 pc-bios/s390-ccw/secure-ipl.h
>
> diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
> index dc69dd484f..fedb89a387 100644
> --- a/pc-bios/s390-ccw/Makefile
> +++ b/pc-bios/s390-ccw/Makefile
> @@ -34,7 +34,8 @@ QEMU_DGFLAGS = -MMD -MP -MT $@ -MF $(@D)/$(*F).d
> .PHONY : all clean build-all distclean
>
> OBJECTS = start.o main.o bootmap.o jump2ipl.o sclp.o menu.o netmain.o \
> - virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o
> + virtio.o virtio-net.o virtio-scsi.o virtio-blkdev.o cio.o dasd-ipl.o \
> + secure-ipl.o
>
> SLOF_DIR := $(SRC_PATH)/../../roms/SLOF
>
> diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
> index 3dd09fda7e..06cea0929a 100644
> --- a/pc-bios/s390-ccw/bootmap.c
> +++ b/pc-bios/s390-ccw/bootmap.c
> @@ -15,6 +15,7 @@
> #include "bootmap.h"
> #include "virtio.h"
> #include "bswap.h"
> +#include "secure-ipl.h"
>
> #ifdef DEBUG
> /* #define DEBUG_FALLBACK */
> @@ -34,6 +35,13 @@ static uint8_t sec[MAX_SECTOR_SIZE*4] __attribute__((__aligned__(PAGE_SIZE)));
> const uint8_t el_torito_magic[] = "EL TORITO SPECIFICATION"
> "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
>
> +/* sector for storing certificates */
> +static uint8_t certs_sec[CERT_MAX_SIZE * MAX_CERTIFICATES];
If I calculated correctly, that's a buffer of 512 kB... That's quite huge
already. Would it be possible to malloc() it only if we really need this
instead of statically allocating it?
> +/* sector for storing signatures */
> +static uint8_t sig_sec[MAX_SECTOR_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
> +
> +ipl_print_func_t zipl_secure_print_func;
> +
> /*
> * Match two CCWs located after PSW and eight filler bytes.
> * From libmagic and arch/s390/kernel/head.S.
> @@ -676,6 +684,155 @@ static int zipl_load_segment(ComponentEntry *entry, uint64_t address)
> return comp_len;
> }
>
> +static uint32_t zipl_handle_sig_entry(ComponentEntry *entry)
> +{
> + uint32_t sig_len;
> +
> + if (zipl_load_segment(entry, (uint64_t)sig_sec) < 0) {
> + return -1;
> + }
> +
> + if (entry->compdat.sig_info.format != DER_SIGNATURE_FORMAT) {
> + puts("Signature is not in DER format");
> + return -1;
> + }
> + sig_len = entry->compdat.sig_info.sig_len;
> +
> + return sig_len;
> +}
> +
> +static int handle_certificate(int *cert_table, uint64_t **cert,
> + uint64_t cert_len, uint8_t cert_idx,
> + IplSignatureCertificateList *certs, int cert_index)
> +{
> + bool unused;
> +
> + unused = cert_table[cert_idx] == -1;
> + if (unused) {
> + if (zipl_secure_request_certificate(*cert, cert_idx)) {
> + zipl_secure_cert_list_add(certs, cert_index, *cert, cert_len);
> + cert_table[cert_idx] = cert_index;
> + *cert += cert_len;
So zipl_secure_cert_list_add() checks for the index not going beyond
MAX_CERTIFICATES, but here you ignore that error and update cert_table and
*cert anyway? Sounds like a potential bug to me.
> + } else {
> + puts("Could not get certificate");
> + return -1;
> + }
> +
> + /* increment cert_index for the next cert entry */
> + return ++cert_index;
> + }
> +
> + return cert_index;
> +}
> +
> +static int zipl_run_secure(ComponentEntry *entry, uint8_t *tmp_sec)
> +{
> + bool found_signature = false;
> + IplDeviceComponentList comps;
> + IplSignatureCertificateList certs;
> + uint64_t *cert = (uint64_t *)certs_sec;
> + int cert_index = 0;
> + int comp_index = 0;
> + uint64_t comp_addr;
> + int comp_len;
> + bool have_sig;
> + uint32_t sig_len;
> + uint64_t cert_len = -1;
> + uint8_t cert_idx = -1;
> + bool verified;
> + /*
> + * Store indices of cert entry that have already used for signature verification
> + * to prevent allocating the same certificate multiple times.
> + * cert_table index: index of certificate from qemu cert store used for verification
> + * cert_table value: index of cert entry in cert list that contains the certificate
> + */
> + int cert_table[MAX_CERTIFICATES] = { [0 ... MAX_CERTIFICATES - 1] = -1};
> + zipl_secure_print_func = zipl_secure_get_print_func(boot_mode);
> +
> + if (!zipl_secure_ipl_supported()) {
> + return -1;
> + }
> +
> + zipl_secure_init_lists(&comps, &certs);
> +
> + have_sig = false;
> + while (entry->component_type == ZIPL_COMP_ENTRY_LOAD ||
> + entry->component_type == ZIPL_COMP_ENTRY_SIGNATURE) {
> +
> + if (entry->component_type == ZIPL_COMP_ENTRY_SIGNATURE) {
> + /* There should never be two signatures in a row */
> + if (have_sig) {
> + return -1;
> + }
> +
> + sig_len = zipl_handle_sig_entry(entry);
> + if (sig_len < 0) {
> + return -1;
> + }
> +
> + have_sig = true;
> + } else {
> + comp_addr = entry->compdat.load_addr;
> + comp_len = zipl_load_segment(entry, comp_addr);
> + if (comp_len < 0) {
> + return -1;
> + }
> +
> + if (have_sig) {
> + verified = verify_signature(comp_len, comp_addr,
> + sig_len, (uint64_t)sig_sec,
> + &cert_len, &cert_idx);
> +
> + if (verified) {
> + cert_index = handle_certificate(cert_table, &cert,
> + cert_len, cert_idx,
> + &certs, cert_index);
> +
> + puts("Verified component");
> + zipl_secure_comp_list_add(&comps, comp_index, cert_table[cert_idx],
> + comp_addr, comp_len,
> + S390_IPL_COMPONENT_FLAG_SC |
> + S390_IPL_COMPONENT_FLAG_CSV);
> + } else {
> + zipl_secure_comp_list_add(&comps, comp_index, -1,
> + comp_addr, comp_len,
> + S390_IPL_COMPONENT_FLAG_SC);
> + zipl_secure_print_func(verified, "Could not verify component");
> + }
> +
> + comp_index++;
> + found_signature = true;
> + /* After a signature is used another new one can be accepted */
> + have_sig = false;
> + }
> + }
> +
> + entry++;
> +
> + if ((uint8_t *)(&entry[1]) > (tmp_sec + MAX_SECTOR_SIZE)) {
Less parentheses please:
if ((uint8_t *)&entry[1] > tmp_sec + MAX_SECTOR_SIZE) {
> + puts("Wrong entry value");
> + return -EINVAL;
> + }
> + }
...
> diff --git a/pc-bios/s390-ccw/secure-ipl.h b/pc-bios/s390-ccw/secure-ipl.h
> new file mode 100644
> index 0000000000..4e2328840b
> --- /dev/null
> +++ b/pc-bios/s390-ccw/secure-ipl.h
> @@ -0,0 +1,109 @@
> +/*
> + * S/390 Secure IPL
> + *
> + * Copyright 2025 IBM Corp.
> + * Author(s): Zhuoying Cai <zycai@linux.ibm.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef _PC_BIOS_S390_CCW_SECURE_IPL_H
> +#define _PC_BIOS_S390_CCW_SECURE_IPL_H
> +
> +#include <diag320.h>
> +#include <diag508.h>
> +
> +VCStorageSizeBlock *zipl_secure_get_vcssb(void);
> +uint32_t zipl_secure_request_certificate(uint64_t *cert, uint8_t index);
> +void zipl_secure_cert_list_add(IplSignatureCertificateList *certs, int cert_index,
> + uint64_t *cert, uint64_t cert_len);
> +void zipl_secure_comp_list_add(IplDeviceComponentList *comps, int comp_index,
> + int cert_index, uint64_t comp_addr,
> + uint64_t comp_len, uint8_t flags);
> +int zipl_secure_update_iirb(IplDeviceComponentList *comps,
> + IplSignatureCertificateList *certs);
> +bool zipl_secure_ipl_supported(void);
> +void zipl_secure_init_lists(IplDeviceComponentList *comps,
> + IplSignatureCertificateList *certs);
> +
> +typedef void (*ipl_print_func_t)(bool, const char *);
> +
> +static inline ipl_print_func_t zipl_secure_get_print_func(ZiplBootMode boot_mode)
> +{
> + if (boot_mode == ZIPL_SECURE_AUDIT_MODE) {
> + return &IPL_check;
> + }
> +
> + return NULL;
> +}
What is this function really good for?? And why do we need the function
pointer below??? Aparently, the function pointer can also be NULL, but you
call it also without checking for NULL first in the various other functions
of this file ... looks very buggy to me, please rework this!
> +extern ipl_print_func_t zipl_secure_print_func;
> +
> +static inline uint64_t diag320(void *data, unsigned long subcode)
> +{
> + register unsigned long addr asm("0") = (unsigned long)data;
> + register unsigned long rc asm("1") = 0;
> +
> + asm volatile ("diag %0,%2,0x320\n"
> + : "+d" (addr), "+d" (rc)
> + : "d" (subcode)
> + : "memory", "cc");
> + return rc;
> +}
> +
> +static inline uint64_t get_320_subcodes(uint64_t *ism)
> +{
> + return diag320(ism, DIAG_320_SUBC_QUERY_ISM);
> +}
For such a simple call, it's likely not worth the effort to have a wrapper
function.
> +static inline bool is_cert_store_facility_supported(void)
> +{
> + uint64_t d320_ism;
> +
> + get_320_subcodes(&d320_ism);
> + return (d320_ism & DIAG_320_ISM_QUERY_VCSI) &&
> + (d320_ism & DIAG_320_ISM_STORE_VC);
> +}
> +
> +static inline uint64_t _diag508(void *data, unsigned long subcode)
> +{
> + register unsigned long addr asm("0") = (unsigned long)data;
> + register unsigned long rc asm("1") = 0;
> +
> + asm volatile ("diag %0,%2,0x508\n"
> + : "+d" (addr), "+d" (rc)
> + : "d" (subcode)
> + : "memory", "cc");
> + return rc;
> +}
> +
> +static inline uint64_t get_508_subcodes(void)
> +{
> + return _diag508(NULL, DIAG_508_SUBC_QUERY_SUBC);
> +}
dito.
> +static inline bool is_secure_ipl_extension_supported(void)
> +{
> + uint64_t d508_subcodes;
> +
> + d508_subcodes = get_508_subcodes();
> + return d508_subcodes & DIAG_508_SUBC_SIG_VERIF;
> +}
> +
> +static inline bool verify_signature(uint64_t comp_len, uint64_t comp_addr,
> + uint64_t sig_len, uint64_t sig_addr,
> + uint64_t *cert_len, uint8_t *cert_idx)
> +{
> + Diag508SignatureVerificationBlock svb = {{}, comp_len, comp_addr,
> + sig_len, sig_addr };
> +
> + if (_diag508(&svb, DIAG_508_SUBC_SIG_VERIF) == DIAG_508_RC_OK) {
> + *cert_len = svb.csi.len;
> + *cert_idx = svb.csi.idx;
> + return true;
> + }
> +
> + return false;
> +}
> +
> +#endif /* _PC_BIOS_S390_CCW_SECURE_IPL_H */
Thomas
next prev parent reply other threads:[~2025-05-20 10:26 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-08 22:50 [PATCH v2 00/25] Secure IPL Support for SCSI Scheme of virtio-blk/virtio-scsi Devices Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 01/25] Add -boot-certificates to s390-ccw-virtio machine type option Zhuoying Cai
2025-05-13 14:58 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 02/25] hw/s390x/ipl: Create certificate store Zhuoying Cai
2025-05-14 5:43 ` Thomas Huth
2025-05-29 18:49 ` Zhuoying Cai
2025-05-14 9:03 ` Daniel P. Berrangé
2025-05-29 17:51 ` Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 03/25] s390x: Guest support for Certificate Store Facility (CS) Zhuoying Cai
2025-05-14 6:11 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 04/25] s390x/diag: Introduce DIAG 320 for certificate store facility Zhuoying Cai
2025-05-14 8:17 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 05/25] s390x/diag: Refactor address validation check from diag308_parm_check Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 06/25] s390x/diag: Implement DIAG 320 subcode 1 Zhuoying Cai
2025-05-14 15:32 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 07/25] s390x/diag: Implement DIAG 320 subcode 2 Zhuoying Cai
2025-05-14 16:18 ` Thomas Huth
2025-05-29 19:09 ` Zhuoying Cai
2025-05-30 6:38 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 08/25] s390x/diag: Introduce DIAG 508 for secure IPL operations Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 09/25] s390x/diag: Implement DIAG 508 subcode 1 for signature verification Zhuoying Cai
2025-05-20 6:11 ` Thomas Huth
2025-05-20 8:16 ` Daniel P. Berrangé
2025-05-08 22:50 ` [PATCH v2 10/25] pc-bios/s390-ccw: Introduce IPL Information Report Block (IIRB) Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 11/25] pc-bios/s390-ccw: Define memory for IPLB and convert IPLB to pointers Zhuoying Cai
2025-05-20 9:24 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 12/25] hw/s390x/ipl: Add IPIB flags to IPL Parameter Block Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 13/25] hw/s390x/ipl: Set iplb->len to maximum length of " Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 14/25] s390x: Guest support for Secure-IPL Facility Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 15/25] pc-bios/s390-ccw: Refactor zipl_run() Zhuoying Cai
2025-05-20 9:29 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 16/25] pc-bios/s390-ccw: Refactor zipl_load_segment function Zhuoying Cai
2025-05-20 9:39 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 17/25] pc-bios/s390-ccw: Add signature verification for secure IPL in audit mode Zhuoying Cai
2025-05-20 10:25 ` Thomas Huth [this message]
2025-05-29 19:28 ` Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 18/25] s390x: Guest support for Secure-IPL Code Loading Attributes Facility (SCLAF) Zhuoying Cai
2025-05-26 14:46 ` Hendrik Brueckner
2025-05-08 22:50 ` [PATCH v2 19/25] pc-bios/s390-ccw: Add additional security checks for secure boot Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 20/25] Add -secure-boot to s390-ccw-virtio machine type option Zhuoying Cai
2025-05-21 12:14 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 21/25] hw/s390x/ipl: Set IPIB flags for secure IPL Zhuoying Cai
2025-05-21 12:20 ` Thomas Huth
2025-05-08 22:50 ` [PATCH v2 22/25] pc-bios/s390-ccw: Handle true secure IPL mode Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 23/25] pc-bios/s390-ccw: Handle secure boot with multiple boot devices Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 24/25] hw/s390x/ipl: Handle secure boot without specifying a boot device Zhuoying Cai
2025-05-08 22:50 ` [PATCH v2 25/25] docs/system/s390x: Add secure IPL documentation Zhuoying Cai
2025-05-21 12:37 ` Thomas Huth
2025-05-23 20:28 ` Collin Walling
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=53616ccd-3fb5-41e9-bd6a-0a0243b1a392@redhat.com \
--to=thuth@redhat.com \
--cc=borntraeger@linux.ibm.com \
--cc=david@redhat.com \
--cc=farman@linux.ibm.com \
--cc=fiuczy@linux.ibm.com \
--cc=iii@linux.ibm.com \
--cc=jjherne@linux.ibm.com \
--cc=jrossi@linux.ibm.com \
--cc=pasic@linux.ibm.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-s390x@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=walling@linux.ibm.com \
--cc=zycai@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).