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