Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86/x86 There is a huge bug in the way a uvm_map_pr...



details:   https://anonhg.NetBSD.org/src/rev/a9f82172e2ec
branches:  trunk
changeset: 346580:a9f82172e2ec
user:      maxv <maxv%NetBSD.org@localhost>
date:      Wed Jul 20 12:33:59 2016 +0000

description:
There is a huge bug in the way a uvm_map_protect is processed on x86.

When mprotecting a page, the kernel updates the uvm protection associated
with the page, and then gives control to the x86 pmap which splits the
procedure in two: if we are restricting the permissions it updates the page
tree right away, and if we are increasing the permissions it just waits for
the page to fault.

In the first case, it forgets to take care of the X permission. Which means
that if we allocate an executable page, it is impossible to remove the X
permission on it, this being true regardless of whether the mprotect call
comes from the kernel or from userland. It is not possible to make sure the
page is non executable either, since the only holder of the permission
information is uvm, and no track is kept at the pmap level of the actual
permissions enforced. In short, the kernel believes the page is non
executable, while the cpu knows it is.

Fix this by properly taking care of the !VM_PROT_EXECUTE case. Since the
bit manipulation is a little tricky we use two vars: bit_rem (remove) and
bit_put.

diffstat:

 sys/arch/x86/x86/pmap.c |  17 +++++++++++++----
 1 files changed, 13 insertions(+), 4 deletions(-)

diffs (54 lines):

diff -r a1eaed5dbb76 -r a9f82172e2ec sys/arch/x86/x86/pmap.c
--- a/sys/arch/x86/x86/pmap.c   Wed Jul 20 12:04:18 2016 +0000
+++ b/sys/arch/x86/x86/pmap.c   Wed Jul 20 12:33:59 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pmap.c,v 1.212 2016/07/19 18:54:45 maxv Exp $  */
+/*     $NetBSD: pmap.c,v 1.213 2016/07/20 12:33:59 maxv Exp $  */
 
 /*-
  * Copyright (c) 2008, 2010, 2016 The NetBSD Foundation, Inc.
@@ -171,7 +171,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.212 2016/07/19 18:54:45 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmap.c,v 1.213 2016/07/20 12:33:59 maxv Exp $");
 
 #include "opt_user_ldt.h"
 #include "opt_lockdebug.h"
@@ -3896,6 +3896,7 @@
 void
 pmap_write_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
 {
+       pt_entry_t bit_rem, bit_put;
        pt_entry_t *ptes;
        pt_entry_t * const *pdes;
        struct pmap *pmap2;
@@ -3903,6 +3904,14 @@
 
        KASSERT(curlwp->l_md.md_gc_pmap != pmap);
 
+       bit_rem = 0;
+       if (!(prot & VM_PROT_WRITE))
+               bit_rem = PG_RW;
+
+       bit_put = 0;
+       if (!(prot & VM_PROT_EXECUTE))
+               bit_put = pmap_pg_nx;
+
        sva &= PG_FRAME;
        eva &= PG_FRAME;
 
@@ -3947,10 +3956,10 @@
 
                        do {
                                opte = *spte;
-                               if ((~opte & (PG_RW | PG_V)) != 0) {
+                               if (!pmap_valid_entry(opte)) {
                                        goto next;
                                }
-                               npte = opte & ~PG_RW;
+                               npte = (opte & ~bit_rem) | bit_put;
                        } while (pmap_pte_cas(spte, opte, npte) != opte);
 
                        if ((opte & PG_M) != 0) {



Home | Main Index | Thread Index | Old Index