]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/zcrypt: Introduce cprb mempool for cca misc functions
authorHarald Freudenberger <freude@linux.ibm.com>
Thu, 24 Apr 2025 13:36:00 +0000 (15:36 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 30 Apr 2025 09:34:00 +0000 (11:34 +0200)
Introduce a new module parameter "zcrypt_mempool_threshold"
for the zcrypt module. This parameter controls the minimal
amount of mempool items which are pre-allocated for urgent
requests/replies and will be used with the support for the
new xflag ZCRYPT_XFLAG_NOMEMALLOC. The default value of 5
shall provide enough memory items to support up to 5 requests
(and their associated reply) in parallel. The minimum value
is 1 and is checked in zcrypt module init().

If the mempool is depleted upon one cca misc functions is called
with the named xflag set, the function will fail with -ENOMEM
and the caller is responsible for taking further actions.

For CCA each mempool item is 16KB, as a CCA CPRB needs to
hold the request and the reply. The pool items only support
requests/replies with a limit of about 8KB.
So by default the CCA mempool consumes
  5 * 16KB = 80KB

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-7-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_api.h
drivers/s390/crypto/zcrypt_ccamisc.c
drivers/s390/crypto/zcrypt_ccamisc.h

index 3a75c3b6c004457daddb59f68421e5464ddc1ab6..57d819966dad3f7e32068e536eba98d8936b94e2 100644 (file)
@@ -50,6 +50,10 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \
                   "Copyright IBM Corp. 2001, 2012");
 MODULE_LICENSE("GPL");
 
+unsigned int zcrypt_mempool_threshold = 5;
+module_param_named(mempool_threshold, zcrypt_mempool_threshold, uint, 0440);
+MODULE_PARM_DESC(mempool_threshold, "CCA and EP11 request/reply mempool minimal items (min: 1)");
+
 /*
  * zcrypt tracepoint functions
  */
@@ -2144,13 +2148,23 @@ int __init zcrypt_api_init(void)
 {
        int rc;
 
+       /* make sure the mempool threshold is >= 1 */
+       if (zcrypt_mempool_threshold < 1) {
+               rc = -EINVAL;
+               goto out;
+       }
+
        rc = zcrypt_debug_init();
        if (rc)
                goto out;
 
        rc = zcdn_init();
        if (rc)
-               goto out;
+               goto out_zcdn_init_failed;
+
+       rc = zcrypt_ccamisc_init();
+       if (rc)
+               goto out_ccamisc_init_failed;
 
        /* Register the request sprayer. */
        rc = misc_register(&zcrypt_misc_device);
@@ -2163,7 +2177,10 @@ int __init zcrypt_api_init(void)
        return 0;
 
 out_misc_register_failed:
+       zcrypt_ccamisc_exit();
+out_ccamisc_init_failed:
        zcdn_exit();
+out_zcdn_init_failed:
        zcrypt_debug_exit();
 out:
        return rc;
index 44f158329545122362dca641bab9b17e403c4234..14ed3e4e8e565e3d7dbfb0ae55e5b0b50cc6f114 100644 (file)
@@ -139,6 +139,8 @@ extern atomic_t zcrypt_rescan_req;
 extern spinlock_t zcrypt_list_lock;
 extern struct list_head zcrypt_card_list;
 
+extern unsigned int zcrypt_mempool_threshold;
+
 #define for_each_zcrypt_card(_zc) \
        list_for_each_entry(_zc, &zcrypt_card_list, list)
 
index 521baaea06ffefcd42311264ff3e00f33beb0730..d51ab5a0c58fafdb21a5b1ebd54c793b40ce04d9 100644 (file)
@@ -11,6 +11,7 @@
 #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>
@@ -40,6 +41,16 @@ struct cca_info_list_entry {
 static LIST_HEAD(cca_info_list);
 static DEFINE_SPINLOCK(cca_info_list_lock);
 
+/*
+ * Cprb memory pool held for urgent cases where no memory
+ * can be allocated via kmalloc. This pool is only used
+ * when alloc_and_prep_cprbmem() is called with the xflag
+ * ZCRYPT_XFLAG_NOMEMALLOC. The cprb memory needs to hold
+ * space for request AND reply!
+ */
+#define CPRB_MEMPOOL_ITEM_SIZE (16 * 1024)
+static mempool_t *cprb_mempool;
+
 /*
  * Simple check if the token is a valid CCA secure AES data key
  * token. If keybitsize is given, the bitsize of the key is
@@ -219,19 +230,27 @@ EXPORT_SYMBOL(cca_check_sececckeytoken);
 static int alloc_and_prep_cprbmem(size_t paramblen,
                                  u8 **p_cprb_mem,
                                  struct CPRBX **p_req_cprb,
-                                 struct CPRBX **p_rep_cprb)
+                                 struct CPRBX **p_rep_cprb,
+                                 u32 xflags)
 {
-       u8 *cprbmem;
+       u8 *cprbmem = NULL;
        size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen;
+       size_t len = 2 * cprbplusparamblen;
        struct CPRBX *preqcblk, *prepcblk;
 
        /*
         * allocate consecutive memory for request CPRB, request param
         * block, reply CPRB and reply param block
         */
-       cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL);
+       if (xflags & ZCRYPT_XFLAG_NOMEMALLOC) {
+               if (len <= CPRB_MEMPOOL_ITEM_SIZE)
+                       cprbmem = mempool_alloc_preallocated(cprb_mempool);
+       } else {
+               cprbmem = kmalloc(len, GFP_KERNEL);
+       }
        if (!cprbmem)
                return -ENOMEM;
+       memset(cprbmem, 0, len);
 
        preqcblk = (struct CPRBX *)cprbmem;
        prepcblk = (struct CPRBX *)(cprbmem + cprbplusparamblen);
@@ -261,11 +280,15 @@ static int alloc_and_prep_cprbmem(size_t paramblen,
  * with zeros before freeing (useful if there was some
  * clear key material in there).
  */
-static void free_cprbmem(void *mem, size_t paramblen, int scrub)
+static void free_cprbmem(void *mem, size_t paramblen, bool scrub, u32 xflags)
 {
-       if (scrub)
+       if (mem && scrub)
                memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen));
-       kfree(mem);
+
+       if (xflags & ZCRYPT_XFLAG_NOMEMALLOC)
+               mempool_free(mem, cprb_mempool);
+       else
+               kfree(mem);
 }
 
 /*
@@ -330,9 +353,11 @@ int cca_genseckey(u16 cardnr, u16 domain,
                        } keyblock;
                } lv3;
        } __packed * prepparm;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -379,7 +404,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -424,7 +449,7 @@ int cca_genseckey(u16 cardnr, u16 domain,
        memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, false, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_genseckey);
@@ -471,9 +496,11 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
                        } keyblock;
                } lv3;
        } __packed * prepparm;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -517,7 +544,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -563,7 +590,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize,
                memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE);
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 1);
+       free_cprbmem(mem, PARMBSIZE, true, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_clr2seckey);
@@ -617,9 +644,11 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
                        } ckb;
                } lv3;
        } __packed * prepparm;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -644,7 +673,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -712,7 +741,7 @@ int cca_sec2protkey(u16 cardnr, u16 domain,
                *protkeylen = prepparm->lv3.ckb.len;
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, true, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_sec2protkey);
@@ -811,9 +840,11 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
                } kb;
        } __packed * prepparm;
        struct cipherkeytoken *t;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -872,7 +903,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -923,7 +954,7 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags,
        *keybufsize = t->len;
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, false, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_gencipherkey);
@@ -987,9 +1018,11 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
        } __packed * prepparm;
        struct cipherkeytoken *t;
        int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -1038,7 +1071,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -1077,7 +1110,7 @@ static int _ip_cprb_helper(u16 cardnr, u16 domain,
        *key_token_size = t->len;
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, false, xflags);
        return rc;
 }
 
@@ -1217,9 +1250,11 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
                } kb;
        } __packed * prepparm;
        int keytoklen = ((struct cipherkeytoken *)ckey)->len;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -1249,7 +1284,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -1323,7 +1358,7 @@ int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey,
                *protkeylen = prepparm->vud.ckb.keylen;
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, true, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_cipher2protkey);
@@ -1380,9 +1415,11 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
                /* followed by a key block */
        } __packed * prepparm;
        int keylen = ((struct eccprivkeytoken *)key)->len;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -1412,7 +1449,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -1470,7 +1507,7 @@ int cca_ecc2protkey(u16 cardnr, u16 domain, const u8 *key,
                *protkeytype = PKEY_KEYTYPE_ECC;
 
 out:
-       free_cprbmem(mem, PARMBSIZE, 0);
+       free_cprbmem(mem, PARMBSIZE, true, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_ecc2protkey);
@@ -1503,9 +1540,11 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
                u8  subfunc_code[2];
                u8  lvdata[];
        } __packed * prepparm;
