diff options
| author | Harald Freudenberger <freude@linux.ibm.com> | 2026-10-06 17:46:03 +0200 |
|---|---|---|
| committer | Heiko Carstens <hca@linux.ibm.com> | 2026-10-09 15:54:04 +0200 |
| commit | 9fd7fca66735307fd7afa3450882a55ef80f2add (patch) | |
| tree | 8c98a4d15d8e7c8fce00a2761028aff3a033fdc5 | |
| parent | 7b88e8b6d714cd1b2b6185e2963c8ec4d98542d0 (diff) | |
| download | linux-9fd7fca66735307fd7afa3450882a55ef80f2add.tar.gz linux-9fd7fca66735307fd7afa3450882a55ef80f2add.zip | |
s390/zcrypt: Fix out-of-bounds ptr advance in cca_query_crypto_facility()
The FQ reply parser code blindly advanced the walk pointer by a length
value read directly from the hardware reply payload without checking
that the advance stayed within the allocated reply buffer. A corrupt
or malicious device response could push ptr beyond the cprbmem region,
causing an out-of-bounds dereference or kernel memory exposure via the
subsequent memcpy().
Fix this by tracking the remaining reply buffer space in a variable
and validating each device-supplied length field against it before
advancing or dereferencing the pointer.
Fixes: 2004b57cde6b ("s390/zcrypt: code cleanup")
Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Cc: stable@vger.kernel.org
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
| -rw-r--r-- | drivers/s390/crypto/zcrypt_ccamisc.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 19909bf43dc9..862947431164 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -1627,6 +1627,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, u8 subfunc_code[2]; u8 lvdata[]; } __packed * prepparm; + size_t datalen; /* get already prepared memory for 2 cprbs with param block each */ rc = alloc_and_prep_cprbmem(parmbsize, &mem, @@ -1673,27 +1674,44 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, prepcblk->rpl_parmb = (u8 __user *)ptr; prepparm = (struct fqrepparm *)ptr; ptr = prepparm->lvdata; + datalen = parmbsize - 2 * sizeof(u8); /* check and possibly copy reply rule array */ len = *((u16 *)ptr); + if (len > datalen) { + ZCRYPT_DBF_ERR("%s reply rule array len %u exceeds datalen %zu\n", + __func__, len, datalen); + rc = -EIO; + goto out; + } + datalen -= sizeof(u16); + ptr += sizeof(u16); if (len > sizeof(u16)) { - ptr += sizeof(u16); len -= sizeof(u16); if (rarray && rarraylen && *rarraylen > 0) { *rarraylen = (len > *rarraylen ? *rarraylen : len); memcpy(rarray, ptr, *rarraylen); } + datalen -= len; ptr += len; } /* check and possible copy reply var array */ len = *((u16 *)ptr); + if (len > datalen) { + ZCRYPT_DBF_ERR("%s reply var array len %u exceeds datalen %zu\n", + __func__, len, datalen); + rc = -EIO; + goto out; + } + datalen -= sizeof(u16); + ptr += sizeof(u16); if (len > sizeof(u16)) { - ptr += sizeof(u16); len -= sizeof(u16); if (varray && varraylen && *varraylen > 0) { *varraylen = (len > *varraylen ? *varraylen : len); memcpy(varray, ptr, *varraylen); } + datalen -= len; ptr += len; } |
