xen: arm: check permissions when copying to/from guest virtual addresses
authorIan Campbell <ian.campbell@citrix.com>
Wed, 4 Jun 2014 13:58:36 +0000 (14:58 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 4 Jun 2014 13:58:36 +0000 (14:58 +0100)
In particular we need to make sure the guest has write permissions to buffers
which it passes as output buffers for hypercalls, otherwise the guest can
overwrite memory which it shouldn't be able to write (like r/o grant table
mappings).

This is XSA-98.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Reviewed-by: Julien Grall <julien.grall@linaro.org>
xen/arch/arm/domain_build.c
xen/arch/arm/guestcopy.c
xen/arch/arm/kernel.c
xen/arch/arm/traps.c
xen/include/asm-arm/arm32/page.h
xen/include/asm-arm/arm64/page.h
xen/include/asm-arm/mm.h
xen/include/asm-arm/page.h

index ddbb88d26bc29513b9ec66b5c82ef23cdb6ffbe4..0e630d529acf7eccdafe947665b208fa55df9e32 100644 (file)
@@ -1007,7 +1007,7 @@ static void initrd_load(struct kernel_info *kinfo)
         s = offs & ~PAGE_MASK;
         l = min(PAGE_SIZE - s, len);
 
-        rc = gvirt_to_maddr(load_addr + offs, &ma);
+        rc = gvirt_to_maddr(load_addr + offs, &ma, GV2M_WRITE);
         if ( rc )
         {
             panic("Unable to translate guest address");
index cea5f97deab09f8202d81a498ab800fbed2c022a..d1fddec3d248a360040905f8a790a6a18fc6679f 100644 (file)
@@ -17,7 +17,7 @@ static unsigned long raw_copy_to_guest_helper(void *to, const void *from,
         void *p;
         unsigned size = min(len, (unsigned)PAGE_SIZE - offset);
 
-        if ( gvirt_to_maddr((vaddr_t) to, &g) )
+        if ( gvirt_to_maddr((vaddr_t) to, &g, GV2M_WRITE) )
             return len;
 
         p = map_domain_page(g>>PAGE_SHIFT);
@@ -62,7 +62,7 @@ unsigned long raw_clear_guest(void *to, unsigned len)
         void *p;
         unsigned size = min(len, (unsigned)PAGE_SIZE - offset);
 
-        if ( gvirt_to_maddr((vaddr_t) to, &g) )
+        if ( gvirt_to_maddr((vaddr_t) to, &g, GV2M_WRITE) )
             return len;
 
         p = map_domain_page(g>>PAGE_SHIFT);
@@ -92,7 +92,7 @@ unsigned long raw_copy_from_guest(void *to, const void __user *from, unsigned le
         void *p;
         unsigned size = min(len, (unsigned)(PAGE_SIZE - offset));
 
-        if ( gvirt_to_maddr((vaddr_t) from & PAGE_MASK, &g) )
+        if ( gvirt_to_maddr((vaddr_t) from & PAGE_MASK, &g, GV2M_READ) )
             return len;
 
         p = map_domain_page(g>>PAGE_SHIFT);
index c82906fd3aa81ffde9fdbec1bcc0388e1d73127a..69182ece71ac03669341657843e3c9d007e795f3 100644 (file)
@@ -172,7 +172,7 @@ static void kernel_zimage_load(struct kernel_info *info)
         s = offs & ~PAGE_MASK;
         l = min(PAGE_SIZE - s, len);
 
-        rc = gvirt_to_maddr(load_addr + offs, &ma);
+        rc = gvirt_to_maddr(load_addr + offs, &ma, GV2M_WRITE);
         if ( rc )
         {
             panic("Unable to map translate guest address");
index 03a3da6f86fa5d20882f68a381824d9ae5a2b65c..df86ffea3c9a10dbe9588a8bbe86cdf6f8216f2a 100644 (file)
@@ -837,7 +837,7 @@ static void show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs)
 
     printk("Guest stack trace from sp=%"PRIvaddr":\n  ", sp);
 
-    if ( gvirt_to_maddr(sp, &stack_phys) )
+    if ( gvirt_to_maddr(sp, &stack_phys, GV2M_READ) )
     {
         printk("Failed to convert stack to physical address\n");
         return;
index 4abb281aae2f68789ee11abd196526ed9a837147..974067299921e36d5d96e580fe2c08f832da891e 100644 (file)
@@ -87,11 +87,14 @@ static inline uint64_t __va_to_par(vaddr_t va)
 }
 
 /* Ask the MMU to translate a Guest VA for us */
-static inline uint64_t gva_to_ma_par(vaddr_t va)
+static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags)
 {
     uint64_t par, tmp;
     tmp = READ_CP64(PAR);
-    WRITE_CP32(va, ATS12NSOPR);
+    if ( (flags & GV2M_WRITE) == GV2M_WRITE )
+        WRITE_CP32(va, ATS12NSOPW);
+    else
+        WRITE_CP32(va, ATS12NSOPR);
     isb(); /* Ensure result is available. */
     par = READ_CP64(PAR);
     WRITE_CP64(tmp, PAR);
index 713baf6da1859a666a8f3c1afec6da4677c5947a..bb10164548fd9ebc98a82fcc259692ea60c6851a 100644 (file)
@@ -81,11 +81,14 @@ static inline uint64_t __va_to_par(vaddr_t va)
 }
 
 /* Ask the MMU to translate a Guest VA for us */
-static inline uint64_t gva_to_ma_par(vaddr_t va)
+static inline uint64_t gva_to_ma_par(vaddr_t va, unsigned int flags)
 {
     uint64_t par, tmp = READ_SYSREG64(PAR_EL1);
 
-    asm volatile ("at s12e1r, %0;" : : "r" (va));
+    if ( (flags & GV2M_WRITE) == GV2M_WRITE )
+        asm volatile ("at s12e1r, %0;" : : "r" (va));
+    else
+        asm volatile ("at s12e1w, %0;" : : "r" (va));
     isb();
     par = READ_SYSREG64(PAR_EL1);
     WRITE_SYSREG64(tmp, PAR_EL1);
index 3bef93fe7741a9d792c934e2b340b20991afed7d..9f98455abc5d112584fc3fce6c77d312dfd3060a 100644 (file)
@@ -234,9 +234,9 @@ static inline void *maddr_to_virt(paddr_t ma)
 }
 #endif
 
-static inline int gvirt_to_maddr(vaddr_t va, paddr_t *pa)
+static inline int gvirt_to_maddr(vaddr_t va, paddr_t *pa, unsigned int flags)
 {
-    uint64_t par = gva_to_ma_par(va);
+    uint64_t par = gva_to_ma_par(va, flags);
     if ( par & PAR_F )
         return -EFAULT;
     *pa = (par & PADDR_MASK & PAGE_MASK) | ((unsigned long) va & ~PAGE_MASK);
index c38e9c9c1621c62273729516617e40bda057e6c3..e723e5a03d4cd82fd1b106ddbeb94411379cc23f 100644 (file)
 #define MATTR_DEV     0x1
 #define MATTR_MEM     0xf
 
+/* Flags for gvirt_to_maddr */
+#define GV2M_READ  (0u<<0)
+#define GV2M_WRITE (1u<<0)
+
 #ifndef __ASSEMBLY__
 
 #include <xen/types.h>