s390/vfio_ccw: Ensure first IDAW remains constant

commit 565bef268d upstream.

The first IDAW in a list does not need to be on a 2K/4K boundary
like all others, and so is read separately to accurately calculate
the size of the buffer needed to read the full IDAL.

Verify that the address found in the first IDAW is unchanged between
reads, to ensure a consistent set of IDAWs being worked with.

Fixes: 01aa26c672 ("s390/cio: Combine direct and indirect CCW paths")
Cc: stable@vger.kernel.org
Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com>
[farman@linux.ibm.com: resolved merge conflict]
Signed-off-by: Eric Farman <farman@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Eric Farman
2026-08-27 14:29:45 +02:00
committed by Greg Kroah-Hartman
parent 152fcb74a2
commit 460b977a4e
2 changed files with 18 additions and 0 deletions
+16
View File
@@ -521,6 +521,7 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
&container_of(cp, struct vfio_ccw_private, cp)->vdev;
unsigned long *idaws;
unsigned int *idaws_f1;
u64 first_idaw;
int idal_len = idaw_nr * sizeof(*idaws);
int idaw_size = idal_is_2k(cp) ? PAGE_SIZE / 2 : PAGE_SIZE;
int idaw_mask = ~(idaw_size - 1);
@@ -537,6 +538,18 @@ static unsigned long *get_guest_idal(struct ccw1 *ccw,
kfree(idaws);
return ERR_PTR(ret);
}
idaws_f1 = (unsigned int *)idaws;
if (cp->orb.cmd.c64)
first_idaw = idaws[0];
else
first_idaw = (unsigned long)(idaws_f1[0]);
/* Unexpected mismatch from earlier read */
if (first_idaw != cp->guest_iova) {
kfree(idaws);
return ERR_PTR(-EINVAL);
}
} else {
/* Fabricate an IDAL based off CCW data address */
if (cp->orb.cmd.c64) {
@@ -598,6 +611,9 @@ static int ccw_count_idaws(struct ccw1 *ccw,
iova = ccw->cda;
}
/* Save the read address for later */
cp->guest_iova = iova;
/* Format-1 IDAWs operate on 2K each */
if (!cp->orb.cmd.c64)
return idal_2k_nr_words((void *)iova, bytes);
+2
View File
@@ -35,6 +35,7 @@
* @initialized: whether this instance is actually initialized
* @guest_cp: copy of guest channel program
* @ccwchain_count: number of channel program segments (linked by TIC)
* @guest_iova: first data address of a guest channel program
*
* @ccwchain_list is the head of a ccwchain list, that contents the
* translated result of the guest channel program that pointed out by
@@ -46,6 +47,7 @@ struct channel_program {
bool initialized;
struct ccw1 *guest_cp;
unsigned int ccwchain_count;
u64 guest_iova;
};
int cp_init(struct channel_program *cp, union orb *orb);