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);