s390/pkey: Wipe copies of protected- and secure-keys
Although the clear-key of neither protected- nor secure-keys is accessible, this key material should only be visible to the calling process. So wipe all copies of protected- or secure-keys from stack, even in case of an error. Reviewed-by: Harald Freudenberger <freude@linux.ibm.com> Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Holger Dengler <dengler@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
This commit is contained in:
parent
d65d76a44f
commit
f2ebdadd85
@ -1359,10 +1359,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = cca_genseckey(kgs.cardnr, kgs.domain,
|
rc = cca_genseckey(kgs.cardnr, kgs.domain,
|
||||||
kgs.keytype, kgs.seckey.seckey);
|
kgs.keytype, kgs.seckey.seckey);
|
||||||
pr_debug("%s cca_genseckey()=%d\n", __func__, rc);
|
pr_debug("%s cca_genseckey()=%d\n", __func__, rc);
|
||||||
if (rc)
|
if (!rc && copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(ugs, &kgs, sizeof(kgs)))
|
memzero_explicit(&kgs, sizeof(kgs));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_CLR2SECK: {
|
case PKEY_CLR2SECK: {
|
||||||
@ -1390,10 +1389,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
ksp.seckey.seckey, ksp.protkey.protkey,
|
ksp.seckey.seckey, ksp.protkey.protkey,
|
||||||
&ksp.protkey.len, &ksp.protkey.type);
|
&ksp.protkey.len, &ksp.protkey.type);
|
||||||
pr_debug("%s cca_sec2protkey()=%d\n", __func__, rc);
|
pr_debug("%s cca_sec2protkey()=%d\n", __func__, rc);
|
||||||
if (rc)
|
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(usp, &ksp, sizeof(ksp)))
|
memzero_explicit(&ksp, sizeof(ksp));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_CLR2PROTK: {
|
case PKEY_CLR2PROTK: {
|
||||||
@ -1437,10 +1435,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = pkey_skey2pkey(ksp.seckey.seckey, ksp.protkey.protkey,
|
rc = pkey_skey2pkey(ksp.seckey.seckey, ksp.protkey.protkey,
|
||||||
&ksp.protkey.len, &ksp.protkey.type);
|
&ksp.protkey.len, &ksp.protkey.type);
|
||||||
pr_debug("%s pkey_skey2pkey()=%d\n", __func__, rc);
|
pr_debug("%s pkey_skey2pkey()=%d\n", __func__, rc);
|
||||||
if (rc)
|
if (!rc && copy_to_user(usp, &ksp, sizeof(ksp)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(usp, &ksp, sizeof(ksp)))
|
memzero_explicit(&ksp, sizeof(ksp));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_VERIFYKEY: {
|
case PKEY_VERIFYKEY: {
|
||||||
@ -1452,10 +1449,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
|
rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain,
|
||||||
&kvk.keysize, &kvk.attributes);
|
&kvk.keysize, &kvk.attributes);
|
||||||
pr_debug("%s pkey_verifykey()=%d\n", __func__, rc);
|
pr_debug("%s pkey_verifykey()=%d\n", __func__, rc);
|
||||||
if (rc)
|
if (!rc && copy_to_user(uvk, &kvk, sizeof(kvk)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(uvk, &kvk, sizeof(kvk)))
|
memzero_explicit(&kvk, sizeof(kvk));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_GENPROTK: {
|
case PKEY_GENPROTK: {
|
||||||
@ -1468,10 +1464,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = pkey_genprotkey(kgp.keytype, kgp.protkey.protkey,
|
rc = pkey_genprotkey(kgp.keytype, kgp.protkey.protkey,
|
||||||
&kgp.protkey.len, &kgp.protkey.type);
|
&kgp.protkey.len, &kgp.protkey.type);
|
||||||
pr_debug("%s pkey_genprotkey()=%d\n", __func__, rc);
|
pr_debug("%s pkey_genprotkey()=%d\n", __func__, rc);
|
||||||
if (rc)
|
if (!rc && copy_to_user(ugp, &kgp, sizeof(kgp)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(ugp, &kgp, sizeof(kgp)))
|
memzero_explicit(&kgp, sizeof(kgp));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_VERIFYPROTK: {
|
case PKEY_VERIFYPROTK: {
|
||||||
@ -1483,6 +1478,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = pkey_verifyprotkey(kvp.protkey.protkey,
|
rc = pkey_verifyprotkey(kvp.protkey.protkey,
|
||||||
kvp.protkey.len, kvp.protkey.type);
|
kvp.protkey.len, kvp.protkey.type);
|
||||||
pr_debug("%s pkey_verifyprotkey()=%d\n", __func__, rc);
|
pr_debug("%s pkey_verifyprotkey()=%d\n", __func__, rc);
|
||||||
|
memzero_explicit(&kvp, sizeof(kvp));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_KBLOB2PROTK: {
|
case PKEY_KBLOB2PROTK: {
|
||||||
@ -1500,10 +1496,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
&ktp.protkey.len, &ktp.protkey.type);
|
&ktp.protkey.len, &ktp.protkey.type);
|
||||||
pr_debug("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
|
pr_debug("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
|
||||||
kfree_sensitive(kkey);
|
kfree_sensitive(kkey);
|
||||||
if (rc)
|
if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
memzero_explicit(&ktp, sizeof(ktp));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_GENSECK2: {
|
case PKEY_GENSECK2: {
|
||||||
@ -1529,23 +1524,23 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
pr_debug("%s pkey_genseckey2()=%d\n", __func__, rc);
|
pr_debug("%s pkey_genseckey2()=%d\n", __func__, rc);
|
||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (kgs.key) {
|
if (kgs.key) {
|
||||||
if (kgs.keylen < klen) {
|
if (kgs.keylen < klen) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (copy_to_user(kgs.key, kkey, klen)) {
|
if (copy_to_user(kgs.key, kkey, klen)) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kgs.keylen = klen;
|
kgs.keylen = klen;
|
||||||
if (copy_to_user(ugs, &kgs, sizeof(kgs)))
|
if (copy_to_user(ugs, &kgs, sizeof(kgs)))
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_CLR2SECK2: {
|
case PKEY_CLR2SECK2: {
|
||||||
@ -1574,18 +1569,18 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
pr_debug("%s pkey_clr2seckey2()=%d\n", __func__, rc);
|
pr_debug("%s pkey_clr2seckey2()=%d\n", __func__, rc);
|
||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
memzero_explicit(&kcs, sizeof(kcs));
|
memzero_explicit(&kcs, sizeof(kcs));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (kcs.key) {
|
if (kcs.key) {
|
||||||
if (kcs.keylen < klen) {
|
if (kcs.keylen < klen) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
memzero_explicit(&kcs, sizeof(kcs));
|
memzero_explicit(&kcs, sizeof(kcs));
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (copy_to_user(kcs.key, kkey, klen)) {
|
if (copy_to_user(kcs.key, kkey, klen)) {
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
memzero_explicit(&kcs, sizeof(kcs));
|
memzero_explicit(&kcs, sizeof(kcs));
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
@ -1594,7 +1589,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
if (copy_to_user(ucs, &kcs, sizeof(kcs)))
|
if (copy_to_user(ucs, &kcs, sizeof(kcs)))
|
||||||
rc = -EFAULT;
|
rc = -EFAULT;
|
||||||
memzero_explicit(&kcs, sizeof(kcs));
|
memzero_explicit(&kcs, sizeof(kcs));
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_VERIFYKEY2: {
|
case PKEY_VERIFYKEY2: {
|
||||||
@ -1611,7 +1606,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
&kvk.cardnr, &kvk.domain,
|
&kvk.cardnr, &kvk.domain,
|
||||||
&kvk.type, &kvk.size, &kvk.flags);
|
&kvk.type, &kvk.size, &kvk.flags);
|
||||||
pr_debug("%s pkey_verifykey2()=%d\n", __func__, rc);
|
pr_debug("%s pkey_verifykey2()=%d\n", __func__, rc);
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
if (rc)
|
if (rc)
|
||||||
break;
|
break;
|
||||||
if (copy_to_user(uvk, &kvk, sizeof(kvk)))
|
if (copy_to_user(uvk, &kvk, sizeof(kvk)))
|
||||||
@ -1642,10 +1637,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
pr_debug("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
|
pr_debug("%s pkey_keyblob2pkey2()=%d\n", __func__, rc);
|
||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
kfree_sensitive(kkey);
|
kfree_sensitive(kkey);
|
||||||
if (rc)
|
if (!rc && copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||||
break;
|
rc = -EFAULT;
|
||||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
memzero_explicit(&ktp, sizeof(ktp));
|
||||||
return -EFAULT;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PKEY_APQNS4K: {
|
case PKEY_APQNS4K: {
|
||||||
@ -1673,7 +1667,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
rc = pkey_apqns4key(kkey, kak.keylen, kak.flags,
|
rc = pkey_apqns4key(kkey, kak.keylen, kak.flags,
|
||||||
apqns, &nr_apqns);
|
apqns, &nr_apqns);
|
||||||
pr_debug("%s pkey_apqns4key()=%d\n", __func__, rc);
|
pr_debug("%s pkey_apqns4key()=%d\n", __func__, rc);
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
if (rc && rc != -ENOSPC) {
|
if (rc && rc != -ENOSPC) {
|
||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
break;
|
break;
|
||||||
@ -1759,7 +1753,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
protkey = kmalloc(protkeylen, GFP_KERNEL);
|
protkey = kmalloc(protkeylen, GFP_KERNEL);
|
||||||
if (!protkey) {
|
if (!protkey) {
|
||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
kfree(kkey);
|
kfree_sensitive(kkey);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries,
|
rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries,
|
||||||
@ -1769,20 +1763,20 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||||||
kfree(apqns);
|
kfree(apqns);
|
||||||
kfree_sensitive(kkey);
|
kfree_sensitive(kkey);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
kfree(protkey);
|
kfree_sensitive(protkey);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ktp.pkey && ktp.pkeylen) {
|
if (ktp.pkey && ktp.pkeylen) {
|
||||||
if (protkeylen > ktp.pkeylen) {
|
if (protkeylen > ktp.pkeylen) {
|
||||||
kfree(protkey);
|
kfree_sensitive(protkey);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (copy_to_user(ktp.pkey, protkey, protkeylen)) {
|
if (copy_to_user(ktp.pkey, protkey, protkeylen)) {
|
||||||
kfree(protkey);
|
kfree_sensitive(protkey);
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
kfree(protkey);
|
kfree_sensitive(protkey);
|
||||||
ktp.pkeylen = protkeylen;
|
ktp.pkeylen = protkeylen;
|
||||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
Loading…
Reference in New Issue
Block a user