mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 23:22:31 +02:00
s390/zcrypt: Introduce cprb mempool for ep11 misc functions
Introduce a cprb mempool for the zcrypt ep11 misc functions (zcrypt_ep11misc.*) do some preparation rework to support a do-not-allocate path through some zcrypt ep11 misc functions. The mempool is controlled by the zcrypt module parameter "mempool_threshold" which shall control the minimal amount of memory items for CCA and EP11. The mempool shall support "mempool_threshold" requests/replies in parallel which means for EP11 to hold a send and receive buffer memory per request. Each of this cprb space items is limited to 8 KB. So by default the mempool consumes 5 * 2 * 8KB = 80KB If the mempool is depleted upon one ep11 misc functions is called with the ZCRYPT_XFLAG_NOMEMALLOC xflag set, the function will fail with -ENOMEM and the caller is responsible for taking further actions. This is only part of an rework to support a new xflag ZCRYPT_XFLAG_NOMEMALLOC but not yet complete. Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Reviewed-by: Holger Dengler <dengler@linux.ibm.com> Link: https://lore.kernel.org/r/20250424133619.16495-8-freude@linux.ibm.com Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
9bdb5f7e83
commit
366367a725
|
|
@ -2166,6 +2166,10 @@ int __init zcrypt_api_init(void)
|
|||
if (rc)
|
||||
goto out_ccamisc_init_failed;
|
||||
|
||||
rc = zcrypt_ep11misc_init();
|
||||
if (rc)
|
||||
goto out_ep11misc_init_failed;
|
||||
|
||||
/* Register the request sprayer. */
|
||||
rc = misc_register(&zcrypt_misc_device);
|
||||
if (rc < 0)
|
||||
|
|
@ -2177,6 +2181,8 @@ int __init zcrypt_api_init(void)
|
|||
return 0;
|
||||
|
||||
out_misc_register_failed:
|
||||
zcrypt_ep11misc_exit();
|
||||
out_ep11misc_init_failed:
|
||||
zcrypt_ccamisc_exit();
|
||||
out_ccamisc_init_failed:
|
||||
zcdn_exit();
|
||||
|
|
|
|||
|
|
@ -10,9 +10,10 @@
|
|||
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/zcrypt.h>
|
||||
#include <asm/pkey.h>
|
||||
#include <crypto/aes.h>
|
||||
|
|
@ -30,6 +31,14 @@
|
|||
static const u8 def_iv[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
|
||||
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
|
||||
|
||||
/*
|
||||
* Cprb memory pool held for urgent cases where no memory
|
||||
* can be allocated via kmalloc. This pool is only used when
|
||||
* alloc_cprbmem() is called with the xflag ZCRYPT_XFLAG_NOMEMALLOC.
|
||||
*/
|
||||
#define CPRB_MEMPOOL_ITEM_SIZE (8 * 1024)
|
||||
static mempool_t *cprb_mempool;
|
||||
|
||||
/* ep11 card info cache */
|
||||
struct card_list_entry {
|
||||
struct list_head list;
|
||||
|
|
@ -411,14 +420,20 @@ EXPORT_SYMBOL(ep11_check_aes_key);
|
|||
/*
|
||||
* Allocate and prepare ep11 cprb plus additional payload.
|
||||
*/
|
||||
static inline struct ep11_cprb *alloc_cprb(size_t payload_len)
|
||||
static void *alloc_cprbmem(size_t payload_len, u32 xflags)
|
||||
{
|
||||
size_t len = sizeof(struct ep11_cprb) + payload_len;
|
||||
struct ep11_cprb *cprb;
|
||||
struct ep11_cprb *cprb = NULL;
|
||||
|
||||
cprb = kzalloc(len, GFP_KERNEL);
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
|
||||
if (len <= CPRB_MEMPOOL_ITEM_SIZE)
|
||||
cprb = mempool_alloc_preallocated(cprb_mempool);
|
||||
} else {
|
||||
cprb = kmalloc(len, GFP_KERNEL);
|
||||
}
|
||||
if (!cprb)
|
||||
return NULL;
|
||||
memset(cprb, 0, len);
|
||||
|
||||
cprb->cprb_len = sizeof(struct ep11_cprb);
|
||||
cprb->cprb_ver_id = 0x04;
|
||||
|
|
@ -429,6 +444,20 @@ static inline struct ep11_cprb *alloc_cprb(size_t payload_len)
|
|||
return cprb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free ep11 cprb buffer space.
|
||||
*/
|
||||
static void free_cprbmem(void *mem, size_t payload_len, bool scrub, u32 xflags)
|
||||
{
|
||||
if (mem && scrub)
|
||||
memzero_explicit(mem, sizeof(struct ep11_cprb) + payload_len);
|
||||
|
||||
if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
|
||||
mempool_free(mem, cprb_mempool);
|
||||
else
|
||||
kfree(mem);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some helper functions related to ASN1 encoding.
|
||||
* Limited to length info <= 2 byte.
|
||||
|
|
@ -489,6 +518,7 @@ static inline void prep_urb(struct ep11_urb *u,
|
|||
struct ep11_cprb *req, size_t req_len,
|
||||
struct ep11_cprb *rep, size_t rep_len)
|
||||
{
|
||||
memset(u, 0, sizeof(*u));
|
||||
u->targets = (u8 __user *)t;
|
||||
u->targets_num = nt;
|
||||
u->req = (u8 __user *)req;
|
||||
|
|
@ -605,11 +635,12 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api = EP11_API_V1, rc = -ENOMEM;
|
||||
const u32 xflags = 0;
|
||||
|
||||
/* request cprb and payload */
|
||||
req = alloc_cprb(sizeof(struct ep11_info_req_pl));
|
||||
req = alloc_cprbmem(sizeof(struct ep11_info_req_pl), xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct ep11_info_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -621,22 +652,19 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
req_pl->query_subtype_len = sizeof(u32);
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct ep11_info_rep_pl) + buflen);
|
||||
rep = alloc_cprbmem(sizeof(struct ep11_info_rep_pl) + buflen, xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct ep11_info_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = cardnr;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + sizeof(*req_pl),
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl) + buflen);
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb, 0);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)cardnr, (int)domain, rc);
|
||||
|
|
@ -667,9 +695,8 @@ static int ep11_query_info(u16 cardnr, u16 domain, u32 query_type,
|
|||
memcpy(buf, ((u8 *)rep_pl) + sizeof(*rep_pl), rep_pl->data_len);
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, 0, false, xflags);
|
||||
free_cprbmem(rep, 0, false, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -823,9 +850,10 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
size_t req_pl_size, pinblob_size = 0;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
const u32 xflags = 0;
|
||||
|
||||
switch (keybitsize) {
|
||||
case 128:
|
||||
|
|
@ -851,7 +879,7 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
pinblob_size = EP11_PINBLOB_V1_BYTES;
|
||||
}
|
||||
req_pl_size = sizeof(struct keygen_req_pl) + ASN1TAGLEN(pinblob_size);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct keygen_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -877,22 +905,19 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
*p++ = pinblob_size;
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct keygen_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct keygen_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct keygen_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb, 0);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -925,9 +950,8 @@ static int _ep11_genaeskey(u16 card, u16 domain,
|
|||
*keybufsize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, 0, false, xflags);
|
||||
free_cprbmem(rep, sizeof(struct keygen_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1000,10 +1024,11 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
size_t req_pl_size, rep_pl_size;
|
||||
struct ep11_urb urb;
|
||||
size_t req_pl_size, rep_pl_size = 0;
|
||||
int n, api = EP11_API_V1, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
const u32 xflags = 0;
|
||||
|
||||
/* the simple asn1 coding used has length limits */
|
||||
if (keysize > 0xFFFF || inbufsize > 0xFFFF)
|
||||
|
|
@ -1012,7 +1037,7 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
/* request cprb and payload */
|
||||
req_pl_size = sizeof(struct crypt_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keysize) + ASN1TAGLEN(inbufsize);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct crypt_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -1034,22 +1059,19 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
|
||||
/* reply cprb and payload, assume out data size <= in data size + 32 */
|
||||
rep_pl_size = sizeof(struct crypt_rep_pl) + ASN1TAGLEN(inbufsize + 32);
|
||||
rep = alloc_cprb(rep_pl_size);
|
||||
rep = alloc_cprbmem(rep_pl_size, xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct crypt_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + rep_pl_size);
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb, 0);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1095,9 +1117,8 @@ static int ep11_cryptsingle(u16 card, u16 domain,
|
|||
*outbufsize = n;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, rep_pl_size, true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1143,9 +1164,10 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
size_t req_pl_size, pinblob_size = 0;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
const u32 xflags = 0;
|
||||
|
||||
/* request cprb and payload */
|
||||
api = (!keygenflags || keygenflags & 0x00200000) ?
|
||||
|
|
@ -1161,7 +1183,7 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
req_pl_size = sizeof(struct uw_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keksize) + ASN1TAGLEN(0)
|
||||
+ ASN1TAGLEN(pinblob_size) + ASN1TAGLEN(enckeysize);
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
req_pl = (struct uw_req_pl *)(((u8 *)req) + sizeof(*req));
|
||||
|
|
@ -1197,22 +1219,19 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
p += asn1tag_write(p, 0x04, enckey, enckeysize);
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct uw_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct uw_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct uw_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb, 0);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1245,9 +1264,8 @@ static int _ep11_unwrapkey(u16 card, u16 domain,
|
|||
*keybufsize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, sizeof(struct uw_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1319,15 +1337,16 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
} __packed * rep_pl;
|
||||
struct ep11_cprb *req = NULL, *rep = NULL;
|
||||
struct ep11_target_dev target;
|
||||
struct ep11_urb *urb = NULL;
|
||||
struct ep11_urb urb;
|
||||
size_t req_pl_size;
|
||||
int api, rc = -ENOMEM;
|
||||
u8 *p;
|
||||
const u32 xflags = 0;
|
||||
|
||||
/* request cprb and payload */
|
||||
req_pl_size = sizeof(struct wk_req_pl) + (iv ? 16 : 0)
|
||||
+ ASN1TAGLEN(keysize) + 4;
|
||||
req = alloc_cprb(req_pl_size);
|
||||
req = alloc_cprbmem(req_pl_size, xflags);
|
||||
if (!req)
|
||||
goto out;
|
||||
if (!mech || mech == 0x80060001)
|
||||
|
|
@ -1357,22 +1376,19 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
*p++ = 0;
|
||||
|
||||
/* reply cprb and payload */
|
||||
rep = alloc_cprb(sizeof(struct wk_rep_pl));
|
||||
rep = alloc_cprbmem(sizeof(struct wk_rep_pl), xflags);
|
||||
if (!rep)
|
||||
goto out;
|
||||
rep_pl = (struct wk_rep_pl *)(((u8 *)rep) + sizeof(*rep));
|
||||
|
||||
/* urb and target */
|
||||
urb = kmalloc(sizeof(*urb), GFP_KERNEL);
|
||||
if (!urb)
|
||||
goto out;
|
||||
target.ap_id = card;
|
||||
target.dom_id = domain;
|
||||
prep_urb(urb, &target, 1,
|
||||
prep_urb(&urb, &target, 1,
|
||||
req, sizeof(*req) + req_pl_size,
|
||||
rep, sizeof(*rep) + sizeof(*rep_pl));
|
||||
|
||||
rc = zcrypt_send_ep11_cprb(urb, 0);
|
||||
rc = zcrypt_send_ep11_cprb(&urb, xflags);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s zcrypt_send_ep11_cprb(card=%d dom=%d) failed, rc=%d\n",
|
||||
__func__, (int)card, (int)domain, rc);
|
||||
|
|
@ -1405,9 +1421,8 @@ static int _ep11_wrapkey(u16 card, u16 domain,
|
|||
*datasize = rep_pl->data_len;
|
||||
|
||||
out:
|
||||
kfree(req);
|
||||
kfree(rep);
|
||||
kfree(urb);
|
||||
free_cprbmem(req, req_pl_size, true, xflags);
|
||||
free_cprbmem(rep, sizeof(struct wk_rep_pl), true, xflags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
@ -1459,7 +1474,7 @@ int ep11_clr2keyblob(u16 card, u16 domain, u32 keybitsize, u32 keygenflags,
|
|||
encbuf, encbuflen, 0, def_iv,
|
||||
keybitsize, 0, keybuf, keybufsize, keytype);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF_ERR("%s importing key value as new key failed,, rc=%d\n",
|
||||
ZCRYPT_DBF_ERR("%s importing key value as new key failed, rc=%d\n",
|
||||
__func__, rc);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1658,7 +1673,19 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
}
|
||||
EXPORT_SYMBOL(ep11_findcard2);
|
||||
|
||||
void __exit zcrypt_ep11misc_exit(void)
|
||||
int __init zcrypt_ep11misc_init(void)
|
||||
{
|
||||
/* Pre-allocate a small memory pool for ep11 cprbs. */
|
||||
cprb_mempool = mempool_create_kmalloc_pool(2 * zcrypt_mempool_threshold,
|
||||
CPRB_MEMPOOL_ITEM_SIZE);
|
||||
if (!cprb_mempool)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zcrypt_ep11misc_exit(void)
|
||||
{
|
||||
card_cache_free();
|
||||
mempool_destroy(cprb_mempool);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ int ep11_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
|
|||
int ep11_kblob2protkey(u16 card, u16 dom, const u8 *key, u32 keylen,
|
||||
u8 *protkey, u32 *protkeylen, u32 *protkeytype);
|
||||
|
||||
int zcrypt_ep11misc_init(void);
|
||||
void zcrypt_ep11misc_exit(void);
|
||||
|
||||
#endif /* _ZCRYPT_EP11MISC_H_ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user