History

Merge tag 's390-7.2-7' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 fixes from Vasily Gorbik: - Fix potential uninitialized memory reads and buffer overflows from malformed zcrypt CCA and EP11 requests by properly validating lengths and payloads - Fix possible out of bounds accesses in zcrypt EP11 domain handling by replacing fixed payload layout assumptions with parsing ASN.1 fields with bounds checks - Fix zcrypt CCA and EP11 request and reply buffer allocations missing required 4-byte padding, and scrub the full allocation on release - Fix zcrypt CCA and EP11 messages leaking up to 3 uninitialized bytes of memory by zeroing trailing alignment padding * tag 's390-7.2-7' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/zcrypt: Pad trailing CCA or EP11 message with zeros s390/zcrypt: Improve EP11 CPRB domain handling with ASN.1 parsing s390/zcrypt: Improve EP11 CPRB length and overflow checks s390/zcrypt: Improve CCA CPRB length and overflow checks s390/zcrypt: Fix CPRB memory allocation in zcrypt misc code

Linus Torvalds committed 3 months ago

Commit b643e492 parents 06cf618 eb363253 files · +278 −124Browse files

Unified · Split

3 files
  1. drivers/s390/crypto/zcrypt_ccamisc.c +14 −6
  2. drivers/s390/crypto/zcrypt_ep11misc.c +11 −5
  3. drivers/s390/crypto/zcrypt_msgtype6.c +253 −113
