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
1515 #include <linux/module.h>
1616 #include <linux/slab.h>
1717 #include <linux/random.h>
18+#include <linux/align.h>
1819 #include <asm/zcrypt.h>
1920 #include <asm/pkey.h>
2021
@@ -267,6 +268,10 @@ EXPORT_SYMBOL(cca_check_sececckeytoken); · 246 unmodified lines
267268 * block, reply CPRB and reply param block and fill in values
268269 * for the common fields. Returns 0 on success or errno value
269270 * 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.
270275 */
271276 static int alloc_and_prep_cprbmem(size_t paramblen,
272277 u8 **p_cprb_mem,
@@ -275,7 +280,8 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 2 unmodified lines
275280 u32 xflags)
276281 {
277282 u8 *cprbmem = NULL;
278− size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;
283+ size_t cprbplusparamblen =
284+ ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
279285 size_t len = 2 * cprbplusparamblen;
280286 struct CPRBX *preqcblk, *prepcblk;
281287
@@ -302,10 +308,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 20 unmodified lines
302308 memcpy(preqcblk->func_id, "T2", 2);
303309 preqcblk->rpl_msgbl = cprbplusparamblen;
304310 if (paramblen) {
305− preqcblk->req_parmb =
306− ((u8 __user *)preqcblk) + sizeof(struct CPRBX);
307− preqcblk->rpl_parmb =
308− ((u8 __user *)prepcblk) + sizeof(struct CPRBX);
311+ preqcblk->req_parmb = ((u8 __user *)preqcblk) +
312+ ALIGN(sizeof(struct CPRBX), 4);
313+ preqcblk->rpl_parmb = ((u8 __user *)prepcblk) +
314+ ALIGN(sizeof(struct CPRBX), 4);
309315 }
310316
311317 *p_cprb_mem = cprbmem;
@@ -323,8 +329,10 @@ static int alloc_and_prep_cprbmem(size_t paramblen, · 11 unmodified lines
323329 */
324330 static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
325331 {
332+ size_t cprblen = ALIGN(sizeof(struct CPRBX), 4) + ALIGN(paramblen, 4);
333+
326334 if (mem && scrub)
327− memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
335+ memzero_explicit(mem, 2 * cprblen);
328336
329337 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
330338 mempool_free(mem, cprb_mempool);
drivers/s390/crypto/zcrypt_ep11misc.c+11−5
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/module.h>
1515 #include <linux/random.h>
1616 #include <linux/slab.h>
17+#include <linux/align.h>
1718 #include <asm/zcrypt.h>
1819 #include <asm/pkey.h>
1920 #include <crypto/aes.h>
@@ -355,21 +356,24 @@ EXPORT_SYMBOL(ep11_check_aes_key); · 335 unmodified lines
355356
356357 /*
357358 * 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).
358362 */
359363 static void *alloc_cprbmem(size_t payload_len, u32 xflags)
360364 {
361− size_t len = sizeof(struct ep11_cprb) + payload_len;
365+ size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
362366 struct ep11_cprb *cprb = NULL;
363367
364368 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
365− if (len <= CPRB_MEMPOOL_ITEM_SIZE)
369+ if (memlen <= CPRB_MEMPOOL_ITEM_SIZE)
366370 cprb = mempool_alloc_preallocated(cprb_mempool);
367371 } else {
368− cprb = kmalloc(len, GFP_KERNEL);
372+ cprb = kmalloc(memlen, GFP_KERNEL);
369373 }
370374 if (!cprb)
371375 return NULL;
372− memset(cprb, 0, len);
376+ memset(cprb, 0, memlen);
373377
374378 cprb->cprb_len = sizeof(struct ep11_cprb);
375379 cprb->cprb_ver_id = 0x04;
@@ -385,8 +389,10 @@ static void *alloc_cprbmem(size_t payload_len, u32 xflags) · 9 unmodified lines
385389 */
386390 static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)
387391 {
392+ size_t memlen = ALIGN(sizeof(struct ep11_cprb) + payload_len, 4);
393+
388394 if (mem && scrub)
389− memzero_explicit(mem, sizeof(struct ep11_cprb) + payload_len);
395+ memzero_explicit(mem, memlen);
390396
391397 if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
392398 mempool_free(mem, cprb_mempool);
drivers/s390/crypto/zcrypt_msgtype6.c+253−113
@@ -19,6 +19,7 @@ · 18 unmodified lines
1919 #include <linux/slab.h>
2020 #include <linux/atomic.h>
2121 #include <linux/uaccess.h>
22+#include <linux/unaligned.h>
2223
2324 #include "ap_bus.h"
2425 #include "zcrypt_api.h"
@@ -34,6 +35,9 @@ · 9 unmodified lines
3435 #define CEXXC_RESPONSE_TYPE_XCRB 1
3536 #define CEXXC_RESPONSE_TYPE_EP11 2
3637
38+/* smallest possible EP11 payload size */
39+#define MIN_EP11_PAYLOAD_SIZE 5
40+
3741 MODULE_AUTHOR("IBM Corporation");
3842 MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
3943 "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
342346 };
343347 } __packed * msg = ap_msg->msg;
344348
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;
353351
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;
358362 if (ap_msg->len > ap_msg->bufsize)
359363 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 ?
369365 req_sumlen < xcrb->request_data_length :
370− req_sumlen < CEIL4(xcrb->request_control_blk_length)) {
366+ req_sumlen < req_cblen) {
371367 return -EINVAL;
372368 }
373369
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) {
388382 return -EINVAL;
389383 }
390384
@@ -393,7 +387,7 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg, · 2 unmodified lines
393387 memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID));
394388 msg->hdr.tocardlen1 = xcrb->request_control_blk_length;
395389 if (xcrb->request_data_length) {
396− msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
390+ msg->hdr.offset2 = msg->hdr.offset1 + req_cblen;
397391 msg->hdr.tocardlen2 = xcrb->request_data_length;
398392 }
399393 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
404398 xcrb->request_control_blk_addr,
405399 xcrb->request_control_blk_length))
406400 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))
409407 return -EINVAL;
410408 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
411409 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
437435 }
438436
439437 /* 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+ }
444445
445446 return 0;
446447 }
447448
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+
448497 static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap_msg,
449498 struct ep11_urb *xcrb,
450499 unsigned int *fcode,
451500 unsigned int *domain)
452501 {
453− unsigned int lfmt;
454502 static struct type6_hdr static_type6_ep11_hdr = {
455503 .type = 0x06,
456504 .rqid = {0x00, 0x01},
@@ -462,34 +510,32 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap · 5 unmodified lines
462510 struct {
463511 struct type6_hdr hdr;
464512 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;
470514 DECLARE_FLEX_ARRAY(u8, userdata);
471515 };
472516 } __packed * msg = ap_msg->msg;
473517
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;
482522
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;
488530 if (ap_msg->len > ap_msg->bufsize)
489531 return -EINVAL;
490532
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;
493539
494540 /* prepare type6 header */
495541 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
498544
499545 /* Import CPRB data from the ioctl input parameter */
500546 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))
502548 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+ */
504567
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;
521596
522597 /* enable special processing based on the cprbs flags special bit */
523598 if (msg->cprbx.flags & 0x20)
@@ -1159,6 +1234,28 @@ int prep_ep11_ap_msg(bool userspace, struct ep11_urb *xcrb, · 635 unmodified lines
11591234 func_code, domain);
11601235 }
11611236
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+
11621259 /*
11631260 * The request distributor calls this function if it picked the CEX4P
11641261 * 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
11711268 struct ap_message *ap_msg)
11721269 {
11731270 int rc;
1174− unsigned int lfmt;
11751271 struct ap_response_type *resp_type = &ap_msg->response;
11761272 struct {
11771273 struct type6_hdr hdr;
11781274 struct ep11_cprb cprbx;
1179− unsigned char pld_tag; /* fixed value 0x30 */
1180− unsigned char pld_lenfmt; /* payload length format */
11811275 } __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;
11901276
11911277 /*
11921278 * The target domain field within the cprb body/payload block will be
11931279 * replaced by the usage domain for non-management commands only.
11941280 * Therefore we check the first bit of the 'flags' parameter for
11951281 * management command indication.
1196− * 0 - non management command
1197− * 1 - management command
11981282 */
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)
12121341 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;
12161358 }
1217− payload_hdr = (struct pld_hdr *)((&msg->pld_lenfmt) + lfmt);
1218− payload_hdr->dom_val = AP_QID_QUEUE(zq->queue->qid);
12191359 }
12201360
12211361 /*