Skip to content

Commit c2863fe

Browse files
nicolincawilliam
authored andcommitted
vfio/ccw: Add kmap_local_page() for memcpy
A PFN is not secure enough to promise that the memory is not IO. And direct access via memcpy() that only handles CPU memory will crash on S390 if the PFN is an IO PFN, as we have to use the memcpy_to/fromio() that uses the special S390 IO access instructions. On the other hand, a "struct page *" is always a CPU coherent thing that fits memcpy(). Also, casting a PFN to "void *" for memcpy() is not a proper practice, kmap_local_page() is the correct API to call here, though S390 doesn't use highmem, which means kmap_local_page() is a NOP. There's a following patch changing the vfio_pin_pages() API to return a list of "struct page *" instead of PFNs. It will block any IO memory from ever getting into this call path, for such a security purpose. In this patch, add kmap_local_page() to prepare for that. Suggested-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Acked-by: Eric Farman <farman@linux.ibm.com> Tested-by: Eric Farman <farman@linux.ibm.com> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> Link: https://lore.kernel.org/r/20220723020256.30081-10-nicolinc@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent 8561aa4 commit c2863fe

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

drivers/s390/cio/vfio_ccw_cp.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/ratelimit.h>
1212
#include <linux/mm.h>
1313
#include <linux/slab.h>
14+
#include <linux/highmem.h>
1415
#include <linux/iommu.h>
1516
#include <linux/vfio.h>
1617
#include <asm/idals.h>
@@ -230,7 +231,6 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
230231
unsigned long n)
231232
{
232233
struct page_array pa = {0};
233-
u64 from;
234234
int i, ret;
235235
unsigned long l, m;
236236

@@ -246,15 +246,18 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
246246

247247
l = n;
248248
for (i = 0; i < pa.pa_nr; i++) {
249-
from = pa.pa_pfn[i] << PAGE_SHIFT;
249+
struct page *page = pfn_to_page(pa.pa_pfn[i]);
250+
void *from = kmap_local_page(page);
251+
250252
m = PAGE_SIZE;
251253
if (i == 0) {
252254
from += iova & (PAGE_SIZE - 1);
253255
m -= iova & (PAGE_SIZE - 1);
254256
}
255257

256258
m = min(l, m);
257-
memcpy(to + (n - l), (void *)from, m);
259+
memcpy(to + (n - l), from, m);
260+
kunmap_local(from);
258261

259262
l -= m;
260263
if (l == 0)

0 commit comments

Comments
 (0)