master
c 759 lines 22.8 KB
Raw
1 /*
2 * S390x DIAG instruction helper functions
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #include <inttypes.h>
16 #include "qemu/osdep.h"
17 #include "cpu.h"
18 #include "s390x-internal.h"
19 #include "hw/watchdog/wdt_diag288.h"
20 #include "system/cpus.h"
21 #include "hw/s390x/cert-store.h"
22 #include "hw/s390x/ipl.h"
23 #include "hw/s390x/ipl/diag320.h"
24 #include "hw/s390x/ipl/diag508.h"
25 #include "hw/s390x/s390-virtio-ccw.h"
26 #include "system/kvm.h"
27 #include "kvm/kvm_s390x.h"
28 #include "target/s390x/kvm/pv.h"
29 #include "qapi/error.h"
30 #include "qemu/error-report.h"
31 #include "crypto/x509-utils.h"
32
33
34 static inline bool diag_parm_addr_valid(uint64_t addr, size_t size, bool write)
35 {
36 return address_space_access_valid(&address_space_memory, addr,
37 size, write, MEMTXATTRS_UNSPECIFIED);
38 }
39
40 int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
41 {
42 uint64_t func = env->regs[r1];
43 uint64_t timeout = env->regs[r1 + 1];
44 uint64_t action = env->regs[r3];
45 Object *obj;
46 DIAG288State *diag288;
47 DIAG288Class *diag288_class;
48
49 if (r1 % 2 || action != 0) {
50 return -1;
51 }
52
53 /* Timeout must be more than 15 seconds except for timer deletion */
54 if (func != WDT_DIAG288_CANCEL && timeout < 15) {
55 return -1;
56 }
57
58 obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
59 if (!obj) {
60 return -1;
61 }
62
63 diag288 = DIAG288(obj);
64 diag288_class = DIAG288_GET_CLASS(diag288);
65 return diag288_class->handle_timer(diag288, func, timeout);
66 }
67
68 static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
69 uintptr_t ra, bool write)
70 {
71 /* Handled by the Ultravisor */
72 if (s390_is_pv()) {
73 return 0;
74 }
75 if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
76 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
77 return -1;
78 }
79 if (!diag_parm_addr_valid(addr, sizeof(IplParameterBlock), write)) {
80 s390_program_interrupt(env, PGM_ADDRESSING, ra);
81 return -1;
82 }
83 return 0;
84 }
85
86 static void s390_ipl_read(CPUS390XState *env, uint64_t addr,
87 void *data, size_t size)
88 {
89 if (s390_is_pv()) {
90 s390_cpu_pv_mem_read(env_archcpu(env), 0, data, size);
91 } else {
92 address_space_read(cpu_get_address_space(env_cpu(env), 0), addr,
93 MEMTXATTRS_UNSPECIFIED, data, size);
94 }
95 }
96
97 static void s390_ipl_write(CPUS390XState *env, uint64_t addr,
98 void *data, size_t size)
99 {
100 if (s390_is_pv()) {
101 s390_cpu_pv_mem_write(env_archcpu(env), 0, data, size);
102 } else {
103 address_space_write(cpu_get_address_space(env_cpu(env), 0), addr,
104 MEMTXATTRS_UNSPECIFIED, data, size);
105 }
106 }
107
108 bool handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
109 {
110 bool valid;
111 CPUState *cs = env_cpu(env);
112 uint64_t addr = env->regs[r1];
113 uint64_t subcode = env->regs[r3];
114 IplParameterBlock *iplb;
115
116 if (env->psw.mask & PSW_MASK_PSTATE) {
117 s390_program_interrupt(env, PGM_PRIVILEGED, ra);
118 return false;
119 }
120
121 if (subcode & ~0x0ffffULL) {
122 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
123 return false;
124 }
125
126 if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
127 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
128 return false;
129 }
130
131 switch (subcode) {
132 case DIAG308_RESET_MOD_CLR:
133 s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
134 return true;
135 case DIAG308_RESET_LOAD_NORM:
136 s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL);
137 return true;
138 case DIAG308_LOAD_CLEAR:
139 /* Well we still lack the clearing bit... */
140 s390_ipl_reset_request(cs, S390_RESET_REIPL);
141 return true;
142 case DIAG308_SET:
143 case DIAG308_PV_SET:
144 if (diag308_parm_check(env, r1, addr, ra, false)) {
145 return false;
146 }
147 iplb = g_new0(IplParameterBlock, 1);
148 s390_ipl_read(env, addr, iplb, sizeof(iplb->len));
149 if (!iplb_valid_len(iplb)) {
150 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
151 goto out;
152 }
153 s390_ipl_read(env, addr, iplb, be32_to_cpu(iplb->len));
154
155 valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
156 if (!valid) {
157 if (subcode == DIAG308_SET && iplb->pbt == S390_IPL_TYPE_QEMU_SCSI) {
158 s390_rebuild_iplb(iplb->devno, iplb);
159 s390_ipl_update_diag308(iplb);
160 env->regs[r1 + 1] = DIAG_308_RC_OK;
161 } else {
162 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
163 }
164
165 goto out;
166 }
167
168 s390_ipl_update_diag308(iplb);
169 env->regs[r1 + 1] = DIAG_308_RC_OK;
170 out:
171 g_free(iplb);
172 return false;
173 case DIAG308_STORE:
174 case DIAG308_PV_STORE:
175 if (diag308_parm_check(env, r1, addr, ra, true)) {
176 return false;
177 }
178 if (subcode == DIAG308_PV_STORE) {
179 iplb = s390_ipl_get_iplb_pv();
180 } else {
181 iplb = s390_ipl_get_iplb();
182 }
183 if (!iplb) {
184 env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
185 return false;
186 }
187
188 s390_ipl_write(env, addr, iplb, be32_to_cpu(iplb->len));
189 env->regs[r1 + 1] = DIAG_308_RC_OK;
190 return false;
191 case DIAG308_PV_START:
192 iplb = s390_ipl_get_iplb_pv();
193 if (!iplb) {
194 env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
195 return false;
196 }
197
198 if (kvm_enabled() && kvm_s390_get_hpage()) {
199 error_report("Protected VMs can currently not be backed with "
200 "huge pages");
201 env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
202 return false;
203 }
204
205 s390_ipl_reset_request(cs, S390_RESET_PV);
206 return true;
207 default:
208 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
209 return false;
210 }
211 }
212
213 static int handle_diag320_query_vcsi(S390CPU *cpu, uint64_t addr, uint64_t r1,
214 uintptr_t ra, S390IPLCertificateStore *cs)
215 {
216 g_autofree VCStorageSizeBlock *vcssb = NULL;
217
218 vcssb = g_new0(VCStorageSizeBlock, 1);
219 if (s390_cpu_virt_mem_read(cpu, addr, r1, vcssb, sizeof(*vcssb))) {
220 s390_cpu_virt_mem_handle_exc(cpu, ra);
221 return -1;
222 }
223
224 if (be32_to_cpu(vcssb->length) != VCSSB_LEN_VALID) {
225 return DIAG_320_RC_INVAL_VCSSB_LEN;
226 }
227
228 if (!cs->count) {
229 vcssb->length = cpu_to_be32(VCSSB_NO_VC);
230 } else {
231 vcssb->version = 0;
232 vcssb->total_vc_ct = cpu_to_be16(cs->count);
233 vcssb->max_vc_ct = cpu_to_be16(MAX_CERTIFICATES);
234 vcssb->max_single_vcb_len = cpu_to_be32(sizeof(VCBlockHeader) +
235 sizeof(VCEntryHeader) +
236 cs->largest_cert_size);
237 vcssb->total_vcb_len = cpu_to_be32(sizeof(VCBlockHeader) +
238 cs->count * sizeof(VCEntryHeader) +
239 cs->total_bytes);
240 }
241
242 if (s390_cpu_virt_mem_write(cpu, addr, r1, vcssb, be32_to_cpu(vcssb->length))) {
243 s390_cpu_virt_mem_handle_exc(cpu, ra);
244 return -1;
245 }
246 return DIAG_320_RC_OK;
247 }
248
249 static bool is_cert_valid(const S390IPLCertificate *cert)
250 {
251 int rc;
252 Error *err = NULL;
253
254 rc = qcrypto_x509_check_cert_times(cert->raw, cert->size, &err);
255 if (rc != 0) {
256 error_report_err(err);
257 return false;
258 }
259
260 return true;
261 }
262
263 static int handle_key_id(VCEntry *vce, const S390IPLCertificate *cert)
264 {
265 int rc;
266 g_autofree unsigned char *key_id_data = NULL;
267 size_t key_id_len;
268 Error *err = NULL;
269
270 rc = qcrypto_x509_get_cert_key_id(cert->raw, cert->size,
271 QCRYPTO_HASH_ALGO_SHA256,
272 &key_id_data, &key_id_len, &err);
273 if (rc < 0) {
274 error_report_err(err);
275 return 0;
276 }
277
278 if (sizeof(VCEntryHeader) + key_id_len > be32_to_cpu(vce->vce_hdr.len)) {
279 error_report("Unable to write key ID: exceeds buffer bounds");
280 return 0;
281 }
282
283 vce->vce_hdr.keyid_len = cpu_to_be16(key_id_len);
284
285 memcpy(vce->cert_buf, key_id_data, key_id_len);
286
287 return ROUND_UP(key_id_len, 4);
288 }
289
290 static int handle_hash(VCEntry *vce, const S390IPLCertificate *cert,
291 uint16_t keyid_field_len)
292 {
293 int rc;
294 uint16_t hash_offset;
295 g_autofree void *hash_data = NULL;
296 size_t hash_len;
297 Error *err = NULL;
298
299 hash_len = CERT_HASH_LEN;
300 hash_data = g_malloc0(hash_len);
301 rc = qcrypto_get_x509_cert_fingerprint(cert->raw, cert->size,
302 QCRYPTO_HASH_ALGO_SHA256,
303 hash_data, &hash_len, &err);
304 if (rc < 0) {
305 error_report_err(err);
306 return 0;
307 }
308
309 hash_offset = sizeof(VCEntryHeader) + keyid_field_len;
310 if (hash_offset + hash_len > be32_to_cpu(vce->vce_hdr.len)) {
311 error_report("Unable to write hash: exceeds buffer bounds");
312 return 0;
313 }
314
315 vce->vce_hdr.hash_len = cpu_to_be16(hash_len);
316 vce->vce_hdr.hash_type = DIAG_320_VCE_HASHTYPE_SHA2_256;
317 vce->vce_hdr.hash_offset = cpu_to_be16(hash_offset);
318
319 memcpy((uint8_t *)vce + hash_offset, hash_data, hash_len);
320
321 return ROUND_UP(hash_len, 4);
322 }
323
324 static int handle_cert(VCEntry *vce, const S390IPLCertificate *cert,
325 uint16_t hash_field_len)
326 {
327 int rc;
328 uint16_t cert_offset;
329 g_autofree uint8_t *cert_der = NULL;
330 size_t der_size;
331 Error *err = NULL;
332
333 rc = qcrypto_x509_convert_cert_der(cert->raw, cert->size,
334 &cert_der, &der_size, &err);
335 if (rc < 0) {
336 error_report_err(err);
337 return 0;
338 }
339
340 cert_offset = be16_to_cpu(vce->vce_hdr.hash_offset) + hash_field_len;
341 if (cert_offset + der_size > be32_to_cpu(vce->vce_hdr.len)) {
342 error_report("Unable to write certificate: exceeds buffer bounds");
343 return 0;
344 }
345
346 vce->vce_hdr.format = DIAG_320_VCE_FORMAT_X509_DER;
347 vce->vce_hdr.cert_len = cpu_to_be32(der_size);
348 vce->vce_hdr.cert_offset = cpu_to_be16(cert_offset);
349
350 memcpy((uint8_t *)vce + cert_offset, cert_der, der_size);
351
352 return ROUND_UP(der_size, 4);
353 }
354
355 static int get_key_type(const S390IPLCertificate *cert)
356 {
357 int rc;
358 Error *err = NULL;
359
360 rc = qcrypto_x509_check_ecc_curve_p521(cert->raw, cert->size, &err);
361 if (rc == -1) {
362 error_report_err(err);
363 return -1;
364 }
365
366 return (rc == 1) ? DIAG_320_VCE_KEYTYPE_ECDSA_P521 :
367 DIAG_320_VCE_KEYTYPE_SELF_DESCRIBING;
368 }
369
370 static int build_vce_header(VCEntry *vce, const S390IPLCertificate *cert, int idx)
371 {
372 int key_type;
373
374 vce->vce_hdr.len = cpu_to_be32(sizeof(VCEntryHeader));
375 vce->vce_hdr.cert_idx = cpu_to_be16(idx + 1);
376 memcpy(vce->vce_hdr.name, cert->name, CERT_NAME_MAX_LEN);
377
378 if (!is_cert_valid(cert)) {
379 return -1;
380 }
381
382 key_type = get_key_type(cert);
383 if (key_type == -1) {
384 return -1;
385 }
386 vce->vce_hdr.key_type = key_type;
387
388 return 0;
389 }
390
391 static int build_vce_data(VCEntry *vce, const S390IPLCertificate *cert,
392 uint32_t vce_max_len)
393 {
394 uint16_t keyid_field_len;
395 uint16_t hash_field_len;
396 uint32_t cert_field_len;
397 uint32_t vce_len;
398
399 vce->vce_hdr.len = cpu_to_be32(vce_max_len);
400
401 keyid_field_len = handle_key_id(vce, cert);
402 if (!keyid_field_len) {
403 return -1;
404 }
405
406 hash_field_len = handle_hash(vce, cert, keyid_field_len);
407 if (!hash_field_len) {
408 return -1;
409 }
410
411 cert_field_len = handle_cert(vce, cert, hash_field_len);
412 if (!cert_field_len) {
413 return -1;
414 }
415
416 vce_len = sizeof(VCEntryHeader) + keyid_field_len + hash_field_len + cert_field_len;
417 if (vce_len > vce_max_len) {
418 return -1;
419 }
420
421 vce->vce_hdr.flags |= DIAG_320_VCE_FLAGS_VALID;
422
423 /* Update vce length to reflect the actual size used by vce */
424 vce->vce_hdr.len = cpu_to_be32(vce_len);
425
426 return 0;
427 }
428
429 static int handle_diag320_store_vc(S390CPU *cpu, uint64_t addr, uint64_t r1, uintptr_t ra,
430 S390IPLCertificateStore *cs)
431 {
432 g_autofree VCBlockHeader *vcb_hdr = NULL;
433 size_t remaining_space;
434 uint16_t first_vc_index;
435 uint16_t last_vc_index;
436 int cs_start_index;
437 int cs_end_index;
438 uint32_t vce_max_len;
439 uint32_t vce_len;
440 uint32_t in_len;
441
442 vcb_hdr = g_new0(VCBlockHeader, 1);
443 if (s390_cpu_virt_mem_read(cpu, addr, r1, vcb_hdr, sizeof(*vcb_hdr))) {
444 s390_cpu_virt_mem_handle_exc(cpu, ra);
445 return -1;
446 }
447
448 in_len = be32_to_cpu(vcb_hdr->in_len);
449 first_vc_index = be16_to_cpu(vcb_hdr->first_vc_index);
450 last_vc_index = be16_to_cpu(vcb_hdr->last_vc_index);
451
452 if (in_len % TARGET_PAGE_SIZE != 0) {
453 return DIAG_320_RC_INVAL_VCB_LEN;
454 }
455
456 if (first_vc_index > last_vc_index) {
457 return DIAG_320_RC_BAD_RANGE;
458 }
459
460 vcb_hdr->out_len = sizeof(VCBlockHeader);
461
462 /*
463 * DIAG 320 subcode 2 expects to query a certificate store that
464 * maintains an index origin of 1. However, the S390IPLCertificateStore
465 * maintains an index origin of 0. Thus, the indices must be adjusted
466 * for correct access into the cert store. A couple of special cases
467 * must also be accounted for.
468 */
469
470 /* Both indices are 0; return header with no certs */
471 if (first_vc_index == 0 && last_vc_index == 0) {
472 goto out;
473 }
474
475 /* Normalize indices */
476 cs_start_index = (first_vc_index == 0) ? 0 : first_vc_index - 1;
477 cs_end_index = last_vc_index - 1;
478
479 /* Requested range is outside the cert store; return header with no certs */
480 if (cs_start_index >= cs->count || cs_end_index >= cs->count) {
481 goto out;
482 }
483
484 remaining_space = in_len - sizeof(VCBlockHeader);
485
486 for (int i = cs_start_index; i <= cs_end_index; i++) {
487 const S390IPLCertificate *cert = &cs->certs[i];
488 /*
489 * Each field of the VCE is word-aligned.
490 * Allocate enough space for the largest possible size for this VCE.
491 * As the certificate fields (key-id, hash, data) are parsed, the
492 * VCE's length field will be updated accordingly.
493 */
494 vce_max_len = sizeof(VCEntryHeader) + ROUND_UP(CERT_KEY_ID_LEN, 4) +
495 ROUND_UP(CERT_HASH_LEN, 4) + ROUND_UP(cert->der_size, 4);
496 g_autofree VCEntry *vce = g_malloc0(vce_max_len);
497
498 /*
499 * Bit 0 of the VCE flags indicates whether the certificate is valid.
500 * The caller of DIAG320 subcode 2 is responsible for verifying that
501 * the VCE contains a valid certificate.
502 */
503 if (build_vce_header(vce, cert, i) || build_vce_data(vce, cert, vce_max_len)) {
504 /*
505 * Error occurs - VCE does not contain a valid certificate.
506 * Bit 0 of the VCE flags is 0 and the VCE length is set.
507 */
508 vce->vce_hdr.len = cpu_to_be32(VCE_INVALID_LEN);
509 }
510 vce_len = be32_to_cpu(vce->vce_hdr.len);
511
512 /*
513 * If there is no more space to store the cert,
514 * set the remaining verification cert count and
515 * break early.
516 */
517 if (remaining_space < vce_len) {
518 vcb_hdr->remain_ct = cpu_to_be16(last_vc_index - i);
519 break;
520 }
521
522 /* Write VCE */
523 if (s390_cpu_virt_mem_write(cpu, addr + vcb_hdr->out_len, r1, vce, vce_len)) {
524 s390_cpu_virt_mem_handle_exc(cpu, ra);
525 return -1;
526 }
527
528 vcb_hdr->out_len += vce_len;
529 remaining_space -= vce_len;
530 vcb_hdr->stored_ct++;
531 }
532 vcb_hdr->stored_ct = cpu_to_be16(vcb_hdr->stored_ct);
533
534 out:
535 vcb_hdr->out_len = cpu_to_be32(vcb_hdr->out_len);
536
537 if (s390_cpu_virt_mem_write(cpu, addr, r1, vcb_hdr, sizeof(VCBlockHeader))) {
538 s390_cpu_virt_mem_handle_exc(cpu, ra);
539 return -1;
540 }
541
542 return DIAG_320_RC_OK;
543 }
544
545 QEMU_BUILD_BUG_MSG(sizeof(VCStorageSizeBlock) != VCSSB_LEN_VALID,
546 "size of VCStorageSizeBlock is wrong");
547 QEMU_BUILD_BUG_MSG(sizeof(VCBlock) != 64, "size of VCBlock is wrong");
548 QEMU_BUILD_BUG_MSG(sizeof(VCEntry) != 128, "size of VCEntry is wrong");
549
550 void handle_diag_320(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
551 {
552 S390CPU *cpu = env_archcpu(env);
553 S390IPLCertificateStore *cs = s390_ipl_get_certificate_store();
554 uint64_t subcode = env->regs[r3];
555 uint64_t addr = env->regs[r1];
556 uint32_t ism_word0;
557 int rc;
558
559 if (env->psw.mask & PSW_MASK_PSTATE) {
560 s390_program_interrupt(env, PGM_PRIVILEGED, ra);
561 return;
562 }
563
564 if (!s390_has_feat(S390_FEAT_CERT_STORE) ||
565 (subcode & ~0x000ffULL) ||
566 (r1 & 1)) {
567 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
568 return;
569 }
570
571 switch (subcode) {
572 case DIAG_320_SUBC_QUERY_ISM:
573 /*
574 * The Installed Subcode Block (ISB) can be up 8 words in size,
575 * but the current set of subcodes can fit within a single word
576 * for now.
577 */
578 ism_word0 = cpu_to_be32(DIAG_320_ISM_QUERY_SUBCODES |
579 DIAG_320_ISM_QUERY_VCSI |
580 DIAG_320_ISM_STORE_VC);
581
582 if (s390_cpu_virt_mem_write(cpu, addr, r1, &ism_word0, sizeof(ism_word0))) {
583 s390_cpu_virt_mem_handle_exc(cpu, ra);
584 return;
585 }
586
587 env->regs[r1 + 1] = DIAG_320_RC_OK;
588 break;
589 case DIAG_320_SUBC_QUERY_VCSI:
590 if (addr & 0x7) {
591 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
592 return;
593 }
594
595 if (!diag_parm_addr_valid(addr, sizeof(VCStorageSizeBlock), true)) {
596 s390_program_interrupt(env, PGM_ADDRESSING, ra);
597 return;
598 }
599
600 rc = handle_diag320_query_vcsi(cpu, addr, r1, ra, cs);
601 if (rc == -1) {
602 return;
603 }
604 env->regs[r1 + 1] = rc;
605 break;
606 case DIAG_320_SUBC_STORE_VC:
607 if (addr & ~TARGET_PAGE_MASK) {
608 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
609 return;
610 }
611
612 rc = handle_diag320_store_vc(cpu, addr, r1, ra, cs);
613 if (rc == -1) {
614 return;
615 }
616 env->regs[r1 + 1] = rc;
617 break;
618 default:
619 env->regs[r1 + 1] = DIAG_320_RC_NOT_SUPPORTED;
620 break;
621 }
622 }
623
624 static bool diag_508_verify_sig(uint8_t *cert, size_t cert_size,
625 uint8_t *comp, size_t comp_size,
626 uint8_t *sig, size_t sig_size)
627 {
628 g_autofree uint8_t *sig_pem = NULL;
629 size_t sig_size_pem;
630 int rc;
631
632 /*
633 * PKCS#7 signature with DER format
634 * Convert to PEM format for signature verification
635 *
636 * Ignore errors during qcrypto signature format conversion and verification
637 * Return false on any error, treating it as a verification failure
638 */
639 rc = qcrypto_pkcs7_convert_sig_pem(sig, sig_size, &sig_pem, &sig_size_pem, NULL);
640 if (rc < 0) {
641 return false;
642 }
643
644 rc = qcrypto_x509_verify_sig(cert, cert_size,
645 comp, comp_size,
646 sig_pem, sig_size_pem, NULL);
647 if (rc < 0) {
648 return false;
649 }
650
651 return true;
652 }
653
654 static int handle_diag508_sig_verif(CPUS390XState *env, uint64_t addr)
655 {
656 int verified;
657 uint32_t svb_len;
658 uint64_t comp_len, comp_addr;
659 uint64_t sig_len, sig_addr;
660 g_autofree uint8_t *comp = NULL;
661 g_autofree uint8_t *sig = NULL;
662 g_autofree Diag508SigVerifBlock *svb = NULL;
663 size_t svb_size = sizeof(Diag508SigVerifBlock);
664 S390IPLCertificateStore *cs = s390_ipl_get_certificate_store();
665
666 if (!cs->count) {
667 return DIAG_508_RC_NO_CERTS;
668 }
669
670 svb = g_new0(Diag508SigVerifBlock, 1);
671 s390_ipl_read(env, addr, svb, svb_size);
672
673 svb_len = be32_to_cpu(svb->length);
674 if (svb_len != svb_size) {
675 return DIAG_508_RC_INVAL_LEN;
676 }
677
678 comp_len = be64_to_cpu(svb->comp_len);
679 comp_addr = be64_to_cpu(svb->comp_addr);
680 sig_len = be64_to_cpu(svb->sig_len);
681 sig_addr = be64_to_cpu(svb->sig_addr);
682
683 if (!comp_len || !comp_addr || comp_len > DIAG_508_MAX_COMP_LEN) {
684 if (comp_len > DIAG_508_MAX_COMP_LEN) {
685 warn_report("DIAG 0x508: component length %" PRIu64
686 " exceeds current maximum %u",
687 comp_len, DIAG_508_MAX_COMP_LEN);
688 }
689 return DIAG_508_RC_INVAL_COMP_DATA;
690 }
691
692 if (!sig_len || !sig_addr || sig_len > DIAG_508_MAX_SIG_LEN) {
693 if (sig_len > DIAG_508_MAX_SIG_LEN) {
694 warn_report("DIAG 0x508: signature length %" PRIu64
695 " exceeds current maximum %u",
696 sig_len, DIAG_508_MAX_SIG_LEN);
697 }
698 return DIAG_508_RC_INVAL_PKCS7_SIG;
699 }
700
701 comp = g_malloc0(comp_len);
702 s390_ipl_read(env, comp_addr, comp, comp_len);
703
704 sig = g_malloc0(sig_len);
705 s390_ipl_read(env, sig_addr, sig, sig_len);
706
707 for (int i = 0; i < cs->count; i++) {
708 verified = diag_508_verify_sig(cs->certs[i].raw,
709 cs->certs[i].size,
710 comp, comp_len,
711 sig, sig_len);
712 if (verified) {
713 svb->cert_store_index = i;
714 svb->cert_len = cpu_to_be64(cs->certs[i].der_size);
715 s390_ipl_write(env, addr, svb, svb_size);
716 return DIAG_508_RC_OK;
717 }
718 }
719
720 return DIAG_508_RC_FAIL_VERIF;
721 }
722
723 QEMU_BUILD_BUG_MSG(sizeof(Diag508SigVerifBlock) != 64,
724 "size of Diag508SigVerifBlock is wrong");
725
726 void handle_diag_508(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
727 {
728 uint64_t subcode = env->regs[r3];
729 uint64_t addr = env->regs[r1];
730 int rc;
731
732 if (env->psw.mask & PSW_MASK_PSTATE) {
733 s390_program_interrupt(env, PGM_PRIVILEGED, ra);
734 return;
735 }
736
737 if ((subcode & ~0x0ffffULL) || (r1 & 1)) {
738 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
739 return;
740 }
741
742 switch (subcode) {
743 case DIAG_508_SUBC_QUERY_SUBC:
744 rc = DIAG_508_SUBC_SIG_VERIF;
745 break;
746 case DIAG_508_SUBC_SIG_VERIF:
747 if (!diag_parm_addr_valid(addr, sizeof(Diag508SigVerifBlock), true)) {
748 s390_program_interrupt(env, PGM_ADDRESSING, ra);
749 return;
750 }
751
752 rc = handle_diag508_sig_verif(env, addr);
753 break;
754 default:
755 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
756 return;
757 }
758 env->regs[r1 + 1] = rc;
759 }