From 8794c5961394b7fb8a69f43eaad9566e5496c0c8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 14 Feb 2023 17:13:18 +0100 Subject: [PATCH] s390/zcrypt: rework length information for dqap The inline ap_dqap function does not return the number of bytes actually written into the message buffer. The calling code inspects the AP message header to figure out what kind of AP message has been received and pulls the length information from this header. This processing may not work correctly in cases where only a fragment of the reply is received. With this patch the ap_dqap inline function now returns the number of actually written bytes in the *length parameter. So the calling function has a chance to compare the number of received bytes against what the AP message header length field states. This is especially useful in cases where a message could only get partially received. The low level reply processing functions needed some rework to be able to catch this new length information and compare it the right way. The rework also deals with some situations where until now the reply length was not correctly calculated and/or set. All this has been heavily tested as the modifications on the reply length information may affect crypto load. Signed-off-by: Harald Freudenberger Reviewed-by: Holger Dengler Signed-off-by: Heiko Carstens --- arch/s390/include/asm/ap.h | 18 +++++++---- drivers/s390/crypto/ap_bus.h | 8 ++--- drivers/s390/crypto/ap_queue.c | 16 +++++----- drivers/s390/crypto/zcrypt_cex2c.c | 3 +- drivers/s390/crypto/zcrypt_msgtype50.c | 11 ++++--- drivers/s390/crypto/zcrypt_msgtype6.c | 41 +++++++++++++++++--------- 6 files changed, 60 insertions(+), 37 deletions(-) diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 0744a00f92a5..6bb536e87897 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -359,10 +359,11 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, * ap_dqap(): Receive message from adjunct processor queue. * @qid: The AP queue number * @psmid: Pointer to program supplied message identifier - * @msg: The message text - * @length: The message length - * @reslength: Resitual length on return - * @resgr0: input: gr0 value (only used if != 0), output: resitual gr0 content + * @msg: Pointer to message buffer + * @msglen: Message buffer size + * @length: Pointer to length of actually written bytes + * @reslength: Residual length on return + * @resgr0: input: gr0 value (only used if != 0), output: residual gr0 content * * Returns AP queue status structure. * Condition code 1 on DQAP means the receive has taken place @@ -387,7 +388,8 @@ static inline struct ap_queue_status ap_nqap(ap_qid_t qid, */ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, unsigned long *psmid, - void *msg, size_t length, + void *msg, size_t msglen, + size_t *length, size_t *reslength, unsigned long *resgr0) { @@ -399,7 +401,7 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, rp1.even = 0UL; rp1.odd = 0UL; rp2.even = (unsigned long)msg; - rp2.odd = (unsigned long)length; + rp2.odd = (unsigned long)msglen; asm volatile( " lgr 0,%[reg0]\n" /* qid param into gr0 */ @@ -434,6 +436,10 @@ static inline struct ap_queue_status ap_dqap(ap_qid_t qid, *resgr0 = 0; } + /* update *length with the nr of bytes stored into the msg buffer */ + if (length) + *length = msglen - rp2.odd; + return reg1.status; } diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 4ef8e6ac6323..b5d7ccbc0784 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -244,8 +244,8 @@ struct ap_message { struct list_head list; /* Request queueing. */ unsigned long psmid; /* Message id. */ void *msg; /* Pointer to message buffer. */ - unsigned int len; /* actual msg len in msg buffer */ - unsigned int bufsize; /* allocated msg buffer size */ + size_t len; /* actual msg len in msg buffer */ + size_t bufsize; /* allocated msg buffer size */ u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ struct ap_fi fi; /* Failure Injection cmd */ int rc; /* Return code for this message */ @@ -285,8 +285,8 @@ static inline void ap_release_message(struct ap_message *ap_msg) * for the first time. Otherwise the ap message queue will get * confused. */ -int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t length); -int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t length); +int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen); +int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen); enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event); diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 2fe8cbf72091..bbd314918a5d 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -59,7 +59,7 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) * @qid: The AP queue number * @psmid: The program supplied message identifier * @msg: The message text - * @length: The message length + * @msglen: The message length * @special: Special Bit * * Returns AP queue status structure. @@ -68,19 +68,19 @@ static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) * because a segment boundary was reached. The NQAP is repeated. */ static inline struct ap_queue_status -__ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t length, +__ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen, int special) { if (special) qid |= 0x400000UL; - return ap_nqap(qid, psmid, msg, length); + return ap_nqap(qid, psmid, msg, msglen); } -int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t length) +int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t msglen) { struct ap_queue_status status; - status = __ap_send(qid, psmid, msg, length, 0); + status = __ap_send(qid, psmid, msg, msglen, 0); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -95,13 +95,13 @@ int ap_send(ap_qid_t qid, unsigned long psmid, void *msg, size_t length) } EXPORT_SYMBOL(ap_send); -int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t length) +int ap_recv(ap_qid_t qid, unsigned long *psmid, void *msg, size_t msglen) { struct ap_queue_status status; if (!msg) return -EINVAL; - status = ap_dqap(qid, psmid, msg, length, NULL, NULL); + status = ap_dqap(qid, psmid, msg, msglen, NULL, NULL, NULL); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -150,7 +150,7 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) do { status = ap_dqap(aq->qid, &aq->reply->psmid, aq->reply->msg, aq->reply->bufsize, - &reslen, &resgr0); + &aq->reply->len, &reslen, &resgr0); parts++; } while (status.response_code == 0xFF && resgr0 != 0); diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c index 9cabe3937c9a..4dacf5f6461f 100644 --- a/drivers/s390/crypto/zcrypt_cex2c.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -203,6 +203,7 @@ static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) ap_msg.msg = (void *)get_zeroed_page(GFP_KERNEL); if (!ap_msg.msg) return -ENOMEM; + ap_msg.bufsize = PAGE_SIZE; rng_type6cprb_msgx(&ap_msg, 4, &domain); @@ -216,7 +217,7 @@ static int zcrypt_cex2c_rng_supported(struct ap_queue *aq) /* Wait for the test message to complete. */ for (i = 0; i < 2 * HZ; i++) { msleep(1000 / HZ); - rc = ap_recv(aq->qid, &psmid, ap_msg.msg, 4096); + rc = ap_recv(aq->qid, &psmid, ap_msg.msg, ap_msg.bufsize); if (rc == 0 && psmid == 0x0102030405060708UL) break; } diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 1b6b60b7215b..05ace18c12b0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -441,14 +441,17 @@ static void zcrypt_cex2a_receive(struct ap_queue *aq, t80h = reply->msg; if (t80h->type == TYPE80_RSP_CODE) { len = t80h->len; - if (len > reply->bufsize || len > msg->bufsize) { + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete((struct completion *)msg->private); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 6c874808c356..914151c03753 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -938,28 +938,37 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq, t86r->cprbx.cprb_ver_id == 0x02) { switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_ICA: - len = sizeof(struct type86x_reply) + t86r->length - 2; - if (len > reply->bufsize || len > msg->bufsize) { + len = sizeof(struct type86x_reply) + t86r->length; + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; case CEXXC_RESPONSE_TYPE_XCRB: - len = t86r->fmt2.offset2 + t86r->fmt2.count2; - if (len > reply->bufsize || len > msg->bufsize) { + if (t86r->fmt2.count2) + len = t86r->fmt2.offset2 + t86r->fmt2.count2; + else + len = t86r->fmt2.offset1 + t86r->fmt2.count1; + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); + msg->len = sizeof(error_reply); } } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete(&resp_type->work); @@ -994,18 +1003,22 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, switch (resp_type->type) { case CEXXC_RESPONSE_TYPE_EP11: len = t86r->fmt2.offset1 + t86r->fmt2.count1; - if (len > reply->bufsize || len > msg->bufsize) { + if (len > reply->bufsize || len > msg->bufsize || + len != reply->len) { + ZCRYPT_DBF_DBG("%s len mismatch => EMSGSIZE\n", __func__); msg->rc = -EMSGSIZE; - } else { - memcpy(msg->msg, reply->msg, len); - msg->len = len; + goto out; } + memcpy(msg->msg, reply->msg, len); + msg->len = len; break; default: memcpy(msg->msg, &error_reply, sizeof(error_reply)); + msg->len = sizeof(error_reply); } } else { memcpy(msg->msg, reply->msg, sizeof(error_reply)); + msg->len = sizeof(error_reply); } out: complete(&resp_type->work);