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 | 54 +++++++++++++++++++++++++++++++++++
pc-bios/s390-ccw/secure-ipl.h | 6 ++++
2 files changed, 60 insertions(+)
diff --git a/pc-bios/s390-ccw/secure-ipl.c b/pc-bios/s390-ccw/secure-ipl.c
index 1d5c2d40ce..27d2833642 100644
--- a/pc-bios/s390-ccw/secure-ipl.c
+++ b/pc-bios/s390-ccw/secure-ipl.c
@@ -210,6 +210,55 @@ static void init_lists(IplDeviceComponentList *comp_list,
cert_list->ipl_info_header.len = sizeof(cert_list->ipl_info_header);
}
+static bool is_comp_overlap(SecureIplCompAddrRange *comp_addr_range,
+ int addr_range_index,
+ uint64_t start_addr, uint64_t end_addr)
+{
+ /* neither a signed nor an unsigned component can overlap with a signed component */
+ for (int i = 0; i < addr_range_index; i++) {
+ if ((comp_addr_range[i].start_addr < end_addr &&
+ start_addr < comp_addr_range[i].end_addr) &&
+ comp_addr_range[i].is_signed) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void comp_addr_range_add(SecureIplCompAddrRange *comp_addr_range,
+ int addr_range_index, bool is_signed,
+ uint64_t start_addr, uint64_t end_addr)
+{
+ if (addr_range_index >= MAX_CERTIFICATES) {
+ printf("Warning: Ignoring component address range index [%d]"
+ " because the maximum supported index is %d\n",
+ addr_range_index, MAX_CERTIFICATES - 1);
+ return;
+ }
+
+ comp_addr_range[addr_range_index].is_signed = is_signed;
+ comp_addr_range[addr_range_index].start_addr = start_addr;
+ comp_addr_range[addr_range_index].end_addr = end_addr;
+}
+
+static void addr_overlap_check(SecureIplCompAddrRange *comp_addr_range,
+ int *addr_range_index,
+ uint64_t start_addr, uint64_t end_addr, bool is_signed)
+{
+ bool overlap;
+
+ overlap = is_comp_overlap(comp_addr_range, *addr_range_index,
+ start_addr, end_addr);
+ if (overlap) {
+ zipl_secure_handle("Component addresses overlap");
+ }
+
+ comp_addr_range_add(comp_addr_range, *addr_range_index, is_signed,
+ start_addr, end_addr);
+ *addr_range_index += 1;
+}
+
static int zipl_load_signature(ComponentEntry *entry, uint64_t sig_sec)
{
if (zipl_load_segment(entry, sig_sec) < 0) {
@@ -253,6 +302,8 @@ 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 };
+ SecureIplCompAddrRange comp_addr_range[MAX_CERTIFICATES];
+ int addr_range_index = 0;
int signed_count = 0;
if (!secure_ipl_supported()) {
@@ -282,6 +333,9 @@ int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec)
goto out;
}
+ addr_overlap_check(comp_addr_range, &addr_range_index,
+ comp_addr, comp_addr + comp_len, sig_len > 0);
+
if (!sig_len) {
break;
}
diff --git a/pc-bios/s390-ccw/secure-ipl.h b/pc-bios/s390-ccw/secure-ipl.h
index eb5ba0ed47..69edfce241 100644
--- a/pc-bios/s390-ccw/secure-ipl.h
+++ b/pc-bios/s390-ccw/secure-ipl.h
@@ -16,6 +16,12 @@
VCStorageSizeBlock *zipl_secure_get_vcssb(void);
int zipl_run_secure(ComponentEntry **entry_ptr, uint8_t *tmp_sec);
+typedef struct SecureIplCompAddrRange {
+ bool is_signed;
+ uint64_t start_addr;
+ uint64_t end_addr;
+} SecureIplCompAddrRange;
+
static inline void zipl_secure_handle(const char *message)
{
switch (boot_mode) {
--
2.52.0