Restrict uva2kva() to only work for user addresses
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 25 Jan 2016 19:34:53 +0000 (14:34 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 2 Feb 2016 22:43:52 +0000 (17:43 -0500)
Previously, we were allowing uva2kva() to work on KVAs.  That's a little
surprising, given the name.

The new version takes a length and protection field, so the caller can
check permissions at the same time.  Note the permissions check is only for
the address space limit - not an actual mmap() permission.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/arch/x86/vmm/intel/vmx.c
kern/include/umem.h
kern/src/umem.c

index 369fa58..7003d7b 100644 (file)
@@ -969,7 +969,7 @@ static int vmcs_set_pgaddr(struct proc *p, void *u_addr, unsigned long field)
        physaddr_t paddr;
 
        /* Enforce page alignment */
-       kva = uva2kva(p, ROUNDDOWN(u_addr, PGSIZE));
+       kva = uva2kva(p, ROUNDDOWN(u_addr, PGSIZE), PGSIZE, PROT_WRITE);
        if (!kva) {
                set_error(EINVAL, "Unmapped pgaddr %p for VMCS", u_addr);
                return -1;
index 6e634d1..2401002 100644 (file)
@@ -70,7 +70,7 @@ char *copy_in_path(struct proc *p, const char *path, size_t path_l);
 void free_path(struct proc *p, char *t_path);
 void *kmalloc_errno(int len);
 bool uva_is_kva(struct proc *p, void *uva, void *kva);
-uintptr_t uva2kva(struct proc *p, void *uva);
+uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot);
 
 /* Helper for is_user_r{w,}addr.
  *
index 94753ba..51e2307 100644 (file)
@@ -194,15 +194,21 @@ bool uva_is_kva(struct proc *p, void *uva, void *kva)
 }
 
 /* Given a proc and a user virtual address, gives us the KVA.  Useful for
- * debugging.  Returns 0 if the page is unmapped (page lookup fails).  If you
- * give it a kva, it'll give you that same KVA, but this doesn't play nice with
- * Jumbo pages. */
-uintptr_t uva2kva(struct proc *p, void *uva)
+ * debugging.  Returns 0 if the page is unmapped (page lookup fails).  This
+ * doesn't play nice with Jumbo pages. */
+uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot)
 {
        struct page *u_page;
        uintptr_t offset = PGOFF(uva);
        if (!p)
                return 0;
+       if (prot & PROT_WRITE) {
+               if (!is_user_rwaddr(uva, len))
+                       return 0;
+       } else {
+               if (!is_user_raddr(uva, len))
+                       return 0;
+       }
        u_page = page_lookup(p->env_pgdir, uva, 0);
        if (!u_page)
                return 0;