+       const u32 xflags = 0;
 
        /* get already prepared memory for 2 cprbs with param block each */
-       rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk);
+       rc = alloc_and_prep_cprbmem(parmbsize, &mem,
+                                   &preqcblk, &prepcblk, xflags);
        if (rc)
                return rc;
 
@@ -1526,7 +1565,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
        prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk);
 
        /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
-       rc = zcrypt_send_cprb(&xcrb, 0);
+       rc = zcrypt_send_cprb(&xcrb, xflags);
        if (rc) {
                ZCRYPT_DBF_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n",
                               __func__, (int)cardnr, (int)domain, rc);
@@ -1573,7 +1612,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
        }
 
 out:
-       free_cprbmem(mem, parmbsize, 0);
+       free_cprbmem(mem, parmbsize, false, xflags);
        return rc;
 }
 EXPORT_SYMBOL(cca_query_crypto_facility);
@@ -1959,7 +1998,19 @@ int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain,
 }
 EXPORT_SYMBOL(cca_findcard2);
 
-void __exit zcrypt_ccamisc_exit(void)
+int __init zcrypt_ccamisc_init(void)
+{
+       /* Pre-allocate a small memory pool for cca cprbs. */
+       cprb_mempool = mempool_create_kmalloc_pool(zcrypt_mempool_threshold,
+                                                  CPRB_MEMPOOL_ITEM_SIZE);
+       if (!cprb_mempool)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void zcrypt_ccamisc_exit(void)
 {
        mkvp_cache_free();
+       mempool_destroy(cprb_mempool);
 }
index 26bdca702523dceb1165b97237dd08dc42828dc1..273edf2bb03667b0451e1511de2f8fb3d1259741 100644 (file)
@@ -272,6 +272,7 @@ struct cca_info {
  */
 int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify);
 
+int zcrypt_ccamisc_init(void);
 void zcrypt_ccamisc_exit(void);
 
 #endif /* _ZCRYPT_CCAMISC_H_ */