Date: Tue, 1 Feb 2005 20:11:57 -0500 From: Bosko Milekic <bmilekic@technokratis.com> To: Kris Kennaway <kris@obsecurity.org> Cc: bmilekic@freebsd.org Subject: Re: Panic: Memory modified after free Message-ID: <20050202011157.GA55803@technokratis.com> In-Reply-To: <20050202001230.GA21847@xor.obsecurity.org> References: <20050130094616.GA76093@peter.osted.lan> <20050202000613.GA9758@xor.obsecurity.org> <20050202001230.GA21847@xor.obsecurity.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--NMuMz9nt05w80d4+ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline I made the attached patch for scottl to allow for > PAGE_SIZE allocations, please feel free to try it as I don't think he has had a chance to yet. -Bosko On Tue, Feb 01, 2005 at 04:12:30PM -0800, Kris Kennaway wrote: > On Tue, Feb 01, 2005 at 04:06:13PM -0800, Kris Kennaway wrote: > > On Sun, Jan 30, 2005 at 10:46:16AM +0100, Peter Holm wrote: > > > With GENERIC HEAD from Jan 28 20:19 UTC + mpsafe_vfs = 1 I got: > > > > > > Memory modified after free 0xc1d7c100(124) val=c23fa000 @ 0xc1d7c164 > > > > > > panic(c083d005,c083b16e,c083cfd6,c1d7c100,7c) at panic+0xef > > > mtrash_ctor(c1d7c100,80,0,402) at mtrash_ctor+0x4d > > > uma_zalloc_arg(c10526e0,0,402) at uma_zalloc_arg+0x14c > > > malloc(68,c08bcd60,402,c094f0c0,0) at malloc+0xae > > > inodedep_lookup(c167a000,193a1,1,cf261be0,c094f0c0) at inodedep_lookup+0xa7 > > > softdep_change_linkcnt(c213b578,c6bc54f0,c65f3f88,c213b578,c1c39270) at softdep_change_linkcnt+0x31 > > > ufs_dirremove(c17d83a8,c213b578,100800c,0,cf261c48) at ufs_dirremove+0x12d > > > ufs_remove(cf261c4c) at ufs_remove+0x4b > > > VOP_REMOVE_AP(cf261c4c) at VOP_REMOVE_AP+0x62 > > > kern_unlink(c1add2e0,bfbfe940,0,cf261d40,c07bd6c3) at kern_unlink+0x167 > > > unlink(c1add2e0,cf261d14,1,28,292) at unlink+0x12 > > > syscall(2804002f,bfbf002f,bfbf002f,2804f6c0,bfbfeb14) at syscall+0x213 > > > > > > More info at http://www.holm.cc/stress/log/cons112.html > > > > > panic: Most recently used by inodedep > > > > You can try to use DEBUG_MEMGUARD with M_INODEDEP to find this. I'll > > add that to my SMP package machines to see if I can trigger it too. > > Well, that didn't work: > > panic: MEMGUARD: Cannot handle objects > PAGE_SIZE > > CC'ing Bosko, the memguard author. > > Kris > > -- Bosko Milekic bmilekic@technokratis.com bmilekic@FreeBSD.org --NMuMz9nt05w80d4+ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="mg_scottl.diff" Index: src/sys/vm/memguard.c =================================================================== RCS file: /home/ncvs/src/sys/vm/memguard.c,v retrieving revision 1.1 diff -u -r1.1 memguard.c --- src/sys/vm/memguard.c 21 Jan 2005 18:09:17 -0000 1.1 +++ src/sys/vm/memguard.c 21 Jan 2005 21:21:38 -0000 @@ -52,6 +52,13 @@ #include <vm/memguard.h> /* + * The maximum number of pages allowed per allocation. If you're using + * MemGuard to override very large items (> MAX_PAGES_PER_ITEM in size), + * you need to increase MAX_PAGES_PER_ITEM. + */ +#define MAX_PAGES_PER_ITEM 10 + +/* * Global MemGuard data. */ static vm_map_t memguard_map; @@ -61,13 +68,20 @@ STAILQ_ENTRY(memguard_entry) entries; void *ptr; }; -static STAILQ_HEAD(memguard_fifo, memguard_entry) memguard_fifo_pool; +static struct memguard_fifo { + struct memguard_entry *stqh_first; + struct memguard_entry **stqh_last; + int index; +} memguard_fifo_pool[MAX_PAGES_PER_ITEM]; /* * Local prototypes. */ -static void memguard_guard(void *addr); -static void memguard_unguard(void *addr); +static void memguard_guard(void *addr, int numpgs); +static void memguard_unguard(void *addr, int numpgs); +static struct memguard_fifo *vtomgfifo(vm_offset_t va); +static void vsetmgfifo(vm_offset_t va, struct memguard_fifo *mgfifo); +static void vclrmgfifo(vm_offset_t va); /* * Local macros. MemGuard data is global, so replace these with whatever @@ -89,6 +103,7 @@ memguard_init(vm_map_t parent_map, unsigned long size) { char *base, *limit; + int i; /* size must be multiple of PAGE_SIZE */ size /= PAGE_SIZE; @@ -103,7 +118,10 @@ MEMGUARD_CRIT_SECTION_INIT; MEMGUARD_CRIT_SECTION_ENTER; - STAILQ_INIT(&memguard_fifo_pool); + for (i = 0; i < MAX_PAGES_PER_ITEM; i++) { + STAILQ_INIT(&memguard_fifo_pool[i]); + memguard_fifo_pool[i].index = i; + } MEMGUARD_CRIT_SECTION_EXIT; printf("MEMGUARD DEBUGGING ALLOCATOR INITIALIZED:\n"); @@ -121,10 +139,11 @@ { void *obj = NULL; struct memguard_entry *e = NULL; + int i; - /* XXX: MemGuard does not handle > PAGE_SIZE objects. */ - if (size > PAGE_SIZE) - panic("MEMGUARD: Cannot handle objects > PAGE_SIZE"); + i = size / PAGE_SIZE; + if (i >= MAX_PAGES_PER_ITEM) + panic("MEMGUARD: You must increase MAX_PAGES_PER_ITEM"); /* * If we haven't exhausted the memguard_map yet, allocate from @@ -137,16 +156,17 @@ */ MEMGUARD_CRIT_SECTION_ENTER; if (memguard_mapused >= memguard_mapsize) { - e = STAILQ_FIRST(&memguard_fifo_pool); + e = STAILQ_FIRST(&memguard_fifo_pool[i]); if (e != NULL) { - STAILQ_REMOVE(&memguard_fifo_pool, e, + STAILQ_REMOVE(&memguard_fifo_pool[i], e, memguard_entry, entries); MEMGUARD_CRIT_SECTION_EXIT; obj = e->ptr; free(e, M_TEMP); - memguard_unguard(obj); + memguard_unguard(obj, i+1); if (flags & M_ZERO) - bzero(obj, PAGE_SIZE); + bzero(obj, PAGE_SIZE * (i+1)); + vsetmgfifo((vm_offset_t)obj, &memguard_fifo_pool[i]); return obj; } MEMGUARD_CRIT_SECTION_EXIT; @@ -155,18 +175,19 @@ "memguard_map too small"); return NULL; } else - memguard_mapused += PAGE_SIZE; + memguard_mapused += (PAGE_SIZE * (i+1)); MEMGUARD_CRIT_SECTION_EXIT; if (obj == NULL) - obj = (void *)kmem_malloc(memguard_map, PAGE_SIZE, flags); + obj = (void *)kmem_malloc(memguard_map, PAGE_SIZE * (i+1), flags); if (obj != NULL) { - memguard_unguard(obj); + memguard_unguard(obj, i+1); + vsetmgfifo((vm_offset_t)obj, &memguard_fifo_pool[i]); if (flags & M_ZERO) - bzero(obj, PAGE_SIZE); + bzero(obj, PAGE_SIZE * (i+1)); } else { MEMGUARD_CRIT_SECTION_ENTER; - memguard_mapused -= PAGE_SIZE; + memguard_mapused -= (PAGE_SIZE * (i+1)); MEMGUARD_CRIT_SECTION_EXIT; } return obj; @@ -179,20 +200,25 @@ memguard_free(void *addr) { struct memguard_entry *e; + struct memguard_fifo *mgfifo; + int idx; - memguard_guard(addr); + mgfifo = vtomgfifo((vm_offset_t)addr); + idx = mgfifo->index; + memguard_guard(addr, idx + 1); + vclrmgfifo((vm_offset_t)addr); e = malloc(sizeof(struct memguard_entry), M_TEMP, M_NOWAIT); if (e == NULL) { MEMGUARD_CRIT_SECTION_ENTER; - memguard_mapused -= PAGE_SIZE; + memguard_mapused -= (PAGE_SIZE * (idx+1)); MEMGUARD_CRIT_SECTION_EXIT; kmem_free(memguard_map, (vm_offset_t)round_page( - (unsigned long)addr), PAGE_SIZE); + (unsigned long)addr), PAGE_SIZE * (idx+1)); return; } e->ptr = (void *)round_page((unsigned long)addr); MEMGUARD_CRIT_SECTION_ENTER; - STAILQ_INSERT_TAIL(&memguard_fifo_pool, e, entries); + STAILQ_INSERT_TAIL(mgfifo, e, entries); MEMGUARD_CRIT_SECTION_EXIT; } @@ -201,11 +227,12 @@ * future writes to it fail). */ static void -memguard_guard(void *addr) +memguard_guard(void *addr, int numpgs) { void *a = (void *)round_page((unsigned long)addr); (void)vm_map_protect(memguard_map, (vm_offset_t)a, - (vm_offset_t)((unsigned long)a + PAGE_SIZE), VM_PROT_READ, 0); + (vm_offset_t)((unsigned long)a + (PAGE_SIZE * numpgs)), + VM_PROT_READ, 0); } /* @@ -213,10 +240,63 @@ * allow full data access). */ static void -memguard_unguard(void *addr) +memguard_unguard(void *addr, int numpgs) { void *a = (void *)round_page((unsigned long)addr); (void)vm_map_protect(memguard_map, (vm_offset_t)a, - (vm_offset_t)((unsigned long)a + PAGE_SIZE), + (vm_offset_t)((unsigned long)a + (PAGE_SIZE * numpgs)), VM_PROT_READ | VM_PROT_WRITE, 0); } + +/* + * vtomgfifo() converts a virtual address of the first page allocated for + * an item to a memguard_fifo_pool reference for the corresponding item's + * size. + * + * vsetmgfifo() sets a reference in an underlying page for the specified + * virtual address to an appropriate memguard_fifo_pool. + * + * These routines are very similar to those defined by UMA in uma_int.h + */ +static struct memguard_fifo * +vtomgfifo(vm_offset_t va) +{ + vm_page_t p; + struct memguard_fifo *mgfifo; + + p = PHYS_TO_VM_PAGE(pmap_kextract(va)); + mgfifo = (struct memguard_fifo *)p->object; + + /* + * We use PG_SLAB, just like UMA does, even though we stash + * a reference to a memguard_fifo, and not a slab. + */ + if ((p->flags & PG_SLAB) == 0) + panic("MEMGUARD: Expected memguard_fifo reference to be set!"); + return mgfifo; +} + +static void +vsetmgfifo(vm_offset_t va, struct memguard_fifo *mgfifo) +{ + vm_page_t p; + + p = PHYS_TO_VM_PAGE(pmap_kextract(va)); + p->object = (vm_object_t)mgfifo; + /* + * We use PG_SLAB, just like UMA does, even though we stash + * a reference to a memguard_fifo, and not a slab. + */ + p->flags |= PG_SLAB; +} + +static void +vclrmgfifo(vm_offset_t va) +{ + vm_page_t p; + + p = PHYS_TO_VM_PAGE(pmap_kextract(va)); + p->object = NULL; + p->flags &= ~PG_SLAB; +} + --NMuMz9nt05w80d4+--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050202011157.GA55803>