| @@ -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 1 | 35 | #define CEXXC_RESPONSE_TYPE_XCRB 1 |
| 35 | #define CEXXC_RESPONSE_TYPE_EP11 2 | 36 | #define CEXXC_RESPONSE_TYPE_EP11 2 |
| 36 | | 37 | |
| | 38 | /* smallest possible EP11 payload size */ |
| | 39 | #define MIN_EP11_PAYLOAD_SIZE 5 |
| | 40 | |
| 37 | MODULE_AUTHOR("IBM Corporation"); | 41 | MODULE_AUTHOR("IBM Corporation"); |
| 38 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ | 42 | MODULE_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 check | 375 | return -EINVAL; |
| 380 | * sum must be greater (or equal) than the largest operand | 376 | 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 | */ |
| | 454 | static 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 | */ |
| | 477 | static 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 | |
| 448 | static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg, | 497 | static 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 | */ |
| | 1242 | static 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 CEX4P | 1260 | * 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 be | 1278 | * 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 for | 1280 | * 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 | /* |