mirror of
https://github.com/torvalds/linux.git
synced 2026-09-20 01:20:03 +02:00
s390/zcrypt: Improve CCA CPRB length and overflow checks
The xcrb_msg_to_type6cprb_msgx() function lacks proper input
validation, creating security vulnerabilities:
1. Integer overflow after CEIL4 alignment: Signed int variables could
overflow during 4-byte boundary alignment, causing undersized
buffer allocations or incorrect bounds checking.
2. Missing minimum size validation: The CPRBX structure is copied from
userspace without verifying sufficient buffer length. Undersized
buffers cause uninitialized memory access when reading structure
fields like cprbx.cprb_len and cprbx.domain.
3. Arithmetic overflow in sum calculations: Adding control block and
data block sizes could overflow, bypassing size checks and enabling
buffer overflows.
Fix by using size_t for length calculations, adding U32_MAX boundary
checks after alignment, validating minimum control block size before
copying from userspace, and detecting sum calculation overflows.
Fixes: e2c6d91eb8 ("s390/zcrypt: Rework domain processing within zcrypt device driver")
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Cc: stable@vger.kernel.org # 7.1+
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
5004889551
commit
35ac6754ba
|
|
@ -342,49 +342,39 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
|
|||
};
|
||||
} __packed * msg = ap_msg->msg;
|
||||
|
||||
int rcblen = CEIL4(xcrb->request_control_blk_length);
|
||||
int req_sumlen, resp_sumlen;
|
||||
char *req_data = ap_msg->msg + sizeof(struct type6_hdr) + rcblen;
|
||||
char *function_code;
|
||||
size_t req_cblen, rep_cblen, req_sumlen, rep_sumlen;
|
||||
char *function_code, *req_data;
|
||||
|
||||
if (CEIL4(xcrb->request_control_blk_length) <
|
||||
xcrb->request_control_blk_length)
|
||||
return -EINVAL; /* overflow after alignment*/
|
||||
|
||||
/* length checks */
|
||||
ap_msg->len = sizeof(struct type6_hdr) +
|
||||
CEIL4(xcrb->request_control_blk_length) +
|
||||
xcrb->request_data_length;
|
||||
/* request length and overflow checks */
|
||||
if (xcrb->request_control_blk_length < sizeof(struct CPRBX))
|
||||
return -EINVAL;
|
||||
req_cblen = CEIL4((size_t)xcrb->request_control_blk_length);
|
||||
if (req_cblen > U32_MAX)
|
||||
return -EINVAL;
|
||||
req_sumlen = req_cblen + xcrb->request_data_length;
|
||||
if (req_sumlen > U32_MAX)
|
||||
return -EINVAL;
|
||||
ap_msg->len = sizeof(struct type6_hdr) + req_sumlen;
|
||||
if (ap_msg->len > ap_msg->bufsize)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Overflow check
|
||||
* sum must be greater (or equal) than the largest operand
|
||||
*/
|
||||
req_sumlen = CEIL4(xcrb->request_control_blk_length) +
|
||||
xcrb->request_data_length;
|
||||
if ((CEIL4(xcrb->request_control_blk_length) <=
|
||||
xcrb->request_data_length) ?
|
||||
if (req_cblen <= xcrb->request_data_length ?
|
||||
req_sumlen < xcrb->request_data_length :
|
||||
req_sumlen < CEIL4(xcrb->request_control_blk_length)) {
|
||||
req_sumlen < req_cblen) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (CEIL4(xcrb->reply_control_blk_length) <
|
||||
xcrb->reply_control_blk_length)
|
||||
return -EINVAL; /* overflow after alignment*/
|
||||
|
||||
/*
|
||||
* Overflow check
|
||||
* sum must be greater (or equal) than the largest operand
|
||||
*/
|
||||
resp_sumlen = CEIL4(xcrb->reply_control_blk_length) +
|
||||
xcrb->reply_data_length;
|
||||
if ((CEIL4(xcrb->reply_control_blk_length) <=
|
||||
xcrb->reply_data_length) ?
|
||||
resp_sumlen < xcrb->reply_data_length :
|
||||
resp_sumlen < CEIL4(xcrb->reply_control_blk_length)) {
|
||||
/* reply length and overflow checks */
|
||||
if (xcrb->reply_control_blk_length < sizeof(struct CPRBX))
|
||||
return -EINVAL;
|
||||
rep_cblen = CEIL4((size_t)xcrb->reply_control_blk_length);
|
||||
if (rep_cblen > U32_MAX)
|
||||
return -EINVAL;
|
||||
rep_sumlen = rep_cblen + xcrb->reply_data_length;
|
||||
if (rep_sumlen > U32_MAX)
|
||||
return -EINVAL;
|
||||
if (rep_cblen <= xcrb->reply_data_length ?
|
||||
rep_sumlen < xcrb->reply_data_length :
|
||||
rep_sumlen < rep_cblen) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +383,7 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
|
|||
memcpy(msg->hdr.agent_id, &xcrb->agent_ID, sizeof(xcrb->agent_ID));
|
||||
msg->hdr.tocardlen1 = xcrb->request_control_blk_length;
|
||||
if (xcrb->request_data_length) {
|
||||
msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
|
||||
msg->hdr.offset2 = msg->hdr.offset1 + req_cblen;
|
||||
msg->hdr.tocardlen2 = xcrb->request_data_length;
|
||||
}
|
||||
msg->hdr.fromcardlen1 = xcrb->reply_control_blk_length;
|
||||
|
|
@ -404,8 +394,8 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
|
|||
xcrb->request_control_blk_addr,
|
||||
xcrb->request_control_blk_length))
|
||||
return -EFAULT;
|
||||
if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
|
||||
xcrb->request_control_blk_length)
|
||||
/* copy subfunction code into AP msg type 6 function code field */
|
||||
if (msg->cprbx.cprb_len > req_cblen - sizeof(msg->hdr.function_code))
|
||||
return -EINVAL;
|
||||
function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
|
||||
memcpy(msg->hdr.function_code, function_code,
|
||||
|
|
@ -437,10 +427,13 @@ static int xcrb_msg_to_type6cprb_msgx(bool userspace, struct ap_message *ap_msg,
|
|||
}
|
||||
|
||||
/* copy data block */
|
||||
if (xcrb->request_data_length &&
|
||||
z_copy_from_user(userspace, req_data, xcrb->request_data_address,
|
||||
xcrb->request_data_length))
|
||||
return -EFAULT;
|
||||
if (xcrb->request_data_length) {
|
||||
req_data = ap_msg->msg + sizeof(struct type6_hdr) + req_cblen;
|
||||
if (z_copy_from_user(userspace, req_data,
|
||||
xcrb->request_data_address,
|
||||
xcrb->request_data_length))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user