On 5/20/25 6:25 AM, Thomas Huth wrote:
> 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 <zy...@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.
> 

If zipl_secure_request_certificate() successfully retrieves a
certificate from the S390 certificate store, updating the corresponding
entry in cert_table should not pose any issues. This is because we
strictly limit the number of certificates to MAX_CERTIFICATES, and
cert_idx is guaranteed to be within the range [0, 63].

The size of cert_table and the memory allocated for *cert are both
defined based on MAX_CERTIFICATES and MAX_CERT_SIZE, so as long as the
request is successful, the update is safe.

The index check in zipl_secure_cert_list_add() ensures that the IIRB
cert list does not exceed the valid range defined by MAX_CERTIFICATES,
preventing out-of-bound memory overwrites.

>> +        } else {
>> +            puts("Could not get certificate");
>> +            return -1;
>> +        }
>> +
>> +        /* increment cert_index for the next cert entry */
>> +        return ++cert_index;
>> +    }
>> +
>> +    return cert_index;
>> +}
>> +

[...]

Reply via email to