s390/zcrypt: Avoid alloc and copy of ep11 targets if kernelspace cprb
authorHarald Freudenberger <freude@linux.ibm.com>
Thu, 24 Apr 2025 13:35:58 +0000 (15:35 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Wed, 30 Apr 2025 09:34:00 +0000 (11:34 +0200)
If there is a target list of APQNs given when an CPRB is
to be send via zcrypt_send_ep11_cprb() there is always a
kmalloc() done and the targets are copied via z_copy_from_user.

As there are callers from kernel space (zcrypt_ep11misc.c)
which signal this via the userspace parameter improve this
code to directly use the given target list in case of
kernelspace thus removing the unnecessary memory alloc
and mem copy.

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

index 139bf2b135446e00a0958d81f5bbc68fe69e01dd..b299cdb73826f945c9a2daf1162cb39c08029657 100644 (file)
@@ -1035,7 +1035,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
 {
        struct zcrypt_card *zc, *pref_zc;
        struct zcrypt_queue *zq, *pref_zq;
-       struct ep11_target_dev *targets;
+       struct ep11_target_dev *targets = NULL;
        unsigned short target_num;
        unsigned int wgt = 0, pref_wgt = 0;
        unsigned int func_code = 0, domain;
@@ -1052,29 +1052,25 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
        target_num = (unsigned short)xcrb->targets_num;
 
        /* empty list indicates autoselect (all available targets) */
-       targets = NULL;
+       rc = -ENOMEM;
        if (target_num != 0) {
-               struct ep11_target_dev __user *uptr;
-
-               targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
-               if (!targets) {
-                       func_code = 0;
-                       rc = -ENOMEM;
-                       goto out;
-               }
-
-               uptr = (struct ep11_target_dev __force __user *)xcrb->targets;
-               if (z_copy_from_user(userspace, targets, uptr,
-                                    target_num * sizeof(*targets))) {
-                       func_code = 0;
-                       rc = -EFAULT;
-                       goto out_free;
+               if (userspace) {
+                       targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL);
+                       if (!targets)
+                               goto out;
+                       if (copy_from_user(targets, xcrb->targets,
+                                          target_num * sizeof(*targets))) {
+                               rc = -EFAULT;
+                               goto out;
+                       }
+               } else {
+                       targets = (struct ep11_target_dev __force __kernel *)xcrb->targets;
                }
        }
 
        rc = prep_ep11_ap_msg(userspace, xcrb, &ap_msg, &func_code, &domain);
        if (rc)
-               goto out_free;
+               goto out;
        print_hex_dump_debug("ep11req: ", DUMP_PREFIX_ADDRESS, 16, 1,
                             ap_msg.msg, ap_msg.len, false);
 
@@ -1082,11 +1078,11 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
                if (ap_msg.flags & AP_MSG_FLAG_ADMIN) {
                        if (!test_bit_inv(domain, perms->adm)) {
                                rc = -ENODEV;
-                               goto out_free;
+                               goto out;
                        }
                } else if ((ap_msg.flags & AP_MSG_FLAG_USAGE) == 0) {
                        rc = -EOPNOTSUPP;
-                       goto out_free;
+                       goto out;
                }
        }
 
@@ -1154,7 +1150,7 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
                        pr_debug("no match for address ff.ffff => ENODEV\n");
                }
                rc = -ENODEV;
-               goto out_free;
+               goto out;
        }
 
        qid = pref_zq->queue->qid;
@@ -1168,9 +1164,9 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
        zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt);
        spin_unlock(&zcrypt_list_lock);
 
-out_free:
-       kfree(targets);
 out:
+       if (userspace)
+               kfree(targets);
        ap_release_apmsg(&ap_msg);
        if (tr) {
                tr->last_rc = rc;