| @@ -19,6 +19,7 @@ · 18 unmodified lines |
| 19 | 19 | #include <linux/slab.h> |
| 20 | 20 | #include <linux/atomic.h> |
| 21 | 21 | #include <linux/uaccess.h> |
| 22 | +#include <linux/unaligned.h> |
| 22 | 23 | |
| 23 | 24 | #include "ap_bus.h" |
| 24 | 25 | #include "zcrypt_api.h" |
| @@ -34,6 +35,9 @@ · 9 unmodified lines |
| 34 | 35 | #define CEXXC_RESPONSE_TYPE_XCRB 1 |
| 35 | 36 | #define CEXXC_RESPONSE_TYPE_EP11 2 |
| 36 | 37 | |
| 38 | +/* smallest possible EP11 payload size */ |
| 39 | +#define MIN_EP11_PAYLOAD_SIZE 5 |
| 40 | + |
| 37 | 41 | MODULE_AUTHOR("IBM Corporation"); |
| 38 | 42 | MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ |
| 39 | 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 | 347 | } __packed * msg = ap_msg->msg; |
| 344 | 348 | |
| 345 | | − int rcblen = CEIL4(xcrb->request_control_blk_length); |
| 346 | | − int req_sumlen, resp_sumlen; |
| 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*/ |
| 349 | + size_t req_cblen, rep_cblen, req_sumlen, rep_sumlen; |
| 350 | + char *function_code, *req_data; |
| 353 | 351 | |
| 354 | | − /* length checks */ |
| 355 | | − ap_msg->len = sizeof(struct type6_hdr) + |
| 356 | | − CEIL4(xcrb->request_control_blk_length) + |
| 357 | | − xcrb->request_data_length; |
| 352 | + /* request length and overflow checks */ |
| 353 | + if (xcrb->request_control_blk_length < sizeof(struct CPRBX)) |
| 354 | + return -EINVAL; |
| 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 | 362 | if (ap_msg->len > ap_msg->bufsize) |
| 359 | 363 | return -EINVAL; |
| 360 | | − |
| 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) ? |
| 364 | + if (req_cblen <= xcrb->request_data_length ? |
| 369 | 365 | req_sumlen < xcrb->request_data_length : |
| 370 | | − req_sumlen < CEIL4(xcrb->request_control_blk_length)) { |
| 366 | + req_sumlen < req_cblen) { |
| 371 | 367 | return -EINVAL; |
| 372 | 368 | } |
| 373 | 369 | |
| 374 | | − if (CEIL4(xcrb->reply_control_blk_length) < |
| 375 | | − xcrb->reply_control_blk_length) |
| 376 | | − return -EINVAL; /* overflow after alignment*/ |
| 377 | | − |
| 378 | | − /* |
| 379 | | − * Overflow check |
| 380 | | − * sum must be greater (or equal) than the largest operand |
| 381 | | − */ |
| 382 | | − resp_sumlen = CEIL4(xcrb->reply_control_blk_length) + |
| 383 | | − xcrb->reply_data_length; |
| 384 | | − if ((CEIL4(xcrb->reply_control_blk_length) <= |
| 385 | | − xcrb->reply_data_length) ? |
| 386 | | − resp_sumlen < xcrb->reply_data_length : |
| 387 | | − resp_sumlen < CEIL4(xcrb->reply_control_blk_length)) { |
| 370 | + /* reply length and overflow checks */ |
| 371 | + if (xcrb->reply_control_blk_length < sizeof(struct CPRBX)) |
| 372 | + return -EINVAL; |
| 373 | + rep_cblen = CEIL4((size_t)xcrb->reply_control_blk_length); |
| 374 | + if (rep_cblen > U32_MAX) |
| 375 | + return -EINVAL; |
| 376 | + rep_sumlen = rep_cblen + xcrb->reply_data_length; |
| 377 | + if (rep_sumlen > U32_MAX) |
| 378 | + return -EINVAL; |
| 379 | + if (rep_cblen <= xcrb->reply_data_length ? |
| 380 | + rep_sumlen < xcrb->reply_data_length : |
| 381 | + rep_sumlen < rep_cblen) { |
| 388 | 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 | 387 | memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID)); |
| 394 | 388 | msg->hdr.tocardlen1 = xcrb->request_control_blk_length; |
| 395 | 389 | if (xcrb->request_data_length) { |
| 396 | | − msg->hdr.offset2 = msg->hdr.offset1 + rcblen; |
| 390 | + msg->hdr.offset2 = msg->hdr.offset1 + req_cblen; |
| 397 | 391 | msg->hdr.tocardlen2 = xcrb->request_data_length; |
| 398 | 392 | } |
| 399 | 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 | 398 | xcrb->request_control_blk_addr, |
| 405 | 399 | xcrb->request_control_blk_length)) |
| 406 | 400 | return -EFAULT; |
| 407 | | − if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > |
| 408 | | − xcrb->request_control_blk_length) |
| 401 | + /* pad tail with 0 up to req_cblen */ |
| 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 | 407 | return -EINVAL; |
| 410 | 408 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; |
| 411 | 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 | 437 | /* copy data block */ |
| 440 | | − if (xcrb->request_data_length && |
| 441 | | − z_copy_from_user(userspace, req_data, xcrb->request_data_address, |
| 442 | | − xcrb->request_data_length)) |
| 443 | | − return -EFAULT; |
| 438 | + if (xcrb->request_data_length) { |
| 439 | + req_data = ap_msg->msg + sizeof(struct type6_hdr) + req_cblen; |
| 440 | + if (z_copy_from_user(userspace, req_data, |
| 441 | + xcrb->request_data_address, |
| 442 | + xcrb->request_data_length)) |
| 443 | + return -EFAULT; |
| 444 | + } |
| 444 | 445 | |
| 445 | 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 | 497 | static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg, |
| 449 | 498 | struct ep11_urb *xcrb, |
| 450 | 499 | unsigned int *fcode, |
| 451 | 500 | unsigned int *domain) |
| 452 | 501 | { |
| 453 | | − unsigned int lfmt; |
| 454 | 502 | static struct type6_hdr static_type6_ep11_hdr = { |
| 455 | 503 | .type = 0x06, |
| 456 | 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 | 510 | struct { |
| 463 | 511 | struct type6_hdr hdr; |
| 464 | 512 | union { |
| 465 | | − struct { |
| 466 | | − struct ep11_cprb cprbx; |
| 467 | | − unsigned char pld_tag; /* fixed value 0x30 */ |
| 468 | | − unsigned char pld_lenfmt; /* length format */ |
| 469 | | − } __packed; |
| 513 | + struct ep11_cprb cprbx; |
| 470 | 514 | DECLARE_FLEX_ARRAY(u8, userdata); |
| 471 | 515 | }; |
| 472 | 516 | } __packed * msg = ap_msg->msg; |
| 473 | 517 | |
| 474 | | − struct pld_hdr { |
| 475 | | − unsigned char func_tag; /* fixed value 0x4 */ |
| 476 | | − unsigned char func_len; /* fixed value 0x4 */ |
| 477 | | − unsigned int func_val; /* function ID */ |
| 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; |
| 518 | + size_t req_len, rep_len, pld_len; |
| 519 | + unsigned char *pld; |
| 520 | + int offs = 0, i; |
| 521 | + unsigned int u; |
| 482 | 522 | |
| 483 | | − if (CEIL4(xcrb->req_len) < xcrb->req_len) |
| 484 | | − return -EINVAL; /* overflow after alignment*/ |
| 485 | | − |
| 486 | | − /* length checks */ |
| 487 | | − ap_msg->len = sizeof(struct type6_hdr) + CEIL4(xcrb->req_len); |
| 523 | + /* request length and overflow checks */ |
| 524 | + if (xcrb->req_len < sizeof(struct ep11_cprb) + MIN_EP11_PAYLOAD_SIZE) |
| 525 | + return -EINVAL; |
| 526 | + req_len = 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 | 530 | if (ap_msg->len > ap_msg->bufsize) |
| 489 | 531 | return -EINVAL; |
| 490 | 532 | |
| 491 | | − if (CEIL4(xcrb->resp_len) < xcrb->resp_len) |
| 492 | | − return -EINVAL; /* overflow after alignment*/ |
| 533 | + /* reply length and overflow checks */ |
| 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 | 540 | /* prepare type6 header */ |
| 495 | 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 | 545 | /* Import CPRB data from the ioctl input parameter */ |
| 500 | 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 | 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*/ |
| 506 | | − switch (msg->pld_lenfmt & 0x03) { |
| 507 | | − case 1: |
| 508 | | − lfmt = 2; |
| 509 | | − break; |
| 510 | | − case 2: |
| 511 | | − lfmt = 3; |
| 512 | | − break; |
| 513 | | − default: |
| 514 | | − return -EINVAL; |
| 515 | | − } |
| 516 | | − } else { |
| 517 | | − lfmt = 1; /* length format #1 */ |
| 518 | | − } |
| 519 | | − payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt); |
| 520 | | − *fcode = payload_hdr->func_val & 0xFFFF; |
| 568 | + /* payload tag */ |
| 569 | + if (pld[offs++] != 0x30) |
| 570 | + return -EINVAL; |
| 571 | + /* payload length field */ |
| 572 | + i = asn1_length_decode(pld + offs, pld_len - offs, &u); |
| 573 | + if (i < 0) |
| 574 | + return -EINVAL; |
| 575 | + offs += i; |
| 576 | + if (offs >= pld_len || u > pld_len - offs) |
| 577 | + return -EINVAL; |
| 578 | + /* function tag */ |
| 579 | + if (pld[offs++] != 0x04) |
| 580 | + return -EINVAL; |
| 581 | + /* function length */ |
| 582 | + if (offs >= pld_len) |
| 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 | 597 | /* enable special processing based on the cprbs flags special bit */ |
| 523 | 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 | 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 | 1260 | * The request distributor calls this function if it picked the CEX4P |
| 1164 | 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 | 1268 | struct ap_message *ap_msg) |
| 1172 | 1269 | { |
| 1173 | 1270 | int rc; |
| 1174 | | − unsigned int lfmt; |
| 1175 | 1271 | struct ap_response_type *resp_type = &ap_msg->response; |
| 1176 | 1272 | struct { |
| 1177 | 1273 | struct type6_hdr hdr; |
| 1178 | 1274 | struct ep11_cprb cprbx; |
| 1179 | | − unsigned char pld_tag; /* fixed value 0x30 */ |
| 1180 | | − unsigned char pld_lenfmt; /* payload length format */ |
| 1181 | 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 | 1278 | * The target domain field within the cprb body/payload block will be |
| 1193 | 1279 | * replaced by the usage domain for non-management commands only. |
| 1194 | 1280 | * Therefore we check the first bit of the 'flags' parameter for |
| 1195 | 1281 | * management command indication. |
| 1196 | | − * 0 - non management command |
| 1197 | | − * 1 - management command |
| 1198 | 1282 | */ |
| 1199 | | − if (!((msg->cprbx.flags & 0x80) == 0x80)) { |
| 1200 | | − msg->cprbx.target_id = (unsigned int) |
| 1201 | | − AP_QID_QUEUE(zq->queue->qid); |
| 1202 | | − |
| 1203 | | − if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ |
| 1204 | | − switch (msg->pld_lenfmt & 0x03) { |
| 1205 | | − case 1: |
| 1206 | | − lfmt = 2; |
| 1207 | | − break; |
| 1208 | | − case 2: |
| 1209 | | − lfmt = 3; |
| 1210 | | − break; |
| 1211 | | − default: |
| 1283 | + if (!(msg->cprbx.flags & 0x80)) { |
| 1284 | + int i, offs = 0; |
| 1285 | + size_t pld_len; |
| 1286 | + u8 *pld; |
| 1287 | + u32 u; |
| 1288 | + |
| 1289 | + /* update target field in ep11_cprb */ |
| 1290 | + msg->cprbx.target_id = (u32)AP_QID_QUEUE(zq->queue->qid); |
| 1291 | + |
| 1292 | + /* ptr and length to payload */ |
| 1293 | + pld = ap_msg->msg + |
| 1294 | + sizeof(struct type6_hdr) + sizeof(struct ep11_cprb); |
| 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 | 1341 | return -EINVAL; |
| 1213 | | − } |
| 1214 | | − } else { |
| 1215 | | − lfmt = 1; /* length format #1 */ |
| 1342 | + /* domain length */ |
| 1343 | + i = asn1_length_decode(pld + offs, pld_len - offs, &u); |
| 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 | /* |