master
c 561 lines 19.1 KB
Raw
1 /*
2 * S/390 Secure IPL
3 *
4 * Functions to support IPL in secure boot mode (DIAG 320, DIAG 508,
5 * signature verification, and certificate handling).
6 *
7 * For secure IPL overview: docs/system/s390x/secure-ipl.rst
8 * For secure IPL technical: docs/specs/s390x-secure-ipl.rst
9 *
10 * Copyright 2025 IBM Corp.
11 * Author(s): Zhuoying Cai <zycai@linux.ibm.com>
12 *
13 * SPDX-License-Identifier: GPL-2.0-or-later
14 */
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include "s390-ccw.h"
20 #include "sclp.h"
21 #include "secure-ipl.h"
22
23 static VCStorageSizeBlock vcssb __attribute__((__aligned__(8)));
24
25 #define for_each_rb_entry(entry, list) \
26 for (entry = (void *)(list) + sizeof((list)->ipl_info_header); \
27 (void *)(entry) + sizeof(*(entry)) <= \
28 (void *)(list) + (list)->ipl_info_header.len; \
29 entry++)
30
31 int zipl_secure_get_vcssb(void)
32 {
33 /* avoid retrieving vcssb multiple times */
34 if (vcssb.length == VCSSB_LEN_VALID) {
35 goto out;
36 }
37
38 vcssb.length = VCSSB_LEN_VALID;
39 if (_diag320(&vcssb, DIAG_320_SUBC_QUERY_VCSI) != DIAG_320_RC_OK) {
40 vcssb.length = 0;
41 }
42
43 out:
44 return vcssb.length;
45 }
46
47 static uint32_t request_certificate(uint8_t *cert_buf, uint8_t index)
48 {
49 VCEntryHeader *vce_hdr;
50 struct vcb {
51 VCBlockHeader vcb_hdr;
52 struct vce {
53 VCEntryHeader vce_hdr;
54 uint8_t cert_buf[CERT_BUF_MAX_LEN];
55 } vce;
56 } __attribute__((__aligned__(PAGE_SIZE))) vcb = { 0 };
57
58 /*
59 * Request single entry
60 * Fill input fields of single-entry VCB
61 *
62 * First and last index must be equal because only one
63 * VCE per VCB is currently supported
64 */
65 vcb.vcb_hdr.in_len = ROUND_UP(vcssb.max_single_vcb_len, PAGE_SIZE);
66 vcb.vcb_hdr.first_vc_index = index;
67 vcb.vcb_hdr.last_vc_index = index;
68
69 if (_diag320(&vcb, DIAG_320_SUBC_STORE_VC) != DIAG_320_RC_OK) {
70 puts("Could not get certificate");
71 return 0;
72 }
73
74 if (vcb.vcb_hdr.out_len == sizeof(VCBlockHeader)) {
75 puts("No certificate entry");
76 return 0;
77 }
78
79 if (vcb.vcb_hdr.remain_ct != 0) {
80 panic("Not enough memory to store requested certificate");
81 }
82
83 vce_hdr = &vcb.vce.vce_hdr;
84 if (!(vce_hdr->flags & DIAG_320_VCE_FLAGS_VALID)) {
85 puts("Invalid certificate");
86 return 0;
87 }
88
89 memcpy(cert_buf, (uint8_t *)&vcb.vce + vce_hdr->cert_offset, vce_hdr->cert_len);
90
91 return vce_hdr->cert_len;
92 }
93
94 static int cert_list_add(IplSignatureCertificateList *cert_list,
95 IplSignatureCertificateEntry cert_entry)
96 {
97 int cert_entry_idx;
98
99 cert_entry_idx = (cert_list->ipl_info_header.len - sizeof(IplInfoBlockHeader)) /
100 sizeof(IplSignatureCertificateEntry);
101
102 cert_list->cert_entries[cert_entry_idx] = cert_entry;
103 cert_list->ipl_info_header.len += sizeof(IplSignatureCertificateEntry);
104
105 return cert_entry_idx;
106 }
107
108 static void comp_list_add(IplDeviceComponentList *comp_list,
109 IplDeviceComponentEntry comp_entry)
110 {
111 int comp_entry_idx;
112
113 comp_entry_idx = (comp_list->ipl_info_header.len - sizeof(IplInfoBlockHeader)) /
114 sizeof(IplDeviceComponentEntry);
115 if (comp_entry_idx > MAX_COMP_ENTRIES - 1) {
116 printf("Warning: only %d component entries are supported\n",
117 MAX_COMP_ENTRIES);
118 panic("The device component list has reached its maximum capacity");
119 }
120
121 comp_list->device_entries[comp_entry_idx] = comp_entry;
122 comp_list->ipl_info_header.len += sizeof(IplDeviceComponentEntry);
123 }
124
125 void update_iirb(IplDeviceComponentList *comp_list,
126 IplSignatureCertificateList *cert_list)
127 {
128 IplInfoReportBlock *iirb;
129 IplDeviceComponentList *iirb_comps;
130 IplSignatureCertificateList *iirb_certs;
131 uint32_t iirb_hdr_len;
132 uint32_t comps_len;
133 uint32_t certs_len;
134
135 if (iplb->len % 8 != 0) {
136 panic("IPL parameter block length field value is not multiple of 8 bytes");
137 }
138
139 iirb_hdr_len = sizeof(IplInfoReportBlockHeader);
140 comps_len = comp_list->ipl_info_header.len;
141 certs_len = cert_list->ipl_info_header.len;
142 if ((comps_len + certs_len + iirb_hdr_len) > sizeof(IplInfoReportBlock)) {
143 panic("Not enough space to hold all components and certificates in IIRB");
144 }
145
146 /* IIRB immediately follows IPLB */
147 iirb = &ipl_blocks.iirb;
148 iirb->hdr.len = iirb_hdr_len;
149
150 /* Copy IPL device component list after IIRB Header */
151 iirb_comps = (IplDeviceComponentList *) iirb->info_blks;
152 memcpy(iirb_comps, comp_list, comps_len);
153
154 /* Update IIRB length */
155 iirb->hdr.len += comps_len;
156
157 /* Copy IPL sig cert list after IPL device component list */
158 iirb_certs = (IplSignatureCertificateList *) (iirb->info_blks +
159 iirb_comps->ipl_info_header.len);
160 memcpy(iirb_certs, cert_list, certs_len);
161
162 /* Update IIRB length */
163 iirb->hdr.len += certs_len;
164 }
165
166 bool secure_ipl_supported(void)
167 {
168 if (!sclp_is_fac_ipl_flag_on(SCCB_FAC_IPL_SIPL_BIT)) {
169 puts("Secure IPL Facility is not supported by the hypervisor!");
170 return false;
171 }
172
173 if (!is_signature_verif_supported()) {
174 puts("Secure IPL extensions are not supported by the hypervisor!");
175 return false;
176 }
177
178 if (!is_cert_store_facility_supported()) {
179 puts("Certificate Store Facility is not supported by the hypervisor!");
180 return false;
181 }
182
183 if (!sclp_is_fac_ipl_flag_on(SCCB_FAC_IPL_SCLAF_BIT)) {
184 puts("Secure IPL Code Loading Attributes Facility is not supported by"
185 " the hypervisor!");
186 return false;
187 }
188
189 return true;
190 }
191
192 static void init_lists(IplDeviceComponentList *comp_list,
193 IplSignatureCertificateList *cert_list)
194 {
195 comp_list->ipl_info_header.type = IPL_INFO_BLOCK_TYPE_COMPONENTS;
196 comp_list->ipl_info_header.len = sizeof(IplInfoBlockHeader);
197
198 cert_list->ipl_info_header.type = IPL_INFO_BLOCK_TYPE_CERTIFICATES;
199 cert_list->ipl_info_header.len = sizeof(IplInfoBlockHeader);
200 }
201
202 static void check_comp_overlap(IplDeviceComponentList *comp_list,
203 IplDeviceComponentEntry comp_entry)
204 {
205 IplDeviceComponentEntry *comp;
206
207 /*
208 * Check component's address range does not overlap with any
209 * signed component's address range.
210 */
211 for_each_rb_entry(comp, comp_list) {
212 if (comp->flags & S390_IPL_DEV_COMP_FLAG_SC &&
213 intersects(comp->addr, comp->len, comp_entry.addr, comp_entry.len)) {
214 zipl_secure_error("Component addresses overlap");
215 }
216 }
217 }
218
219 static bool is_psw_valid(uint64_t psw, IplDeviceComponentEntry *comp)
220 {
221 uint32_t addr = psw & 0x7fffffff;
222
223 /*
224 * PSW points within a signed binary code component
225 *
226 * Check addr falls within [comp->addr, comp->addr + comp->len - 2],
227 * ensuring at least 2 bytes (minimum instruction length) remain.
228 */
229 return intersects(addr, 1, comp->addr, comp->len - 1);
230 }
231
232 void check_global_sclab(const SclaBlock *global_sclab,
233 IplDeviceComponentEntry *comp_entry,
234 IplDeviceComponentList *comp_list)
235 {
236 bool psw_valid = false;
237 bool global_psw_valid = false;
238 int signed_count = 0;
239 int unsigned_count = 0;
240 IplDeviceComponentEntry *comp;
241
242 if (!global_sclab) {
243 comp_list->ipl_info_header.iiei |= S390_IIEI_NO_GLOBAL_SCLAB;
244 zipl_secure_error("Global SCLAB does not exist");
245 return;
246 }
247
248 for_each_rb_entry(comp, comp_list) {
249 if (comp->flags & S390_IPL_DEV_COMP_FLAG_SC) {
250 psw_valid |= is_psw_valid(comp_entry->addr, comp);
251 global_psw_valid |= is_psw_valid(global_sclab->load_psw, comp);
252 signed_count += 1;
253 } else {
254 unsigned_count += 1;
255 }
256 }
257
258 /* validate load PSW with PSW specified in the final entry */
259 zipl_secure_validate(psw_valid && global_psw_valid, &comp_entry->cei,
260 S390_CEI_INVALID_LOAD_PSW, "Invalid PSW");
261
262 /* compare load PSW with the PSW specified in component */
263 zipl_secure_validate(global_sclab->load_psw == comp_entry->addr,
264 &comp_entry->cei, S390_CEI_UNMATCHED_SCLAB_LOAD_PSW,
265 "Load PSW does not match with PSW in component");
266
267 /* Unsigned components are not allowed if NUC flag is set in the global SCLAB */
268 if ((global_sclab->flags & S390_SCLAB_NUC) && unsigned_count > 0) {
269 comp_list->ipl_info_header.iiei |= S390_IIEI_FOUND_UNSIGNED_COMP;
270 zipl_secure_error("Unsigned components are not allowed");
271 }
272
273 /*
274 * Only one signed component is allowed if SC flag is set in the global SCLAB
275 * More than one component in the component table is not allowed
276 */
277 if ((global_sclab->flags & S390_SCLAB_SC) &&
278 (signed_count != 1 || unsigned_count != 0)) {
279 comp_list->ipl_info_header.iiei |= S390_IIEI_MORE_SIGNED_COMP;
280 zipl_secure_error("Only one signed component is allowed");
281 }
282 }
283
284 static void check_sclab(SclaBlock **global_sclab,
285 IplDeviceComponentEntry *comp_entry,
286 IplInfoBlockHeader *comp_list_hdr)
287 {
288 SclabOriginLocator *sclab_locator;
289 SclaBlock *sclab;
290
291 /* must be large enough to locate the sclab locator, else implies invalid SCLAB */
292 zipl_secure_validate(comp_entry->len >= 8, &comp_entry->cei,
293 S390_CEI_INVALID_SCLAB,
294 "Signed component too short to contain SCLAB locator");
295
296 if (comp_entry->cei & S390_CEI_INVALID_SCLAB) {
297 return;
298 }
299
300 /* sclab locator is located at the last 8 bytes of the signed comp */
301 sclab_locator = (SclabOriginLocator *)(comp_entry->addr +
302 comp_entry->len - 8);
303
304 /* return early if sclab does not exist */
305 zipl_secure_validate(magic_match(sclab_locator->magic, ZIPL_MAGIC),
306 &comp_entry->cei, S390_CEI_INVALID_SCLAB,
307 "Magic does not match. SCLAB does not exist");
308
309 if (comp_entry->cei & S390_CEI_INVALID_SCLAB) {
310 return;
311 }
312
313 zipl_secure_validate(sclab_locator->len >= S390_SCLAB_MIN_LEN, &comp_entry->cei,
314 S390_CEI_INVALID_SCLAB_LEN | S390_CEI_INVALID_SCLAB,
315 "Invalid SCLAB length");
316
317 /* return early if sclab is invalid */
318 if (comp_entry->cei & S390_CEI_INVALID_SCLAB) {
319 return;
320 }
321
322 sclab = (SclaBlock *)(comp_entry->addr + comp_entry->len -
323 sclab_locator->len);
324
325 zipl_secure_validate(sclab->format == 0, &comp_entry->cei,
326 S390_CEI_INVALID_SCLAB_FORMAT,
327 "Format-0 SCLAB is not being used");
328
329 if (!(sclab->flags & S390_SCLAB_OPSW)) {
330 /* OPSW = 0 - Load PSW field in SCLAB must contain zeros */
331 zipl_secure_validate(sclab->load_psw == 0, &comp_entry->cei,
332 S390_CEI_SCLAB_LOAD_PSW_NOT_ZERO,
333 "Load PSW is not zero when Override PSW bit is zero");
334 } else {
335 /* OPSW = 1 indicating global SCLAB */
336 if (*global_sclab) {
337 comp_list_hdr->iiei |= S390_IIEI_MORE_GLOBAL_SCLAB;
338 zipl_secure_error("More than one global SCLAB");
339 }
340 *global_sclab = sclab;
341
342 /* override load address flag must set to one */
343 zipl_secure_validate(sclab->flags & S390_SCLAB_OLA, &comp_entry->cei,
344 S390_CEI_SCLAB_OLA_NOT_ONE,
345 "OLA flag is not set to one in the global SCLAB");
346 }
347
348 if (!(sclab->flags & S390_SCLAB_OLA)) {
349 /* OLA = 0 - Load address field in SCLAB must contain zeros */
350 zipl_secure_validate(sclab->load_addr == 0, &comp_entry->cei,
351 S390_CEI_SCLAB_LOAD_ADDR_NOT_ZERO,
352 "Load Address is not zero when OLA flag is zero");
353 } else {
354 /* OLA = 1 - Load address field must match storage address of the component */
355 zipl_secure_validate(sclab->load_addr == comp_entry->addr, &comp_entry->cei,
356 S390_CEI_UNMATCHED_SCLAB_LOAD_ADDR,
357 "Load Address does not match with component load address");
358 }
359
360 zipl_secure_validate(~sclab->flags & S390_SCLAB_NUC || sclab->flags & S390_SCLAB_OPSW,
361 &comp_entry->cei, S390_CEI_NUC_NOT_IN_GLOBAL_SCLAB,
362 "NUC bit is set, but not in the global SCLAB");
363
364 zipl_secure_validate(~sclab->flags & S390_SCLAB_SC || sclab->flags & S390_SCLAB_OPSW,
365 &comp_entry->cei, S390_CEI_SC_NOT_IN_GLOBAL_SCLAB,
366 "SC bit is set, but not in the global SCLAB");
367 }
368
369 static int zipl_load_signature(ComponentEntry *entry, uint64_t sig)
370 {
371 if (entry->compdat.sig_info.format != DER_SIGNATURE_FORMAT) {
372 puts("Signature is not in DER format");
373 return -1;
374 }
375
376 if (zipl_load_segment(entry->data.blockno, sig) < 0) {
377 return -1;
378 }
379
380 return entry->compdat.sig_info.sig_len;
381 }
382
383 void update_cert_list(IplSignatureCertificateList *cert_list)
384 {
385 IplSignatureCertificateEntry *cert_entry;
386 uint8_t *cert_buf;
387
388 /*
389 * Recover the original base address of ipl_data for cert storage.
390 *
391 * The IplParameterBlocks stored in ipl_data will no longer be needed
392 * after this point. Reuse this region to store certificates from the
393 * BIOS heap into stable memory.
394 */
395 cert_buf = (uint8_t *)qipl.ipl_data - qipl.index * sizeof(IplParameterBlock);
396
397 for_each_rb_entry(cert_entry, cert_list) {
398 memcpy(cert_buf, (uint8_t *)cert_entry->addr, cert_entry->len);
399 cert_entry->addr = (uint64_t)cert_buf;
400 cert_buf += cert_entry->len;
401 }
402 }
403
404 int zipl_run_secure(ComponentEntry **entry_ptr, const uint8_t *tmp_sec,
405 IplDeviceComponentList *comp_list,
406 IplSignatureCertificateList *cert_list,
407 uint8_t **tmp_cert_buf)
408 {
409 /*
410 * Keep track of which certificate store indices correspond to the
411 * certificate data entries within the IplSignatureCertificateList to
412 * prevent allocating space for the same certificate multiple times.
413 *
414 * The array index corresponds to the certificate's cert-store index.
415 *
416 * The array value corresponds to the certificate's entry within the
417 * IplSignatureCertificateList (with a value of -1 denoting no entry
418 * exists for the certificate).
419 */
420 int cert_list_table[vcssb.total_vc_ct + 1];
421 IplSignatureCertificateEntry sig_entry = { 0 };
422 IplSignatureCertificateEntry cert_entry;
423 IplDeviceComponentEntry comp_entry;
424 ComponentEntry *entry = *entry_ptr;
425 int rc = -1;
426 int sig_len = 0;
427 int comp_len;
428 int cert_entry_idx;
429 uint64_t comp_addr;
430 uint8_t cert_table_idx;
431 uint8_t *tmp_buf;
432 bool verified;
433 bool signed_found = false;
434 bool sclab_found = false;
435 SclaBlock *global_sclab = NULL;
436
437 if ((MAX_SIGNED_COMP * CERT_BUF_MAX_LEN) > CERT_BUF_SIZE) {
438 panic("Not enough memory to store certificates");
439 }
440 *tmp_cert_buf = malloc(CERT_BUF_SIZE);
441 tmp_buf = *tmp_cert_buf;
442
443 init_lists(comp_list, cert_list);
444 sig_entry.addr = (uint64_t)malloc(MAX_SECTOR_SIZE);
445 memset(cert_list_table, -1, sizeof(cert_list_table));
446
447 while (entry->component_type != ZIPL_COMP_ENTRY_EXEC) {
448 switch (entry->component_type) {
449 case ZIPL_COMP_ENTRY_SIGNATURE:
450 if (sig_entry.len) {
451 goto error;
452 }
453
454 sig_len = zipl_load_signature(entry, sig_entry.addr);
455 if (sig_len < 0) {
456 goto error;
457 }
458
459 sig_entry.len = sig_len;
460 break;
461 case ZIPL_COMP_ENTRY_LOAD:
462 comp_addr = entry->compdat.load_addr;
463 comp_len = zipl_load_segment(entry->data.blockno, comp_addr);
464 if (comp_len < 0) {
465 goto error;
466 }
467
468 comp_entry = (IplDeviceComponentEntry){ 0 };
469 comp_entry.addr = comp_addr;
470 comp_entry.len = (uint64_t)comp_len;
471
472 check_comp_overlap(comp_list, comp_entry);
473
474 /* no signature present (unsigned component) */
475 if (!sig_entry.len) {
476 zipl_secure_validate(comp_entry.addr >= S390_UNSIGNED_MIN_ADDR,
477 &comp_entry.cei, S390_CEI_INVALID_UNSIGNED_ADDR,
478 "Load address for unsigned component is less than 0x2000");
479
480 comp_list_add(comp_list, comp_entry);
481 break;
482 }
483
484 /*
485 * Initialize with SC flag (signed component)
486 * CSV flag set upon successful verification
487 */
488 comp_entry.flags = S390_IPL_DEV_COMP_FLAG_SC;
489 signed_found = true;
490
491 check_sclab(&global_sclab, &comp_entry, &comp_list->ipl_info_header);
492 sclab_found |= !(comp_entry.cei & S390_CEI_INVALID_SCLAB);
493
494 cert_entry = (IplSignatureCertificateEntry) { 0 };
495 verified = verify_signature(comp_entry, sig_entry,
496 &cert_entry.len, &cert_table_idx);
497
498 if (verified) {
499 if (cert_list_table[cert_table_idx] == -1) {
500 if (!request_certificate(tmp_buf, cert_table_idx)) {
501 puts("Could not get certificate");
502 goto error;
503 }
504
505 cert_entry.addr = (uint64_t)tmp_buf;
506 cert_entry_idx = cert_list_add(cert_list, cert_entry);
507 /* map cert-store index to cert-list entry index */
508 cert_list_table[cert_table_idx] = cert_entry_idx;
509 /* increment for the next certificate */
510 tmp_buf += cert_entry.len;
511 }
512
513 comp_entry.cert_index = cert_list_table[cert_table_idx];
514 comp_entry.flags |= S390_IPL_DEV_COMP_FLAG_CSV;
515 puts("Verified component");
516 } else {
517 zipl_secure_error("Could not verify component");
518 }
519
520 comp_list_add(comp_list, comp_entry);
521
522 /* After a signature is used another new one can be accepted */
523 sig_entry.len = 0;
524 break;
525 default:
526 puts("Unknown component entry type");
527 goto error;
528 }
529
530 entry++;
531
532 if ((uint8_t *)(&entry[1]) > tmp_sec + MAX_SECTOR_SIZE) {
533 puts("Wrong entry value");
534 rc = -EINVAL;
535 goto error;
536 }
537 }
538
539 zipl_secure_validate(signed_found, &comp_list->ipl_info_header.iiei,
540 S390_IIEI_NO_SIGNED_COMP,
541 "Secure boot is on, but components are not signed");
542
543 zipl_secure_validate(sclab_found, &comp_list->ipl_info_header.iiei,
544 S390_IIEI_NO_SCLAB, "No recognizable SCLAB");
545
546 comp_entry = (IplDeviceComponentEntry){ 0 };
547 comp_entry.addr = entry->compdat.load_psw;
548 check_global_sclab(global_sclab, &comp_entry, comp_list);
549 comp_list_add(comp_list, comp_entry);
550
551 *entry_ptr = entry;
552 free((void *)sig_entry.addr);
553
554 return 0;
555 error:
556 free(*tmp_cert_buf);
557 *tmp_cert_buf = NULL;
558 free((void *)sig_entry.addr);
559
560 return rc;
561 }