Module Name: src Committed By: yamt Date: Tue Jul 5 14:03:07 UTC 2011
Modified Files: src/sys/uvm: uvm_km.c uvm_map.c Log Message: - fix a use-after-free bug in uvm_km_free. (after uvm_km_pgremove frees pages, the following pmap_remove touches them.) - acquire the object lock for operations on pmap_kernel as it can actually be raced with P->V operations. eg. pagedaemon. To generate a diff of this commit: cvs rdiff -u -r1.109 -r1.110 src/sys/uvm/uvm_km.c cvs rdiff -u -r1.299 -r1.300 src/sys/uvm/uvm_map.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/uvm/uvm_km.c diff -u src/sys/uvm/uvm_km.c:1.109 src/sys/uvm/uvm_km.c:1.110 --- src/sys/uvm/uvm_km.c:1.109 Sun Jun 12 03:36:03 2011 +++ src/sys/uvm/uvm_km.c Tue Jul 5 14:03:06 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_km.c,v 1.109 2011/06/12 03:36:03 rmind Exp $ */ +/* $NetBSD: uvm_km.c,v 1.110 2011/07/05 14:03:06 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -122,7 +122,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_km.c,v 1.109 2011/06/12 03:36:03 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_km.c,v 1.110 2011/07/05 14:03:06 yamt Exp $"); #include "opt_uvmhist.h" @@ -384,10 +384,7 @@ } /* - * uvm_km_pgremove: remove pages from a kernel uvm_object. - * - * => when you unmap a part of anonymous kernel memory you want to toss - * the pages right away. (this gets called from uvm_unmap_...). + * uvm_km_pgremove: remove pages from a kernel uvm_object and KVA. */ void @@ -406,7 +403,7 @@ KASSERT(endva <= VM_MAX_KERNEL_ADDRESS); mutex_enter(uobj->vmobjlock); - + pmap_remove(pmap_kernel(), startva, endva); for (curoff = start; curoff < end; curoff = nextoff) { nextoff = curoff + PAGE_SIZE; pg = uvm_pagelookup(uobj, curoff); @@ -474,6 +471,7 @@ pg = PHYS_TO_VM_PAGE(pa); KASSERT(pg); KASSERT(pg->uobject == NULL && pg->uanon == NULL); + KASSERT((pg->flags & PG_BUSY) == 0); uvm_pagefree(pg); } } @@ -655,15 +653,8 @@ size = round_page(size); - if (flags & UVM_KMF_PAGEABLE) { - /* - * No need to lock for pmap, since the kernel is always - * self-consistent. The pages cannot be in use elsewhere. - */ uvm_km_pgremove(addr, addr + size); - pmap_remove(pmap_kernel(), addr, addr + size); - } else if (flags & UVM_KMF_WIRED) { /* * Note: uvm_km_pgremove_intrsafe() extracts mapping, thus @@ -722,6 +713,8 @@ return 0; } } + pg->flags &= ~PG_BUSY; /* new page */ + UVM_PAGE_OWN(pg, NULL); pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), VM_PROT_READ|VM_PROT_WRITE, PMAP_KMPAGE); pmap_update(pmap_kernel()); Index: src/sys/uvm/uvm_map.c diff -u src/sys/uvm/uvm_map.c:1.299 src/sys/uvm/uvm_map.c:1.300 --- src/sys/uvm/uvm_map.c:1.299 Mon Jun 13 23:19:40 2011 +++ src/sys/uvm/uvm_map.c Tue Jul 5 14:03:07 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_map.c,v 1.299 2011/06/13 23:19:40 rmind Exp $ */ +/* $NetBSD: uvm_map.c,v 1.300 2011/07/05 14:03:07 yamt Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.299 2011/06/13 23:19:40 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.300 2011/07/05 14:03:07 yamt Exp $"); #include "opt_ddb.h" #include "opt_uvmhist.h" @@ -2367,55 +2367,8 @@ } } else if (UVM_ET_ISOBJ(entry) && UVM_OBJ_IS_KERN_OBJECT(entry->object.uvm_obj)) { - KASSERT(vm_map_pmap(map) == pmap_kernel()); - - /* - * note: kernel object mappings are currently used in - * two ways: - * [1] "normal" mappings of pages in the kernel object - * [2] uvm_km_valloc'd allocations in which we - * pmap_enter in some non-kernel-object page - * (e.g. vmapbuf). - * - * for case [1], we need to remove the mapping from - * the pmap and then remove the page from the kernel - * object (because, once pages in a kernel object are - * unmapped they are no longer needed, unlike, say, - * a vnode where you might want the data to persist - * until flushed out of a queue). - * - * for case [2], we need to remove the mapping from - * the pmap. there shouldn't be any pages at the - * specified offset in the kernel object [but it - * doesn't hurt to call uvm_km_pgremove just to be - * safe?] - * - * uvm_km_pgremove currently does the following: - * for pages in the kernel object in range: - * - drops the swap slot - * - uvm_pagefree the page - */ - - /* - * remove mappings from pmap and drop the pages - * from the object. offsets are always relative - * to vm_map_min(kernel_map). - * - * don't need to lock object as the kernel is - * always self-consistent. - */ - - pmap_remove(pmap_kernel(), entry->start, - entry->start + len); - uvm_km_pgremove(entry->start, entry->end); - - /* - * null out kernel_object reference, we've just - * dropped it - */ - - entry->etype &= ~UVM_ET_OBJ; - entry->object.uvm_obj = NULL; + panic("%s: kernel object %p %p\n", + __func__, map, entry); } else if (UVM_ET_ISOBJ(entry) || entry->aref.ar_amap) { /* * remove mappings the standard way. lock object