Re: [PATCH v16 26/33] pc-bios/s390-ccw: Add additional security checks for secure boot
On 7/7/26 19:40, Zhuoying Cai wrote: > Add additional checks to ensure that components do not overlap with > signed components when loaded into memory. > > Add additional checks to ensure the load addresses of unsigned components > are greater than or equal to 0x2000. > > When the secure IPL code loading attributes facility (SCLAF) is installed, > all signed components must contain a secure code loading attributes block > (SCLAB). > > The SCLAB provides further validation of information on where to load the > signed binary code from the load device, and where to start the execution > of the loaded OS code. > > When SCLAF is installed, its content must be evaluated during secure IPL. > > Add IPL Information Error Indicators (IIEI) and Component Error > Indicators (CEI) for IPL Information Report Block (IIRB). > > When SCLAF is installed, additional secure boot checks are performed > during zipl and store results of verification into IIRB. > > Signed-off-by: Zhuoying Cai > Reviewed-by: Eric Farman > --- [...] This significantly cleaner and much more conscise. Thank you for all the effort of getting this to the current state. Reviewed-by: Collin Walling -- Regards, Collin
[PATCH v16 26/33] pc-bios/s390-ccw: Add additional security checks for secure boot
Add additional checks to ensure that components do not overlap with
signed components when loaded into memory.
Add additional checks to ensure the load addresses of unsigned components
are greater than or equal to 0x2000.
When the secure IPL code loading attributes facility (SCLAF) is installed,
all signed components must contain a secure code loading attributes block
(SCLAB).
The SCLAB provides further validation of information on where to load the
signed binary code from the load device, and where to start the execution
of the loaded OS code.
When SCLAF is installed, its content must be evaluated during secure IPL.
Add IPL Information Error Indicators (IIEI) and Component Error
Indicators (CEI) for IPL Information Report Block (IIRB).
When SCLAF is installed, additional secure boot checks are performed
during zipl and store results of verification into IIRB.
Signed-off-by: Zhuoying Cai
Reviewed-by: Eric Farman
---
include/hw/s390x/ipl/qipl.h | 29 +-
pc-bios/s390-ccw/sclp.h | 1 +
pc-bios/s390-ccw/secure-ipl.c | 179 +-
pc-bios/s390-ccw/secure-ipl.h | 51 ++
4 files changed, 255 insertions(+), 5 deletions(-)
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 37452faaa6..37a1a76a2d 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -170,10 +170,20 @@ struct IplInfoReportBlockHeader {
};
typedef struct IplInfoReportBlockHeader IplInfoReportBlockHeader;
+/* IPL Info Error Indicators */
+#define S390_IIEI_NO_SIGNED_COMP 0x8000 /* bit 0 */
+#define S390_IIEI_NO_SCLAB0x4000 /* bit 1 */
+#define S390_IIEI_NO_GLOBAL_SCLAB 0x2000 /* bit 2 */
+#define S390_IIEI_MORE_GLOBAL_SCLAB 0x1000 /* bit 3 */
+#define S390_IIEI_FOUND_UNSIGNED_COMP 0x800 /* bit 4 */
+#define S390_IIEI_MORE_SIGNED_COMP0x400 /* bit 5 */
+
struct IplInfoBlockHeader {
uint32_t len;
uint8_t type;
-uint8_t reserved1[11];
+uint8_t reserved1[3];
+uint16_t iiei;
+uint8_t reserved2[6];
};
typedef struct IplInfoBlockHeader IplInfoBlockHeader;
@@ -197,13 +207,28 @@ typedef struct IplSignatureCertificateList
IplSignatureCertificateList;
#define S390_IPL_DEV_COMP_FLAG_SC 0x80
#define S390_IPL_DEV_COMP_FLAG_CSV 0x40
+/* IPL Device Component Error Indicators */
+#define S390_CEI_INVALID_SCLAB 0x8000 /* bit 0 */
+#define S390_CEI_INVALID_SCLAB_LEN 0x4000 /* bit 1 */
+#define S390_CEI_INVALID_SCLAB_FORMAT 0x2000 /* bit 2 */
+#define S390_CEI_UNMATCHED_SCLAB_LOAD_ADDR 0x1000 /* bit 3 */
+#define S390_CEI_UNMATCHED_SCLAB_LOAD_PSW 0x800 /* bit 4 */
+#define S390_CEI_INVALID_LOAD_PSW 0x400 /* bit 5 */
+#define S390_CEI_NUC_NOT_IN_GLOBAL_SCLAB 0x200 /* bit 6 */
+#define S390_CEI_SCLAB_OLA_NOT_ONE 0x100 /* bit 7 */
+#define S390_CEI_SC_NOT_IN_GLOBAL_SCLAB0x80 /* bit 8 */
+#define S390_CEI_SCLAB_LOAD_ADDR_NOT_ZERO 0x40 /* bit 9 */
+#define S390_CEI_SCLAB_LOAD_PSW_NOT_ZERO 0x20 /* bit 10 */
+#define S390_CEI_INVALID_UNSIGNED_ADDR 0x10 /* bit 11 */
+
struct IplDeviceComponentEntry {
uint64_t addr;
uint64_t len;
uint8_t flags;
uint8_t reserved1[5];
uint16_t cert_index;
-uint8_t reserved2[8];
+uint32_t cei;
+uint8_t reserved2[4];
};
typedef struct IplDeviceComponentEntry IplDeviceComponentEntry;
diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h
index a8a41cd004..cae65b29b5 100644
--- a/pc-bios/s390-ccw/sclp.h
+++ b/pc-bios/s390-ccw/sclp.h
@@ -52,6 +52,7 @@ typedef struct SCCBHeader {
#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
#define SCCB_FAC134_DIAG320_BIT 0x4
#define SCCB_FAC_IPL_SIPL_BIT 0x4000
+#define SCCB_FAC_IPL_SCLAF_BIT 0x1000
typedef struct ReadInfo {
SCCBHeader h;
diff --git a/pc-bios/s390-ccw/secure-ipl.c b/pc-bios/s390-ccw/secure-ipl.c
index cd2d18bfa0..8989e9aba5 100644
--- a/pc-bios/s390-ccw/secure-ipl.c
+++ b/pc-bios/s390-ccw/secure-ipl.c
@@ -180,6 +180,12 @@ bool secure_ipl_supported(void)
return false;
}
+if (!sclp_is_fac_ipl_flag_on(SCCB_FAC_IPL_SCLAF_BIT)) {
+puts("Secure IPL Code Loading Attributes Facility is not supported by"
+ " the hypervisor!");
+return false;
+}
+
return true;
}
@@ -210,6 +216,156 @@ static void check_comp_overlap(IplDeviceComponentList
*comp_list,
}
}
+static bool is_psw_valid(uint64_t psw, IplDeviceComponentEntry *comp)
+{
+uint32_t addr = psw & 0x7fff;
+
+/*
+ * PSW points within a signed binary code component
+ *
+ * Check addr falls within [comp->addr, comp->addr + comp->len - 2],
+ * ensuring at least 2 bytes (minimum instruction length) remain.
+ */
+return intersects(addr, 1, comp->addr, comp->len - 1);
+}
+
+void check_global_sclab(const SclaBlock *global_sclab,
+IplDeviceComponentEntry *comp_entry,
+
[PATCH v16 26/33] pc-bios/s390-ccw: Add additional security checks for secure boot
Add additional checks to ensure that components do not overlap with
signed components when loaded into memory.
Add additional checks to ensure the load addresses of unsigned components
are greater than or equal to 0x2000.
When the secure IPL code loading attributes facility (SCLAF) is installed,
all signed components must contain a secure code loading attributes block
(SCLAB).
The SCLAB provides further validation of information on where to load the
signed binary code from the load device, and where to start the execution
of the loaded OS code.
When SCLAF is installed, its content must be evaluated during secure IPL.
Add IPL Information Error Indicators (IIEI) and Component Error
Indicators (CEI) for IPL Information Report Block (IIRB).
When SCLAF is installed, additional secure boot checks are performed
during zipl and store results of verification into IIRB.
Signed-off-by: Zhuoying Cai
Reviewed-by: Eric Farman
---
include/hw/s390x/ipl/qipl.h | 29 +-
pc-bios/s390-ccw/sclp.h | 1 +
pc-bios/s390-ccw/secure-ipl.c | 179 +-
pc-bios/s390-ccw/secure-ipl.h | 51 ++
4 files changed, 255 insertions(+), 5 deletions(-)
diff --git a/include/hw/s390x/ipl/qipl.h b/include/hw/s390x/ipl/qipl.h
index 37452faaa6..37a1a76a2d 100644
--- a/include/hw/s390x/ipl/qipl.h
+++ b/include/hw/s390x/ipl/qipl.h
@@ -170,10 +170,20 @@ struct IplInfoReportBlockHeader {
};
typedef struct IplInfoReportBlockHeader IplInfoReportBlockHeader;
+/* IPL Info Error Indicators */
+#define S390_IIEI_NO_SIGNED_COMP 0x8000 /* bit 0 */
+#define S390_IIEI_NO_SCLAB0x4000 /* bit 1 */
+#define S390_IIEI_NO_GLOBAL_SCLAB 0x2000 /* bit 2 */
+#define S390_IIEI_MORE_GLOBAL_SCLAB 0x1000 /* bit 3 */
+#define S390_IIEI_FOUND_UNSIGNED_COMP 0x800 /* bit 4 */
+#define S390_IIEI_MORE_SIGNED_COMP0x400 /* bit 5 */
+
struct IplInfoBlockHeader {
uint32_t len;
uint8_t type;
-uint8_t reserved1[11];
+uint8_t reserved1[3];
+uint16_t iiei;
+uint8_t reserved2[6];
};
typedef struct IplInfoBlockHeader IplInfoBlockHeader;
@@ -197,13 +207,28 @@ typedef struct IplSignatureCertificateList
IplSignatureCertificateList;
#define S390_IPL_DEV_COMP_FLAG_SC 0x80
#define S390_IPL_DEV_COMP_FLAG_CSV 0x40
+/* IPL Device Component Error Indicators */
+#define S390_CEI_INVALID_SCLAB 0x8000 /* bit 0 */
+#define S390_CEI_INVALID_SCLAB_LEN 0x4000 /* bit 1 */
+#define S390_CEI_INVALID_SCLAB_FORMAT 0x2000 /* bit 2 */
+#define S390_CEI_UNMATCHED_SCLAB_LOAD_ADDR 0x1000 /* bit 3 */
+#define S390_CEI_UNMATCHED_SCLAB_LOAD_PSW 0x800 /* bit 4 */
+#define S390_CEI_INVALID_LOAD_PSW 0x400 /* bit 5 */
+#define S390_CEI_NUC_NOT_IN_GLOBAL_SCLAB 0x200 /* bit 6 */
+#define S390_CEI_SCLAB_OLA_NOT_ONE 0x100 /* bit 7 */
+#define S390_CEI_SC_NOT_IN_GLOBAL_SCLAB0x80 /* bit 8 */
+#define S390_CEI_SCLAB_LOAD_ADDR_NOT_ZERO 0x40 /* bit 9 */
+#define S390_CEI_SCLAB_LOAD_PSW_NOT_ZERO 0x20 /* bit 10 */
+#define S390_CEI_INVALID_UNSIGNED_ADDR 0x10 /* bit 11 */
+
struct IplDeviceComponentEntry {
uint64_t addr;
uint64_t len;
uint8_t flags;
uint8_t reserved1[5];
uint16_t cert_index;
-uint8_t reserved2[8];
+uint32_t cei;
+uint8_t reserved2[4];
};
typedef struct IplDeviceComponentEntry IplDeviceComponentEntry;
diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h
index a8a41cd004..cae65b29b5 100644
--- a/pc-bios/s390-ccw/sclp.h
+++ b/pc-bios/s390-ccw/sclp.h
@@ -52,6 +52,7 @@ typedef struct SCCBHeader {
#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
#define SCCB_FAC134_DIAG320_BIT 0x4
#define SCCB_FAC_IPL_SIPL_BIT 0x4000
+#define SCCB_FAC_IPL_SCLAF_BIT 0x1000
typedef struct ReadInfo {
SCCBHeader h;
diff --git a/pc-bios/s390-ccw/secure-ipl.c b/pc-bios/s390-ccw/secure-ipl.c
index cd2d18bfa0..8989e9aba5 100644
--- a/pc-bios/s390-ccw/secure-ipl.c
+++ b/pc-bios/s390-ccw/secure-ipl.c
@@ -180,6 +180,12 @@ bool secure_ipl_supported(void)
return false;
}
+if (!sclp_is_fac_ipl_flag_on(SCCB_FAC_IPL_SCLAF_BIT)) {
+puts("Secure IPL Code Loading Attributes Facility is not supported by"
+ " the hypervisor!");
+return false;
+}
+
return true;
}
@@ -210,6 +216,156 @@ static void check_comp_overlap(IplDeviceComponentList
*comp_list,
}
}
+static bool is_psw_valid(uint64_t psw, IplDeviceComponentEntry *comp)
+{
+uint32_t addr = psw & 0x7fff;
+
+/*
+ * PSW points within a signed binary code component
+ *
+ * Check addr falls within [comp->addr, comp->addr + comp->len - 2],
+ * ensuring at least 2 bytes (minimum instruction length) remain.
+ */
+return intersects(addr, 1, comp->addr, comp->len - 1);
+}
+
+void check_global_sclab(const SclaBlock *global_sclab,
+IplDeviceComponentEntry *comp_entry,
+
