mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 's390-7.2-6' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Vasily Gorbik: - Fix PCI MMIO write syscall falsely reporting success for mappings not valid for MMIO when MIO is unavailable by returning -EFAULT - Fix CPRB parameter buffer overflows in zcrypt CCA AES cipher and ECC private key conversion by rejecting oversized key tokens - Fix buffer overreads and length underflow in pkey and zcrypt CCA token validation by checking length fields against actual buffer sizes - Fix out of bounds permission bitmap access in zcrypt EP11 admin CPRB filtering on custom device nodes by using AP_DOMAINS as the limit - Fix speculative permission bitmap reads in zcrypt CCA and EP11 admin CPRB handling by sanitizing user controlled domain indexes - Fix sensitive key material left in zcrypt CCA clear key import buffers by scrubbing CPRB and temporary buffers after use * tag 's390-7.2-6' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/zcrypt: Fix missing mem scrub at clear key import in cca_clr2cipherkey() s390/zcrypt: Close speculative mem read possibility s390/zcrypt: Fix wrong domain value verification with EP11 CPRBs s390/zcrypt: Fix buffer over-read in cca_cipher2protkey s390/zcrypt: Validate length for CCA ECC private key requests s390/zcrypt: Validate length for CCA AES cipher key requests s390/pci: Fix s390_pci_mmio_write syscall error return without MIO
This commit is contained in:
@@ -188,6 +188,7 @@ SYSCALL_DEFINE3(s390_pci_mmio_write, unsigned long, mmio_addr,
|
||||
goto out_unlock_mmap;
|
||||
}
|
||||
|
||||
ret = -EFAULT;
|
||||
io_addr = (void __iomem *)((args.pfn << PAGE_SHIFT) |
|
||||
(mmio_addr & ~PAGE_MASK));
|
||||
|
||||
|
||||
@@ -236,22 +236,16 @@ static int cca_key2protkey(const struct pkey_apqn *apqns, size_t nr_apqns,
|
||||
if (hdr->type == TOKTYPE_CCA_INTERNAL &&
|
||||
hdr->version == TOKVER_CCA_AES) {
|
||||
/* CCA AES data key */
|
||||
if (keylen < sizeof(struct secaeskeytoken))
|
||||
return -EINVAL;
|
||||
if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0))
|
||||
if (cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0))
|
||||
return -EINVAL;
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL &&
|
||||
hdr->version == TOKVER_CCA_VLSC) {
|
||||
/* CCA AES cipher key */
|
||||
if (keylen < hdr->len)
|
||||
return -EINVAL;
|
||||
if (cca_check_secaescipherkey(pkey_dbf_info,
|
||||
3, key, 0, 1))
|
||||
3, key, keylen, 0, 1))
|
||||
return -EINVAL;
|
||||
} else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) {
|
||||
/* CCA ECC (private) key */
|
||||
if (keylen < sizeof(struct eccprivkeytoken))
|
||||
return -EINVAL;
|
||||
if (cca_check_sececckeytoken(pkey_dbf_info, 3, key, keylen, 1))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
@@ -484,7 +478,7 @@ static int cca_verifykey(const u8 *key, u32 keylen,
|
||||
hdr->version == TOKVER_CCA_AES) {
|
||||
struct secaeskeytoken *t = (struct secaeskeytoken *)key;
|
||||
|
||||
rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, 0);
|
||||
rc = cca_check_secaeskeytoken(pkey_dbf_info, 3, key, keylen, 0);
|
||||
if (rc)
|
||||
goto out;
|
||||
*keytype = PKEY_TYPE_CCA_DATA;
|
||||
@@ -512,7 +506,8 @@ static int cca_verifykey(const u8 *key, u32 keylen,
|
||||
hdr->version == TOKVER_CCA_VLSC) {
|
||||
struct cipherkeytoken *t = (struct cipherkeytoken *)key;
|
||||
|
||||
rc = cca_check_secaescipherkey(pkey_dbf_info, 3, key, 0, 1);
|
||||
rc = cca_check_secaescipherkey(pkey_dbf_info, 3,
|
||||
key, keylen, 0, 1);
|
||||
if (rc)
|
||||
goto out;
|
||||
*keytype = PKEY_TYPE_CCA_CIPHER;
|
||||
|
||||
@@ -879,6 +879,7 @@ static long _zcrypt_send_cprb(u32 xflags, struct ap_perms *perms,
|
||||
|
||||
if (perms != &ap_perms && domain < AP_DOMAINS) {
|
||||
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
|
||||
domain = array_index_nospec(domain, AP_DOMAINS);
|
||||
if (!test_bit_inv(domain, perms->adm)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
@@ -1077,8 +1078,9 @@ static long _zcrypt_send_ep11_cprb(u32 xflags, struct ap_perms *perms,
|
||||
print_hex_dump_debug("ep11req: ", DUMP_PREFIX_ADDRESS, 16, 1,
|
||||
ap_msg.msg, ap_msg.len, false);
|
||||
|
||||
if (perms != &ap_perms && domain < AUTOSEL_DOM) {
|
||||
if (perms != &ap_perms && domain < AP_DOMAINS) {
|
||||
if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
|
||||
domain = array_index_nospec(domain, AP_DOMAINS);
|
||||
if (!test_bit_inv(domain, perms->adm)) {
|
||||
rc = -ENODEV;
|
||||
goto out;
|
||||
|
||||
@@ -62,12 +62,18 @@ static DEFINE_MUTEX(dev_status_mem_mutex);
|
||||
* also checked. Returns 0 on success or errno value on failure.
|
||||
*/
|
||||
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
|
||||
const u8 *token, int keybitsize)
|
||||
const u8 *token, u32 keysize, int keybitsize)
|
||||
{
|
||||
struct secaeskeytoken *t = (struct secaeskeytoken *)token;
|
||||
|
||||
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
|
||||
|
||||
if (keysize < sizeof(*t)) {
|
||||
if (dbg)
|
||||
DBF("%s keysize %u < min token size %zu\n",
|
||||
__func__, keysize, sizeof(*t));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->type != TOKTYPE_CCA_INTERNAL) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
|
||||
@@ -101,14 +107,20 @@ EXPORT_SYMBOL(cca_check_secaeskeytoken);
|
||||
* Returns 0 on success or errno value on failure.
|
||||
*/
|
||||
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
|
||||
const u8 *token, int keybitsize,
|
||||
int checkcpacfexport)
|
||||
const u8 *token, u32 keysize,
|
||||
int keybitsize, int checkcpacfexport)
|
||||
{
|
||||
struct cipherkeytoken *t = (struct cipherkeytoken *)token;
|
||||
bool keybitsizeok = true;
|
||||
|
||||
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
|
||||
|
||||
if (keysize < sizeof(*t)) {
|
||||
if (dbg)
|
||||
DBF("%s keysize %u < min token size %zu\n",
|
||||
__func__, keysize, sizeof(*t));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->type != TOKTYPE_CCA_INTERNAL) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
|
||||
@@ -121,6 +133,18 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
|
||||
__func__, (int)t->version, TOKVER_CCA_VLSC);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->len > keysize) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, len %d > keysize %u\n",
|
||||
__func__, (int)t->len, keysize);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->len < sizeof(*t)) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, len %d < min token size %zu\n",
|
||||
__func__, (int)t->len, sizeof(*t));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->algtype != 0x02) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, algtype 0x%02x != 0x02\n",
|
||||
@@ -195,6 +219,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
|
||||
|
||||
#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__)
|
||||
|
||||
if (keysize < sizeof(*t)) {
|
||||
if (dbg)
|
||||
DBF("%s keysize %u < min token size %zu\n",
|
||||
__func__, keysize, sizeof(*t));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->type != TOKTYPE_CCA_INTERNAL_PKA) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, type 0x%02x != 0x%02x\n",
|
||||
@@ -207,6 +237,12 @@ int cca_check_sececckeytoken(debug_info_t *dbg, int dbflvl,
|
||||
__func__, (int)t->len, keysize);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->len < sizeof(*t)) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, len %d < min token size %zu\n",
|
||||
__func__, (int)t->len, sizeof(*t));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->secid != 0x20) {
|
||||
if (dbg)
|
||||
DBF("%s token check failed, secid 0x%02x != 0x20\n",
|
||||
@@ -443,7 +479,8 @@ int cca_genseckey(u16 cardnr, u16 domain,
|
||||
|
||||
/* check secure key token */
|
||||
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
|
||||
prepparm->lv3.keyblock.tok, 8 * keysize);
|
||||
prepparm->lv3.keyblock.tok,
|
||||
seckeysize, 8 * keysize);
|
||||
if (rc) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
@@ -582,7 +619,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
|
||||
|
||||
/* check secure key token */
|
||||
rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR,
|
||||
prepparm->lv3.keyblock.tok, 8 * keysize);
|
||||
prepparm->lv3.keyblock.tok,
|
||||
seckeysize, 8 * keysize);
|
||||
if (rc) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
@@ -842,6 +880,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
} kb;
|
||||
} __packed * prepparm;
|
||||
struct cipherkeytoken *t;
|
||||
u32 keybuflen;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
@@ -936,23 +975,28 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
|
||||
}
|
||||
|
||||
/* and some checks on the generated key */
|
||||
t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
|
||||
if (prepparm->kb.tlv1.len < 2 * sizeof(uint16_t) + sizeof(*t)) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
keybuflen = prepparm->kb.tlv1.len - 2 * sizeof(uint16_t);
|
||||
rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR,
|
||||
prepparm->kb.tlv1.gen_key,
|
||||
keybitsize, 1);
|
||||
keybuflen, keybitsize, 1);
|
||||
if (rc) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* copy the generated vlsc key token */
|
||||
t = (struct cipherkeytoken *)prepparm->kb.tlv1.gen_key;
|
||||
if (keybuf) {
|
||||
if (*keybufsize >= t->len)
|
||||
memcpy(keybuf, t, t->len);
|
||||
if (*keybufsize >= keybuflen)
|
||||
memcpy(keybuf, t, keybuflen);
|
||||
else
|
||||
rc = -EINVAL;
|
||||
}
|
||||
*keybufsize = t->len;
|
||||
*keybufsize = keybuflen;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, false, xflags);
|
||||
@@ -971,7 +1015,8 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
||||
int clr_key_bit_size,
|
||||
u8 *key_token,
|
||||
int *key_token_size,
|
||||
u32 xflags)
|
||||
u32 xflags,
|
||||
bool scrub)
|
||||
{
|
||||
int rc, n;
|
||||
u8 *mem, *ptr;
|
||||
@@ -1111,7 +1156,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
|
||||
*key_token_size = t->len;
|
||||
|
||||
out:
|
||||
free_cprbmem(mem, PARMBSIZE, false, xflags);
|
||||
free_cprbmem(mem, PARMBSIZE, scrub, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1162,28 +1207,32 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
|
||||
* 4/4 COMPLETE the secure cipher key import
|
||||
*/
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART",
|
||||
exorbuf, keybitsize, token, &tokensize, xflags);
|
||||
exorbuf, keybitsize, token, &tokensize,
|
||||
xflags, true);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
|
||||
clrkey, keybitsize, token, &tokensize, xflags);
|
||||
clrkey, keybitsize, token, &tokensize,
|
||||
xflags, true);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL,
|
||||
exorbuf, keybitsize, token, &tokensize, xflags);
|
||||
exorbuf, keybitsize, token, &tokensize,
|
||||
xflags, true);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL,
|
||||
NULL, keybitsize, token, &tokensize, xflags);
|
||||
NULL, keybitsize, token, &tokensize,
|
||||
xflags, true);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
@@ -1200,6 +1249,8 @@ int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags,
|
||||
*keybufsize = tokensize;
|
||||
|
||||
out:
|
||||
memzero_explicit(exorbuf, sizeof(exorbuf));
|
||||
memzero_explicit(mem, CPRB_MEMPOOL_ITEM_SIZE);
|
||||
mempool_free(mem, cprb_mempool);
|
||||
return rc;
|
||||
}
|
||||
@@ -1261,6 +1312,9 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
|
||||
} __packed * prepparm;
|
||||
int keytoklen = ((struct cipherkeytoken *)ckey)->len;
|
||||
|
||||
if (keytoklen > PARMBSIZE - sizeof(struct aureqparm))
|
||||
return -EINVAL;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
@@ -1425,6 +1479,9 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
|
||||
} __packed * prepparm;
|
||||
int keylen = ((struct eccprivkeytoken *)key)->len;
|
||||
|
||||
if (keylen > PARMBSIZE - sizeof(struct aureqparm))
|
||||
return -EINVAL;
|
||||
|
||||
/* get already prepared memory for 2 cprbs with param block each */
|
||||
rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
|
||||
&preqcblk, &prepcblk, xflags);
|
||||
|
||||
@@ -136,7 +136,7 @@ struct eccprivkeytoken {
|
||||
* also checked. Returns 0 on success or errno value on failure.
|
||||
*/
|
||||
int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
|
||||
const u8 *token, int keybitsize);
|
||||
const u8 *token, u32 keysize, int keybitsize);
|
||||
|
||||
/*
|
||||
* Simple check if the token is a valid CCA secure AES cipher key
|
||||
@@ -146,8 +146,8 @@ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl,
|
||||
* Returns 0 on success or errno value on failure.
|
||||
*/
|
||||
int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl,
|
||||
const u8 *token, int keybitsize,
|
||||
int checkcpacfexport);
|
||||
const u8 *token, u32 keysize,
|
||||
int keybitsize, int checkcpacfexport);
|
||||
|
||||
/*
|
||||
* Simple check if the token is a valid CCA secure ECC private
|
||||
|
||||
Reference in New Issue
Block a user