Commit c2863feb authored by Nicolin Chen's avatar Nicolin Chen Committed by Alex Williamson

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: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Acked-by: default avatarEric Farman <farman@linux.ibm.com>
Tested-by: default avatarEric Farman <farman@linux.ibm.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Link: https://lore.kernel.org/r/20220723020256.30081-10-nicolinc@nvidia.comSigned-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent 8561aa4f
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/vfio.h> #include <linux/vfio.h>
#include <asm/idals.h> #include <asm/idals.h>
...@@ -230,7 +231,6 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova, ...@@ -230,7 +231,6 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
unsigned long n) unsigned long n)
{ {
struct page_array pa = {0}; struct page_array pa = {0};
u64 from;
int i, ret; int i, ret;
unsigned long l, m; unsigned long l, m;
...@@ -246,7 +246,9 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova, ...@@ -246,7 +246,9 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
l = n; l = n;
for (i = 0; i < pa.pa_nr; i++) { for (i = 0; i < pa.pa_nr; i++) {
from = pa.pa_pfn[i] << PAGE_SHIFT; struct page *page = pfn_to_page(pa.pa_pfn[i]);
void *from = kmap_local_page(page);
m = PAGE_SIZE; m = PAGE_SIZE;
if (i == 0) { if (i == 0) {
from += iova & (PAGE_SIZE - 1); from += iova & (PAGE_SIZE - 1);
...@@ -254,7 +256,8 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova, ...@@ -254,7 +256,8 @@ static long copy_from_iova(struct vfio_device *vdev, void *to, u64 iova,
} }
m = min(l, m); m = min(l, m);
memcpy(to + (n - l), (void *)from, m); memcpy(to + (n - l), from, m);
kunmap_local(from);
l -= m; l -= m;
if (l == 0) if (l == 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment