]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/pkey: Use preallocated memory for retrieve of UV secret metadata
authorHarald Freudenberger <freude@linux.ibm.com>
Thu, 24 Apr 2025 13:36:16 +0000 (15:36 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 30 Apr 2025 09:34:03 +0000 (11:34 +0200)
The pkey uv functions may be called in a situation where memory
allocations which trigger IO operations are not allowed. An example:
decryption of the swap partition with protected key (PAES).

The pkey uv code takes care of this by holding one preallocated
struct uv_secret_list to be used with the new UV function
uv_find_secret(). The older function uv_get_secret_metadata()
used before always allocates/frees an ephemeral memory buffer.
The preallocated struct is concurrency protected by a mutex.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Link: https://lore.kernel.org/r/20250424133619.16495-23-freude@linux.ibm.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/crypto/pkey_uv.c

index 805817b1435401d8c05ea2968a22f7bcdabd59c4..afbdb59c90f5a140f4705cac89b4f1937a0e8363 100644 (file)
@@ -20,6 +20,12 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("IBM Corporation");
 MODULE_DESCRIPTION("s390 protected key UV handler");
 
+/*
+ * One pre-allocated uv_secret_list for use with uv_find_secret()
+ */
+static struct uv_secret_list *uv_list;
+static DEFINE_MUTEX(uv_list_mutex);
+
 /*
  * UV secret token struct and defines.
  */
@@ -85,13 +91,26 @@ static bool is_uv_keytype(enum pkey_key_type keytype)
        }
 }
 
+static int get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN],
+                              struct uv_secret_list_item_hdr *secret)
+{
+       int rc;
+
+       mutex_lock(&uv_list_mutex);
+       memset(uv_list, 0, sizeof(*uv_list));
+       rc = uv_find_secret(secret_id, uv_list, secret);
+       mutex_unlock(&uv_list_mutex);
+
+       return rc;
+}
+
 static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN],
                           u16 *secret_type, u8 *buf, u32 *buflen)
 {
        struct uv_secret_list_item_hdr secret_meta_data;
        int rc;
 
-       rc = uv_get_secret_metadata(secret_id, &secret_meta_data);
+       rc = get_secret_metadata(secret_id, &secret_meta_data);
        if (rc)
                return rc;
 
@@ -225,7 +244,7 @@ static int uv_verifykey(const u8 *key, u32 keylen,
        if (rc)
                goto out;
 
-       rc = uv_get_secret_metadata(t->secret_id, &secret_meta_data);
+       rc = get_secret_metadata(t->secret_id, &secret_meta_data);
        if (rc)
                goto out;
 
@@ -263,13 +282,23 @@ static struct pkey_handler uv_handler = {
  */
 static int __init pkey_uv_init(void)
 {
+       int rc;
+
        if (!is_prot_virt_guest())
                return -ENODEV;
 
        if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list))
                return -ENODEV;
 
-       return pkey_handler_register(&uv_handler);
+       uv_list = kmalloc(sizeof(*uv_list), GFP_KERNEL);
+       if (!uv_list)
+               return -ENOMEM;
+
+       rc = pkey_handler_register(&uv_handler);
+       if (rc)
+               kfree(uv_list);
+
+       return rc;
 }
 
 /*
@@ -278,6 +307,9 @@ static int __init pkey_uv_init(void)
 static void __exit pkey_uv_exit(void)
 {
        pkey_handler_unregister(&uv_handler);
+       mutex_lock(&uv_list_mutex);
+       kvfree(uv_list);
+       mutex_unlock(&uv_list_mutex);
 }
 
 module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init);