drivers/s390/crypto/zcrypt_ccamisc.c+14−6
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <linux/module.h>15#include <linux/module.h>
16#include <linux/slab.h>16#include <linux/slab.h>
17#include <linux/random.h>17#include <linux/random.h>
18#include <linux/align.h>
18#include <asm/zcrypt.h>19#include <asm/zcrypt.h>
19#include <asm/pkey.h>20#include <asm/pkey.h>
20 21
@@ -267,6 +268,10 @@ EXPORT_SYMBOL(cca_check_sececckeytoken); · 246 unmodified lines
267 * block, reply CPRB and reply param block and fill in values268 * block, reply CPRB and reply param block and fill in values
268 * for the common fields. Returns 0 on success or errno value269 * for the common fields. Returns 0 on success or errno value
269 * on failure.270 * on failure.
271 * It is guaranteed that request and a possible param block
272 * are aligned to a 4 byte boundary. Furthermore if a param
273 * block is used, the memory allocated for this is rounded up to
274 * the next multiple of 4 bytes.
270 */275 */
271static int alloc_and_prep_cprbmem(size_t paramblen,276static int alloc_and_prep_cprbmem(size_t paramblen,
272 u8 **p_cprb_mem,277 u8 **p_cprb_mem,
@@ -275,7 +280,8 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 2 unmodified lines
275 u32 xflags)280 u32 xflags)
276{281{
277 u8 *cprbmem = NULL;282 u8 *cprbmem = NULL;
278 size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;283 size_t cprbplusparamblen =
284 ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
279 size_t len = 2 * cprbplusparamblen;285 size_t len = 2 * cprbplusparamblen;
280 struct CPRBX *preqcblk, *prepcblk;286 struct CPRBX *preqcblk, *prepcblk;
281 287
@@ -302,10 +308,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 20 unmodified lines
302 memcpy(preqcblk->func_id, "T2", 2);308 memcpy(preqcblk->func_id, "T2", 2);
303 preqcblk->rpl_msgbl = cprbplusparamblen;309 preqcblk->rpl_msgbl = cprbplusparamblen;
304 if (paramblen) {310 if (paramblen) {
305 preqcblk->req_parmb =311 preqcblk->req_parmb = ((u8 __user *)preqcblk) +
306 ((u8 __user *)preqcblk) + sizeof(struct CPRBX);312 ALIGN(sizeof(struct CPRBX), 4);
307 preqcblk->rpl_parmb =313 preqcblk->rpl_parmb = ((u8 __user *)prepcblk) +
308 ((u8 __user *)prepcblk) + sizeof(struct CPRBX);314 ALIGN(sizeof(struct CPRBX), 4);
309 }315 }
310 316
311 *p_cprb_mem = cprbmem;317 *p_cprb_mem = cprbmem;
@@ -323,8 +329,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 11 unmodified lines
323 */329 */
324static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)330static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
325{331{
332 size_t cprblen = ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
333
326 if (mem && scrub)334 if (mem && scrub)
327 memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));335 memzero_explicit(mem, 2 * cprblen);
328 336
329 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)337 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
330 mempool_free(mem, cprb_mempool);338 mempool_free(mem, cprb_mempool);
drivers/s390/crypto/zcrypt_ep11misc.c+11−5
@@ -14,6 +14,7 @@ · 13 unmodified lines
14#include <linux/module.h>14#include <linux/module.h>
15#include <linux/random.h>15#include <linux/random.h>
16#include <linux/slab.h>16#include <linux/slab.h>
17#include <linux/align.h>
17#include <asm/zcrypt.h>18#include <asm/zcrypt.h>
18#include <asm/pkey.h>19#include <asm/pkey.h>
19#include <crypto/aes.h>20#include <crypto/aes.h>
@@ -355,21 +356,24 @@ EXPORT_SYMBOL(ep11_check_aes_key); · 335 unmodified lines
355 356
356/*357/*
357 * Allocate and prepare ep11 cprb plus additional payload.358 * Allocate and prepare ep11 cprb plus additional payload.
359 * It is guaranteed that the memory is aligned to a 4 byte boundary.
360 * Furthermore the memory allocation is rounded up to the next
361 * multiple of 4 bytes (with taking the payload_len into account).
358 */362 */
359static void *alloc_cprbmem(size_t payload_len, u32 xflags)363static void *alloc_cprbmem(size_t payload_len, u32 xflags)
360{364{
361 size_t len = sizeof(struct ep11_cprb) + payload_len;365 size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
362 struct ep11_cprb *cprb = NULL;366 struct ep11_cprb *cprb = NULL;
363 367
364 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {368 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
365 if (len <= CPRB_MEMPOOL_ITEM_SIZE)369 if (memlen <= CPRB_MEMPOOL_ITEM_SIZE)
366 cprb = mempool_alloc_preallocated(cprb_mempool);370 cprb = mempool_alloc_preallocated(cprb_mempool);
367 } else {371 } else {
368 cprb = kmalloc(len, GFP_KERNEL);372 cprb = kmalloc(memlen, GFP_KERNEL);
369 }373 }
370 if (!cprb)374 if (!cprb)
371 return NULL;375 return NULL;
372 memset(cprb, 0, len);376 memset(cprb, 0, memlen);
373 377
374 cprb->cprb_len = sizeof(struct ep11_cprb);378 cprb->cprb_len = sizeof(struct ep11_cprb);
375 cprb->cprb_ver_id = 0x04;379 cprb->cprb_ver_id = 0x04;
@@ -385,8 +389,10 @@ static void *alloc_cprbmem(size_t payload_len, u32 xflags) · 9 unmodified lines
385 */389 */
386static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)390static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)
387{391{
392 size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
393
388 if (mem && scrub)394 if (mem && scrub)
389 memzero_explicit(mem, sizeof(struct ep11_cprb) + payload_len);395 memzero_explicit(mem, memlen);
390 396
391 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)397 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
392 mempool_free(mem, cprb_mempool);398 mempool_free(mem, cprb_mempool);
drivers/s390/crypto/zcrypt_msgtype6.c+253−113
@@ -19,6 +19,7 @@ · 18 unmodified lines
19#include <linux/slab.h>19#include <linux/slab.h>
20#include <linux/atomic.h>20#include <linux/atomic.h>
21#include <linux/uaccess.h>21#include <linux/uaccess.h>
22#include <linux/unaligned.h>
22 23
23#include "ap_bus.h"24#include "ap_bus.h"
24#include "zcrypt_api.h"25#include "zcrypt_api.h"
@@ -34,6 +35,9 @@ · 9 unmodified lines
34#define CEXXC_RESPONSE_TYPE_XCRB 135#define CEXXC_RESPONSE_TYPE_XCRB 1
35#define CEXXC_RESPONSE_TYPE_EP11 236#define CEXXC_RESPONSE_TYPE_EP11 2
36 37
38/* smallest possible EP11 payload size */
39#define MIN_EP11_PAYLOAD_SIZE 5
40
37MODULE_AUTHOR("IBM Corporation");41MODULE_AUTHOR("IBM Corporation");
38MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \42MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
39 "Copyright IBM Corp. 2001, 2023");43 "Copyright IBM Corp. 2001, 2023");
@@ -342,49 +346,39 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, · 302 unmodified lines
342 };346 };
343 } __packed * msg = ap_msg->msg;347 } __packed * msg = ap_msg->msg;
344 348
345 int rcblen = CEIL4(xcrb->request_control_blk_length);349 size_t req_cblen, rep_cblen, req_sumlen, rep_sumlen;
346 int req_sumlen, resp_sumlen;350 char *function_code, *req_data;
347 char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen;
348 char *function_code;
349
350 if (CEIL4(xcrb->request_control_blk_length) <
351 xcrb->request_control_blk_length)
352 return -EINVAL; /* overflow after alignment*/
353 351
354 /* length checks */352 /* request length and overflow checks */
355 ap_msg->len = sizeof(struct type6_hdr) +353 if (xcrb->request_control_blk_length < sizeof(struct CPRBX))
356 CEIL4(xcrb->request_control_blk_length) +354 return -EINVAL;
357 xcrb->request_data_length;355 req_cblen = CEIL4((size_t)xcrb->request_control_blk_length);
356 if (req_cblen > U32_MAX)
357 return -EINVAL;
358 req_sumlen = req_cblen + xcrb->request_data_length;
359 if (req_sumlen > U32_MAX)
360 return -EINVAL;
361 ap_msg->len = sizeof(struct type6_hdr) + req_sumlen;
358 if (ap_msg->len > ap_msg->bufsize)362 if (ap_msg->len > ap_msg->bufsize)
359 return -EINVAL;363 return -EINVAL;
360 364 if (req_cblen <= xcrb->request_data_length ?
361 /*
362 * Overflow check
363 * sum must be greater (or equal) than the largest operand
364 */
365 req_sumlen = CEIL4(xcrb->request_control_blk_length) +
366 xcrb->request_data_length;
367 if ((CEIL4(xcrb->request_control_blk_length) <=
368 xcrb->request_data_length) ?
369 req_sumlen < xcrb->request_data_length :365 req_sumlen < xcrb->request_data_length :
370 req_sumlen < CEIL4(xcrb->request_control_blk_length)) {366 req_sumlen < req_cblen) {
371 return -EINVAL;367 return -EINVAL;
372 }368 }
373 369
374 if (CEIL4(xcrb->reply_control_blk_length) <370 /* reply length and overflow checks */
375 xcrb->reply_control_blk_length)371 if (xcrb->reply_control_blk_length < sizeof(struct CPRBX))
376 return -EINVAL; /* overflow after alignment*/372 return -EINVAL;
377 373 rep_cblen = CEIL4((size_t)xcrb->reply_control_blk_length);
378 /*374 if (rep_cblen > U32_MAX)
379 * Overflow check375 return -EINVAL;
380 * sum must be greater (or equal) than the largest operand376 rep_sumlen = rep_cblen + xcrb->reply_data_length;
381 */377 if (rep_sumlen > U32_MAX)
382 resp_sumlen = CEIL4(xcrb->reply_control_blk_length) +378 return -EINVAL;
383 xcrb->reply_data_length;379 if (rep_cblen <= xcrb->reply_data_length ?
384 if ((CEIL4(xcrb->reply_control_blk_length) <=380 rep_sumlen < xcrb->reply_data_length :
385 xcrb->reply_data_length) ?381 rep_sumlen < rep_cblen) {
386 resp_sumlen < xcrb->reply_data_length :
387 resp_sumlen < CEIL4(xcrb->reply_control_blk_length)) {
388 return -EINVAL;382 return -EINVAL;
389 }383 }
390 384
@@ -393,7 +387,7 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, · 2 unmodified lines
393 memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID));387 memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID));
394 msg->hdr.tocardlen1 = xcrb->request_control_blk_length;388 msg->hdr.tocardlen1 = xcrb->request_control_blk_length;
395 if (xcrb->request_data_length) {389 if (xcrb->request_data_length) {
396 msg->hdr.offset2 = msg->hdr.offset1 + rcblen;390 msg->hdr.offset2 = msg->hdr.offset1 + req_cblen;
397 msg->hdr.tocardlen2 = xcrb->request_data_length;391 msg->hdr.tocardlen2 = xcrb->request_data_length;
398 }392 }
399 msg->hdr.fromcardlen1 = xcrb->reply_control_blk_length;393 msg->hdr.fromcardlen1 = xcrb->reply_control_blk_length;
@@ -404,8 +398,12 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, · 4 unmodified lines
404 xcrb->request_control_blk_addr,398 xcrb->request_control_blk_addr,
405 xcrb->request_control_blk_length))399 xcrb->request_control_blk_length))
406 return -EFAULT;400 return -EFAULT;
407 if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >401 /* pad tail with 0 up to req_cblen */
408 xcrb->request_control_blk_length)402 if (xcrb->request_control_blk_length < req_cblen)
403 memset(msg->userdata + xcrb->request_control_blk_length,
404 0, req_cblen - xcrb->request_control_blk_length);
405 /* copy subfunction code into AP msg type 6 function code field */
406 if (msg->cprbx.cprb_len > req_cblen - sizeof(msg->hdr.function_code))
409 return -EINVAL;407 return -EINVAL;
410 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;408 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
411 memcpy(msg->hdr.function_code, function_code,409 memcpy(msg->hdr.function_code, function_code,
@@ -437,20 +435,70 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, · 25 unmodified lines
437 }435 }
438 436
439 /* copy data block */437 /* copy data block */
440 if (xcrb->request_data_length &&438 if (xcrb->request_data_length) {
441 z_copy_from_user(userspace, req_data, xcrb->request_data_address,439 req_data = ap_msg->msg + sizeof(struct type6_hdr) + req_cblen;
442 xcrb->request_data_length))440 if (z_copy_from_user(userspace, req_data,
443 return -EFAULT;441 xcrb->request_data_address,
442 xcrb->request_data_length))
443 return -EFAULT;
444 }
444 445
445 return 0;446 return 0;
446}447}
447 448
449/*
450 * Simple asn1 int reader/decoder helper function
451 * Returns number of bytes processed or < 0 on failure
452 * Only accepts int length values of 1, 2 or 4.
453 */
454static inline int asn1_int_decode(const u8 *buf, size_t intlen, u32 *u)
455{
456 switch (intlen) {
457 case 1:
458 *u = (u32)(*buf);
459 return 1;
460 case 2:
461 *u = (u32)get_unaligned_be16(buf);
462 return 2;
463 case 4:
464 *u = (u32)get_unaligned_be32(buf);
465 return 4;
466 default:
467 return -EINVAL;
468 }
469}
470
471/*
472 * Simple asn1 length parse helper function
473 * Returns number of bytes processed or < 0 on failure
474 * Only accepts length encoded within the length octet
475 * or for long form 1, 2 or 4 octet length bytes.
476 */
477static inline int asn1_length_decode(const u8 *buf, size_t buflen, u32 *u)
478{
479 int i;
480
481 if (buflen < 1)
482 return -EINVAL;
483
484 if (*buf < 128) {
485 *u = (u32)(*buf & 0x7F);
486 return 1;
487 }
488
489 i = *buf & 0x7F;
490 if (--buflen < i)
491 return -EINVAL;
492 i = asn1_int_decode(++buf, i, u);
493
494 return i < 0 ? i : i + 1;
495}
496
448static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg,497static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg,
449 struct ep11_urb *xcrb,498 struct ep11_urb *xcrb,
450 unsigned int *fcode,499 unsigned int *fcode,
451 unsigned int *domain)500 unsigned int *domain)
452{501{
453 unsigned int lfmt;
454 static struct type6_hdr static_type6_ep11_hdr = {502 static struct type6_hdr static_type6_ep11_hdr = {
455 .type = 0x06,503 .type = 0x06,
456 .rqid = {0x00, 0x01},504 .rqid = {0x00, 0x01},
@@ -462,34 +510,32 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap · 5 unmodified lines
462 struct {510 struct {
463 struct type6_hdr hdr;511 struct type6_hdr hdr;
464 union {512 union {
465 struct {513 struct ep11_cprb cprbx;
466 struct ep11_cprb cprbx;
467 unsigned char pld_tag; /* fixed value 0x30 */
468 unsigned char pld_lenfmt; /* length format */
469 } __packed;
470 DECLARE_FLEX_ARRAY(u8, userdata);514 DECLARE_FLEX_ARRAY(u8, userdata);
471 };515 };
472 } __packed * msg = ap_msg->msg;516 } __packed * msg = ap_msg->msg;
473 517
474 struct pld_hdr {518 size_t req_len, rep_len, pld_len;
475 unsigned char func_tag; /* fixed value 0x4 */519 unsigned char *pld;
476 unsigned char func_len; /* fixed value 0x4 */520 int offs = 0, i;
477 unsigned int func_val; /* function ID */521 unsigned int u;
478 unsigned char dom_tag; /* fixed value 0x4 */
479 unsigned char dom_len; /* fixed value 0x4 */
480 unsigned int dom_val; /* domain id */
481 } __packed * payload_hdr = NULL;
482 522
483 if (CEIL4(xcrb->req_len) < xcrb->req_len)523 /* request length and overflow checks */
484 return -EINVAL; /* overflow after alignment*/524 if (xcrb->req_len < sizeof(struct ep11_cprb) + MIN_EP11_PAYLOAD_SIZE)
485 525 return -EINVAL;
486 /* length checks */526 req_len = CEIL4(xcrb->req_len);
487 ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcrb->req_len);527 if (req_len < xcrb->req_len || req_len > U32_MAX)
528 return -EINVAL;
529 ap_msg->len = sizeof(struct type6_hdr) + req_len;
488 if (ap_msg->len > ap_msg->bufsize)530 if (ap_msg->len > ap_msg->bufsize)
489 return -EINVAL;531 return -EINVAL;
490 532
491 if (CEIL4(xcrb->resp_len) < xcrb->resp_len)533 /* reply length and overflow checks */
492 return -EINVAL; /* overflow after alignment*/534 if (xcrb->resp_len < sizeof(struct ep11_cprb))
535 return -EINVAL;
536 rep_len = CEIL4(xcrb->resp_len);
537 if (rep_len < xcrb->resp_len || rep_len > U32_MAX)
538 return -EINVAL;
493 539
494 /* prepare type6 header */540 /* prepare type6 header */
495 msg->hdr = static_type6_ep11_hdr;541 msg->hdr = static_type6_ep11_hdr;
@@ -498,26 +544,55 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap · 2 unmodified lines
498 544
499 /* Import CPRB data from the ioctl input parameter */545 /* Import CPRB data from the ioctl input parameter */
500 if (z_copy_from_user(userspace, msg->userdata,546 if (z_copy_from_user(userspace, msg->userdata,
501 (char __force __user *)xcrb->req, xcrb->req_len)) {547 (char __force __user *)xcrb->req, xcrb->req_len))
502 return -EFAULT;548 return -EFAULT;
503 }549 /* pad tail with 0 up to req_len */
550 if (xcrb->req_len < req_len)
551 memset(msg->userdata + xcrb->req_len, 0,
552 req_len - xcrb->req_len);
553
554 pld = msg->userdata + sizeof(struct ep11_cprb);
555 pld_len = msg->cprbx.payload_len;
556 if (pld_len != xcrb->req_len - sizeof(struct ep11_cprb))
557 return -EINVAL;
558 /*
559 * At this point pld_len is always >= MIN_EP11_PAYLOAD_SIZE
560 * and the smallest supported asn1 payload is:
561 * payload tag (1 octet)
562 * payload length (1-5 octets)
563 * function tag (1 octet)
564 * function length (1-5 octets)
565 * function value (1-4 octets)
566 */
504 567
505 if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/568 /* payload tag */
506 switch (msg->pld_lenfmt & 0x03) {569 if (pld[offs++] != 0x30)
507 case 1:570 return -EINVAL;
508 lfmt = 2;571 /* payload length field */
509 break;572 i = asn1_length_decode(pld + offs, pld_len - offs, &u);
510 case 2:573 if (i < 0)
511 lfmt = 3;574 return -EINVAL;
512 break;575 offs += i;
513 default:576 if (offs >= pld_len || u > pld_len - offs)
514 return -EINVAL;577 return -EINVAL;
515 }578 /* function tag */
516 } else {579 if (pld[offs++] != 0x04)
517 lfmt = 1; /* length format #1 */580 return -EINVAL;
518 }581 /* function length */
519 payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt);582 if (offs >= pld_len)
520 *fcode = payload_hdr->func_val & 0xFFFF;583 return -EINVAL;
584 i = asn1_length_decode(pld + offs, pld_len - offs, &u);
585 if (i < 0)
586 return -EINVAL;
587 offs += i;
588 if (offs >= pld_len || u > pld_len - offs)
589 return -EINVAL;
590 /* function value */
591 i = asn1_int_decode(pld + offs, u, &u);
592 if (i < 0)
593 return -EINVAL;
594 offs += i;
595 *fcode = 0xFFFF & u;
521 596
522 /* enable special processing based on the cprbs flags special bit */597 /* enable special processing based on the cprbs flags special bit */
523 if (msg->cprbx.flags & 0x20)598 if (msg->cprbx.flags & 0x20)
@@ -1159,6 +1234,28 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb, · 635 unmodified lines
1159 func_code, domain);1234 func_code, domain);
1160}1235}
1161 1236
1237/*
1238 * Simple asn1 int writer/encoder helper function
1239 * Returns number of bytes processed or < 0 on failure
1240 * Only accepts int length values of 1, 2 or 4.
1241 */
1242static inline int asn1_int_encode(u8 *buf, size_t intlen, u32 u)
1243{
1244 switch (intlen) {
1245 case 1:
1246 *buf = (u8)u;
1247 return 1;
1248 case 2:
1249 put_unaligned_be16((u16)u, buf);
1250 return 2;
1251 case 4:
1252 put_unaligned_be32((u32)u, buf);
1253 return 4;
1254 default:
1255 return -EINVAL;
1256 }
1257}
1258
1162/*1259/*
1163 * The request distributor calls this function if it picked the CEX4P1260 * The request distributor calls this function if it picked the CEX4P
1164 * device to handle a send_ep11_cprb request.1261 * device to handle a send_ep11_cprb request.
@@ -1171,51 +1268,94 @@ static long zcrypt_msgtype6_send_ep11_cprb(bool userspace, struct zcrypt_queue * · 6 unmodified lines
1171 struct ap_message *ap_msg)1268 struct ap_message *ap_msg)
1172{1269{
1173 int rc;1270 int rc;
1174 unsigned int lfmt;
1175 struct ap_response_type *resp_type = &ap_msg->response;1271 struct ap_response_type *resp_type = &ap_msg->response;
1176 struct {1272 struct {
1177 struct type6_hdr hdr;1273 struct type6_hdr hdr;
1178 struct ep11_cprb cprbx;1274 struct ep11_cprb cprbx;
1179 unsigned char pld_tag; /* fixed value 0x30 */
1180 unsigned char pld_lenfmt; /* payload length format */
1181 } __packed * msg = ap_msg->msg;1275 } __packed * msg = ap_msg->msg;
1182 struct pld_hdr {
1183 unsigned char func_tag; /* fixed value 0x4 */
1184 unsigned char func_len; /* fixed value 0x4 */
1185 unsigned int func_val; /* function ID */
1186 unsigned char dom_tag; /* fixed value 0x4 */
1187 unsigned char dom_len; /* fixed value 0x4 */
1188 unsigned int dom_val; /* domain id */
1189 } __packed * payload_hdr = NULL;
1190 1276
1191 /*1277 /*
1192 * The target domain field within the cprb body/payload block will be1278 * The target domain field within the cprb body/payload block will be
1193 * replaced by the usage domain for non-management commands only.1279 * replaced by the usage domain for non-management commands only.
1194 * Therefore we check the first bit of the 'flags' parameter for1280 * Therefore we check the first bit of the 'flags' parameter for
1195 * management command indication.1281 * management command indication.
1196 * 0 - non management command
1197 * 1 - management command
1198 */1282 */
1199 if (!((msg->cprbx.flags & 0x80) == 0x80)) {1283 if (!(msg->cprbx.flags & 0x80)) {
1200 msg->cprbx.target_id = (unsigned int)1284 int i, offs = 0;
1201 AP_QID_QUEUE(zq->queue->qid);1285 size_t pld_len;
1202 1286 u8 *pld;
1203 if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/1287 u32 u;
1204 switch (msg->pld_lenfmt & 0x03) {1288
1205 case 1:1289 /* update target field in ep11_cprb */
1206 lfmt = 2;1290 msg->cprbx.target_id = (u32)AP_QID_QUEUE(zq->queue->qid);
1207 break;1291
1208 case 2:1292 /* ptr and length to payload */
1209 lfmt = 3;1293 pld = ap_msg->msg +
1210 break;1294 sizeof(struct type6_hdr) + sizeof(struct ep11_cprb);
1211 default:1295 pld_len = msg->cprbx.payload_len;
1296 if (pld_len < MIN_EP11_PAYLOAD_SIZE)
1297 return -EINVAL;
1298
1299 /*
1300 * Parse the asn1 payload, at least we have
1301 * pld tag (1 octet)
1302 * payload length (1-5 octets)
1303 * function tag (1 octet)
1304 * function length (1-5 octets)
1305 * function value (1-4 octets)
1306 * ----- optional fields -----
1307 * domain tag (1 octet)
1308 * domain length (1-5 octets)
1309 * domain value (1-4 octets)
1310 * ... maybe much more data ...
1311 */
1312
1313 /* payload tag */
1314 if (pld[offs++] != 0x30)
1315 return -EINVAL;
1316 /* payload length field */
1317 i = asn1_length_decode(pld + offs, pld_len - offs, &u);
1318 if (i < 0)
1319 return -EINVAL;
1320 offs += i;
1321 if (offs >= pld_len || u > pld_len - offs)
1322 return -EINVAL;
1323 /* function tag */
1324 if (pld[offs++] != 0x04)
1325 return -EINVAL;
1326 /* function length */
1327 if (offs >= pld_len)
1328 return -EINVAL;
1329 i = asn1_length_decode(pld + offs, pld_len - offs, &u);
1330 if (i < 0)
1331 return -EINVAL;
1332 offs += i;
1333 if (u > pld_len - offs)
1334 return -EINVAL;
1335 /* skip over the function value */
1336 offs += u;
1337 /* is there some payload left which could hold a domain value ? */
1338 if (offs < pld_len && pld_len - offs >= 3) {
1339 /* domain tag */
1340 if (pld[offs++] != 0x04)
1212 return -EINVAL;1341 return -EINVAL;
1213 }1342 /* domain length */
1214 } else {1343 i = asn1_length_decode(pld + offs, pld_len - offs, &u);
1215 lfmt = 1; /* length format #1 */1344 if (i < 0)
1345 return -EINVAL;
1346 offs += i;
1347 if (offs >= pld_len || u > pld_len - offs)
1348 return -EINVAL;
1349 /*
1350 * pld[offs] is now at the start of the domain value
1351 * with the value sprawled in u octets.
1352 */
1353 i = asn1_int_encode(pld + offs, u,
1354 AP_QID_QUEUE(zq->queue->qid));
1355 if (i < 0)
1356 return -EINVAL;
1357 offs += i;
1216 }1358 }
1217 payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt);
1218 payload_hdr->dom_val = AP_QID_QUEUE(zq->queue->qid);
1219 }1359 }
1220 1360
1221 /*1361 /*