[PATCH v10 20/30] pc-bios/s390-ccw: Add signed component address overlap checks

Zhuoying Cai posted 30 patches 4 days, 11 hours ago
Maintainers: "Daniel P. Berrangé" <berrange@redhat.com>, Pierrick Bouvier <pierrick.bouvier@linaro.org>, Cornelia Huck <cohuck@redhat.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Halil Pasic <pasic@linux.ibm.com>, Christian Borntraeger <borntraeger@linux.ibm.com>, Richard Henderson <richard.henderson@linaro.org>, Ilya Leoshkevich <iii@linux.ibm.com>, David Hildenbrand <david@kernel.org>, Jared Rossi <jrossi@linux.ibm.com>, Zhuoying Cai <zycai@linux.ibm.com>, Jason Herne <jjherne@linux.ibm.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>, Hendrik Brueckner <brueckner@linux.ibm.com>
[PATCH v10 20/30] pc-bios/s390-ccw: Add signed component address overlap checks
Posted by Zhuoying Cai 4 days, 11 hours ago
Add address range tracking and overlap checks to ensure that no
component overlaps with a signed component during secure IPL.

Signed-off-by: Zhuoying Cai <zycai@linux.ibm.com>
---
 pc-bios/s390-ccw/secure-ipl.c | 58 ++++++++++++++++++++++++++++++++---
 pc-bios/s390-ccw/secure-ipl.h | 15 +++++++++
 2 files changed, 69 insertions(+), 4 deletions(-)

diff --git a/pc-bios/s390-ccw/secure-ipl.c b/pc-bios/s390-ccw/secure-ipl.c
index b66ca9ca7e..d2079e19bc 100644
--- a/pc-bios/s390-ccw/secure-ipl.c
+++ b/pc-bios/s390-ccw/secure-ipl.c
@@ -211,6 +211,49 @@ static void init_lists(IplDeviceComponentList *comp_list,
     cert_list->ipl_info_header.len = sizeof(cert_list->ipl_info_header);
 }
 
+static bool is_comp_overlap(SecureIplCompAddrRangeList *range_list,
+                            SecureIplCompEntryInfo comp_entry_info)
+{
+    uint64_t start_addr;
+    uint64_t end_addr;
+
+    start_addr = comp_entry_info.addr;
+    end_addr = comp_entry_info.addr + comp_entry_info.len;
+
+    /*
+     * Check component's address range does not overlap with any
+     * signed component's address range.
+     */
+    for (int i = 0; i < range_list->index; i++) {
+        if ((range_list->comp_addr_range[i].start_addr < end_addr &&
+            start_addr < range_list->comp_addr_range[i].end_addr) &&
+            range_list->comp_addr_range[i].is_signed) {
+            return true;
+       }
+    }
+    return false;
+}
+
+static void comp_addr_range_add(SecureIplCompAddrRangeList *range_list,
+                                SecureIplCompEntryInfo comp_entry_info,
+                                bool is_signed)
+{
+    uint64_t start_addr;
+    uint64_t end_addr;
+
+    start_addr = comp_entry_info.addr;
+    end_addr = comp_entry_info.addr + comp_entry_info.len;
+
+    if (range_list->index >= MAX_CERTIFICATES) {
+        zipl_secure_handle("Component address range update failed due to out-of-range"
+                           " index; Overlapping validation cannot be guaranteed");
+    }
+
+    range_list->comp_addr_range[range_list->index].is_signed = is_signed;
+    range_list->comp_addr_range[range_list->index].start_addr = start_addr;
+    range_list->comp_addr_range[range_list->index].end_addr = end_addr;
+}
+
 static int zipl_load_signature(ComponentEntry *entry, uint64_t sig_sec)
 {
     if (zipl_load_segment(entry, sig_sec) < 0) {
@@ -253,6 +296,7 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
      * exists for the certificate).
      */
     int cert_list_table[MAX_CERTIFICATES] = { [0 ... MAX_CERTIFICATES - 1] = -1 };
+    SecureIplCompAddrRangeList range_list = { 0 };
     int signed_count = 0;
 
     if (!secure_ipl_supported()) {
@@ -282,14 +326,20 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
                 goto out;
             }
 
-            if (!sig_len) {
-                break;
-            }
-
             comp_entry_info = (SecureIplCompEntryInfo){ 0 };
             comp_entry_info.addr = comp_addr;
             comp_entry_info.len = (uint64_t)comp_len;
 
+            if (is_comp_overlap(&range_list, comp_entry_info)) {
+                zipl_secure_handle("Component addresses overlap");
+            }
+            comp_addr_range_add(&range_list, comp_entry_info, !!sig_len);
+            range_list.index += 1;
+
+            if (!sig_len) {
+                break;
+            }
+
             verified = verify_signature(comp_entry_info,
                                         sig_len, (uint64_t)sig,
                                         &cert_len, &cert_table_idx);
diff --git a/pc-bios/s390-ccw/secure-ipl.h b/pc-bios/s390-ccw/secure-ipl.h
index 6d65cd5596..c625ac2e3a 100644
--- a/pc-bios/s390-ccw/secure-ipl.h
+++ b/pc-bios/s390-ccw/secure-ipl.h
@@ -24,6 +24,21 @@ typedef struct SecureIplCompEntryInfo {
     uint8_t  flags;
 } SecureIplCompEntryInfo;
 
+typedef struct SecureIplCompAddrRange {
+    bool is_signed;
+    uint64_t start_addr;
+    uint64_t end_addr;
+} SecureIplCompAddrRange;
+
+/*
+ * Custom struct for managing a list of secure IPL component address ranges.
+ * Tracks up to MAX_CERTIFICATES address ranges with an index counter.
+ */
+typedef struct SecureIplCompAddrRangeList {
+    SecureIplCompAddrRange comp_addr_range[MAX_CERTIFICATES];
+    int index;
+} SecureIplCompAddrRangeList;
+
 static inline void zipl_secure_handle(const char *message)
 {
     switch (boot_mode) {
-- 
2.53.0