xen/arm: Correctly handle non-page aligned pointer in raw_copy_from_guest
authorJulien Grall <julien.grall@linaro.org>
Tue, 18 Feb 2014 16:56:17 +0000 (16:56 +0000)
committerIan Campbell <ian.campbell@citrix.com>
Tue, 18 Feb 2014 17:33:49 +0000 (17:33 +0000)
The current implementation of raw_copy_guest helper may lead to data corruption
and sometimes Xen crash when the guest virtual address is not aligned to
PAGE_SIZE.

When the total length is higher than a page, the length to read is badly
compute with
    min(len, (unsigned)(PAGE_SIZE - offset))

As the offset is only computed one time per function, if the start address was
not aligned to PAGE_SIZE, we can end up in same iteration:
    - to read accross page boundary => xen crash
    - read the previous page => data corruption

This issue can be resolved by setting offset to 0 at the end of the first
iteration. Indeed, after it, the virtual guest address is always aligned
to PAGE_SIZE.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Cc: George Dunlap <george.dunlap@citrix.com>
[ ijc -- duplicated the comment in the other two functions with this behaviour ]

xen/arch/arm/guestcopy.c

index af0af6b19b0d668aff1ad9dfe29d0432d24e87f7..cea5f97deab09f8202d81a498ab800fbed2c022a 100644 (file)
@@ -30,6 +30,10 @@ static unsigned long raw_copy_to_guest_helper(void *to, const void *from,
         len -= size;
         from += size;
         to += size;
+        /*
+         * After the first iteration, guest virtual address is correctly
+         * aligned to PAGE_SIZE.
+         */
         offset = 0;
     }
 
@@ -68,6 +72,10 @@ unsigned long raw_clear_guest(void *to, unsigned len)
         unmap_domain_page(p - offset);
         len -= size;
         to += size;
+        /*
+         * After the first iteration, guest virtual address is correctly
+         * aligned to PAGE_SIZE.
+         */
         offset = 0;
     }
 
@@ -96,6 +104,11 @@ unsigned long raw_copy_from_guest(void *to, const void __user *from, unsigned le
         len -= size;
         from += size;
         to += size;
+        /*
+         * After the first iteration, guest virtual address is correctly
+         * aligned to PAGE_SIZE.
+         */
+        offset = 0;
     }
     return 0;
 }