lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 13 Sep 2019 17:26:54 -0400
From:   Tony Krowiak <akrowiak@...ux.ibm.com>
To:     linux-s390@...r.kernel.org, linux-kernel@...r.kernel.org,
        kvm@...r.kernel.org
Cc:     freude@...ux.ibm.com, borntraeger@...ibm.com, cohuck@...hat.com,
        mjrosato@...ux.ibm.com, pmorel@...ux.ibm.com, pasic@...ux.ibm.com,
        alex.williamson@...hat.com, kwankhede@...dia.com,
        jjherne@...ux.ibm.com, Tony Krowiak <akrowiak@...ux.ibm.com>
Subject: [PATCH v6 06/10] s390: vfio-ap: update guest CRYCB in vfio_ap probe and remove callbacks

When the vfio_ap device driver's probe callback is invoked to bind a
an AP queue device, if its APQN has been assigned to a matrix mdev that is
in use by a guest, the queue will be hot plugged into the guest's AP
configuration if:

1. Each APQN derived from the APID and the APQIs already set in the
   guest's CRYCB references an AP queue device bound to the vfio_ap
   device driver.

2. Each APQN derived from the APQI and the APIDs already set in the
   guest's CRYCB references an AP queue device bound to the vfio_ap
   device driver.

When an AP adapter is removed from the AP configuration via the SE or an
'SCLP Deconfigure AP Adapter' instruction, each queue device associated
with the adapter will be unbound from device driver to which it is bound.
When the vfio_ap device driver's remove callback is invoked to unbind an
AP queue device, if the queue's APQN is assigned to a matrix mdev in use
by a guest, the adapter to which the queue is connected will be hot
unplugged from the guest's configuration. The reason for this is because
an adapter of a different type can be added back to the AP configuration
with the APID corresponding to the adapter being removed. If the new
adapter is not of the appropriate type, it will not get bound to the
vfio_ap driver. If we did not unplug it from the guest, both the guest
and the host would have access to all of the queues associated with the
adapter which is a no-no.

Signed-off-by: Tony Krowiak <akrowiak@...ux.ibm.com>
---
 drivers/s390/crypto/vfio_ap_ops.c | 93 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c
index 14f221b7426b..f3332424670f 100644
--- a/drivers/s390/crypto/vfio_ap_ops.c
+++ b/drivers/s390/crypto/vfio_ap_ops.c
@@ -507,6 +507,63 @@ static void vfio_ap_mdev_get_crycb_matrix(struct ap_matrix_mdev *matrix_mdev)
 	}
 }
 
+static bool vfio_ap_mdev_update_crycb_matrix(struct ap_matrix_mdev *matrix_mdev,
+					     struct vfio_ap_queue *q)
+{
+	unsigned long crycb_apid, crycb_apqi;
+	unsigned long apid = AP_QID_CARD(q->apqn);
+	unsigned long apqi = AP_QID_QUEUE(q->apqn);
+
+	/*
+	 * If the APID of the input queue is not already set in the guest's
+	 * CRYCB, then verify that all APQNs derived from Cartesian product of
+	 * the APID and each APQI set in the guest's CRYCB references a queue
+	 * that is bound to the vfio_ap driver.
+	 */
+	if (!test_bit_inv(apid, matrix_mdev->crycb.apm)) {
+		for_each_set_bit_inv(crycb_apqi, matrix_mdev->crycb.aqm,
+				     matrix_mdev->crycb.aqm_max + 1) {
+			/*
+			 * The APQN formulated from the APID and APQI of the
+			 * input queue is in the process of being bound to the
+			 * vfio_ap driver so there is no need to verify it.
+			 */
+			if (apqi == crycb_apqi)
+				continue;
+
+			if (!vfio_ap_find_queue(AP_MKQID(apid, crycb_apqi)))
+				return false;
+		}
+	}
+
+	/*
+	 * If the APQI of the input queue is not already set in the guest's
+	 * CRYCB, then verify that all APQNs derived from Cartesian product of
+	 * the APQI and each APID set in the guest's CRYCB references a queue
+	 * that is bound to the vfio_ap driver.
+	 */
+	if (!test_bit_inv(apqi, matrix_mdev->crycb.aqm)) {
+		for_each_set_bit_inv(crycb_apid, matrix_mdev->crycb.apm,
+				     matrix_mdev->crycb.apm_max + 1) {
+			/*
+			 * The APQN formulated from the APID and APQI of the
+			 * input queue is in the process of being bound to the
+			 * vfio_ap driver so there is no need to verify it.
+			 */
+			if (apid == crycb_apid)
+				continue;
+
+			if (!vfio_ap_find_queue(AP_MKQID(crycb_apid, apqi)))
+				return false;
+		}
+	}
+
+	set_bit_inv(apid, matrix_mdev->crycb.apm);
+	set_bit_inv(apqi, matrix_mdev->crycb.aqm);
+
+	return true;
+}
+
 static bool vfio_ap_mdev_has_crycb(struct ap_matrix_mdev *matrix_mdev)
 {
 	return matrix_mdev->kvm && matrix_mdev->kvm->arch.crypto.crycbd;
@@ -1311,9 +1368,23 @@ void vfio_ap_mdev_unregister(void)
 	mdev_unregister_device(&matrix_dev->device);
 }
 
+static struct ap_matrix_mdev *vfio_ap_mdev_for_queue(int apqn)
+{
+	struct ap_matrix_mdev *matrix_mdev;
+
+	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
+		if (test_bit_inv(AP_QID_CARD(apqn), matrix_mdev->matrix.apm) &&
+		    test_bit_inv(AP_QID_QUEUE(apqn), matrix_mdev->matrix.aqm))
+			return matrix_mdev;
+	}
+
+	return NULL;
+}
+
 int vfio_ap_mdev_probe_queue(struct ap_queue *queue)
 {
 	struct vfio_ap_queue *q;
+	struct ap_matrix_mdev *matrix_mdev;
 
 	q = kzalloc(sizeof(*q), GFP_KERNEL);
 	if (!q)
@@ -1322,18 +1393,40 @@ int vfio_ap_mdev_probe_queue(struct ap_queue *queue)
 	q->apqn = queue->qid;
 	q->saved_isc = VFIO_AP_ISC_INVALID;
 
+	/*
+	 * If the APQN for the queue is assigned to a matrix mdev that is in
+	 * use by a guest, then plug the queue into the guest.
+	 */
+	matrix_mdev = vfio_ap_mdev_for_queue(queue->qid);
+	if (matrix_mdev && vfio_ap_mdev_has_crycb(matrix_mdev)) {
+		vfio_ap_mdev_update_crycb_matrix(matrix_mdev, q);
+		vfio_ap_mdev_update_crycb(matrix_mdev);
+	}
+
 	return 0;
 }
 
 void vfio_ap_mdev_remove_queue(struct ap_queue *queue)
 {
 	struct vfio_ap_queue *q;
+	struct ap_matrix_mdev *matrix_mdev;
 	int apid, apqi;
 
 	q = dev_get_drvdata(&queue->ap_dev.device);
 	dev_set_drvdata(&queue->ap_dev.device, NULL);
 	apid = AP_QID_CARD(q->apqn);
 	apqi = AP_QID_QUEUE(q->apqn);
+
+	/*
+	 * If the APQN for the queue is assigned to a matrix mdev that is in
+	 * use by a guest, then unplug the adapter from the guest.
+	 */
+	matrix_mdev = vfio_ap_mdev_for_queue(queue->qid);
+	if (matrix_mdev && vfio_ap_mdev_has_crycb(matrix_mdev)) {
+		clear_bit_inv(apid, matrix_mdev->crycb.apm);
+		vfio_ap_mdev_update_crycb(matrix_mdev);
+	}
+
 	vfio_ap_mdev_reset_queue(apid, apqi);
 	vfio_ap_irq_disable(q);
 	kfree(q);
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