]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/ap: Fix CCA crypto card behavior within protected execution environment
authorHarald Freudenberger <freude@linux.ibm.com>
Wed, 25 Sep 2024 13:31:06 +0000 (15:31 +0200)
committerHeiko Carstens <hca@linux.ibm.com>
Thu, 10 Oct 2024 13:31:55 +0000 (15:31 +0200)
A crypto card comes in 3 flavors: accelerator, CCA co-processor or
EP11 co-processor. Within a protected execution environment only the
accelerator and EP11 co-processor is supported. However, it is
possible to set up a KVM guest with a CCA card and run it as a
protected execution guest. There is nothing at the host side which
prevents this. Within such a guest, a CCA card is shown as "illicit"
and you can't do anything with such a crypto card.

Regardless of the unsupported CCA card within a protected execution
guest there are a couple of user space applications which
unconditional try to run crypto requests to the zcrypt device
driver. There was a bug within the AP bus code which allowed such a
request to be forwarded to a CCA card where it is finally
rejected and the driver reacts with -ENODEV but also triggers an AP
bus scan. Together with a retry loop this caused some kind of "hang"
of the KVM guest. On startup it caused timeouts and finally led the
KVM guest startup fail. Fix that by closing the gap and make sure a
CCA card is not usable within a protected execution environment.

Another behavior within an protected execution environment with CCA
cards was that the se_bind and se_associate AP queue sysfs attributes
where shown. The implementation unconditional always added these
attributes. Fix that by checking if the card mode is supported within
a protected execution environment and only if valid, add the attribute
group.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/ap_bus.h
drivers/s390/crypto/ap_queue.c

index 60cea6c243497b9f788c8da18eb77c055ac81cc6..e14638936de6b8773a43aec14b04df94f26e6357 100644 (file)
@@ -1864,13 +1864,12 @@ static inline void ap_scan_domains(struct ap_card *ac)
                }
                /* if no queue device exists, create a new one */
                if (!aq) {
-                       aq = ap_queue_create(qid, ac->ap_dev.device_type);
+                       aq = ap_queue_create(qid, ac);
                        if (!aq) {
                                AP_DBF_WARN("%s(%d,%d) ap_queue_create() failed\n",
                                            __func__, ac->id, dom);
                                continue;
                        }
-                       aq->card = ac;
                        aq->config = !decfg;
                        aq->chkstop = chkstop;
                        aq->se_bstate = hwinfo.bs;
index 0b275c719319645368f2bfba3fb59e78888e361e..f4622ee4d8947396dda5b73ce300c84dab27c6c5 100644 (file)
@@ -272,7 +272,7 @@ int ap_test_config_usage_domain(unsigned int domain);
 int ap_test_config_ctrl_domain(unsigned int domain);
 
 void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg);
-struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type);
+struct ap_queue *ap_queue_create(ap_qid_t qid, struct ap_card *ac);
 void ap_queue_prepare_remove(struct ap_queue *aq);
 void ap_queue_remove(struct ap_queue *aq);
 void ap_queue_init_state(struct ap_queue *aq);
index 8c878c5aa31fd72c73889eb35aa213a82a1930bb..9a0e6e4d8a5e2aef03bf2d06e588c2c787a8b7bf 100644 (file)
@@ -22,6 +22,11 @@ static void __ap_flush_queue(struct ap_queue *aq);
  * some AP queue helper functions
  */
 
+static inline bool ap_q_supported_in_se(struct ap_queue *aq)
+{
+       return aq->card->hwinfo.ep11 || aq->card->hwinfo.accel;
+}
+
 static inline bool ap_q_supports_bind(struct ap_queue *aq)
 {
        return aq->card->hwinfo.ep11 || aq->card->hwinfo.accel;
@@ -1104,18 +1109,19 @@ static void ap_queue_device_release(struct device *dev)
        kfree(aq);
 }
 
-struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type)
+struct ap_queue *ap_queue_create(ap_qid_t qid, struct ap_card *ac)
 {
        struct ap_queue *aq;
 
        aq = kzalloc(sizeof(*aq), GFP_KERNEL);
        if (!aq)
                return NULL;
+       aq->card = ac;
        aq->ap_dev.device.release = ap_queue_device_release;
        aq->ap_dev.device.type = &ap_queue_type;
-       aq->ap_dev.device_type = device_type;
-       // add optional SE secure binding attributes group
-       if (ap_sb_available() && is_prot_virt_guest())
+       aq->ap_dev.device_type = ac->ap_dev.device_type;
+       /* in SE environment add bind/associate attributes group */
+       if (ap_is_se_guest() && ap_q_supported_in_se(aq))
                aq->ap_dev.device.groups = ap_queue_dev_sb_attr_groups;
        aq->qid = qid;
        spin_lock_init(&aq->lock);
@@ -1196,10 +1202,16 @@ bool ap_queue_usable(struct ap_queue *aq)
        }
 
        /* SE guest's queues additionally need to be bound */
-       if (ap_q_needs_bind(aq) &&
-           !(aq->se_bstate == AP_BS_Q_USABLE ||
-             aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY))
-               rc = false;
+       if (ap_is_se_guest()) {
+               if (!ap_q_supported_in_se(aq)) {
+                       rc = false;
+                       goto unlock_and_out;
+               }
+               if (ap_q_needs_bind(aq) &&
+                   !(aq->se_bstate == AP_BS_Q_USABLE ||
+                     aq->se_bstate == AP_BS_Q_USABLE_NO_SECURE_KEY))
+                       rc = false;
+       }
 
 unlock_and_out:
        spin_unlock_bh(&aq->lock);