[Bug 64] Any user can trigger a panic in mmap with an overlapping mapping
Hi, We just came across another issue that allows a user to crash the system through mmap. Despite trying, we didn't notice any more serious privilege escalation opportunities. /* * mmap_dup_panic.c *Demonstrate a panic through the mmap system call. * * gcc -g mmap_dup_panic.c -o mmap_dup_panic */ #ifdef BUG_WRITEUP //--- Any user can trigger a panic in mmap with an overlapping mapping Impact: Any user can trigger a panic by requesting a large mapping that overlaps with an existing mapping. Description: It is possible for an mmap() call to request a mapping at a virtual address that overlaps an existing mapping. This is checked for in uvm_map() by calling uvm_map_isavail() with the hint address and size.. There is a flaw in uvm_map_isavail() when the requested size is very large. The code looks up the maps at the start and end address with: if (*start_ptr == NULL) { *start_ptr = uvm_map_entrybyaddr(atree, addr); if (*start_ptr == NULL) return 0; } else KASSERT(*start_ptr == uvm_map_entrybyaddr(atree, addr)); if (*end_ptr == NULL) { if (VMMAP_FREE_END(*start_ptr) >= addr + sz) *end_ptr = *start_ptr; else { *end_ptr = uvm_map_entrybyaddr(atree, addr + sz - 1); if (*end_ptr == NULL) return 0; } } else KASSERT(*end_ptr == uvm_map_entrybyaddr(atree, addr + sz - 1)); Due to an integer overflow that can occur when computing "addr + sz" it is possible for the end_ptr map to be computed incorrectly (setting "*end_ptr = *start_ptr"). Later when this same function iterates over the maps between the start and end maps, the function may fail to notice that a large mapping overlaps with an existing mapping. If uvm_map_isavail() indicates that the hint address is available, uvm_map() will continue its processing without assigning a new address. It will eventually call uvm_map_fix_space() which performs its own sanity lookup with uvm_mapent_addr_insert(), and panics if an overlapping mapping is added: res = RB_INSERT(uvm_map_addr, &map->addr, entry); if (res != NULL) { panic("uvm_mapent_addr_insert: map %p entry %p " "(0x%lx-0x%lx G=0x%lx F=0x%lx) insert collision " "with entry %p (0x%lx-0x%lx G=0x%lx F=0x%lx)", map, entry, entry->start, entry->end, entry->guard, entry->fspace, res, res->start, res->end, res->guard, res->fspace); } An attacker can take advantage of this to intentionally trigger a panic to crash the system. This does not require any special privileges. In theory this flaw might allow an attacker to make a mapping that wraps around from user addresses, through kernel addresses and back to low user addresses. Such a mapping might allow access to kernel memory or to the NULL page (useful for performing certain attacks against NULL pointer use in the kernel). However NCC was unable to find any way to create such a mapping without causing a panic since it does not appear to be possible to make a mapping above the stack segment. All wrap-around mappings lower than this address overlap with the stack segment and result in a panic. Reproduction: Run the attached mmap_dup_panic.c program. It first maps a page in and then performs a second mmap() call to request another mapping at the next page address. This second mapping overlaps the first due to the large size, and causes a panic message such as "panic: uvm_mapent_addr_insert: map 0xff00036be300 entry 0xff000311d178 (0x1dcc5600-0x1dcc5600 G=0x0 F=0x2) insert collision with entry 0xff000272de08 (0x1dcc5600-0x1dcc5600 G=0x0 F=0x1000)" NCC Group was able to reproduce this issue on OpenBSD 5.9-stable kernel pulled from CVS on July 25, 2016. Recommendation: Detect when "addr + sz" causes an integer overflow in uvm_map_isavail(). Return zero indicating that this mapping is not available in this case. Reported: 2016-07-28 Fixed:notyet #endif // BUG_WRITEUP --- #include #include #include #include #include void xperror(int cond, char *msg) { if(cond) { perror(msg); exit(1); } } int main(int argc, char **argv) { int fd; char *p, *pg; fd = open("/tmp/mapfile", O_RDWR|O_CREAT, 0666); xperror(fd == -1, "/tmp/mapfile"); write(fd, "testing\n", 8); pg = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); xperror(pg == MAP_FAILED, "mmap"); p = mmap(pg+4096, 0xff00, 0, 0, fd, 0); xperror(pg == MAP_FAILED, "mmap2"); printf("no crash!\n"); return 0; } Tim Newsham Distinguished Security Engineer, Security Consulting NCC Group Tim.Newsham@nccgroup.trust | PGP: B415 550D BEE9 07DB B4C9 F96C 8EFE CB2F 402D 3DF0
format errors in {,s}bin
I have found this useful. It's caught a few errors. Everything currently compiles (in my limited testing), so it's a good way to keep it that way. It could use some more testing on exotic archs so as to not break builds. Index: sbin/Makefile.inc === RCS file: /cvs/src/sbin/Makefile.inc,v retrieving revision 1.6 diff -u -p -r1.6 Makefile.inc --- sbin/Makefile.inc 11 Jul 2014 13:13:04 - 1.6 +++ sbin/Makefile.inc 6 Jan 2016 18:55:55 - @@ -2,4 +2,4 @@ BINDIR?= /sbin LDSTATIC= ${STATIC} -COPTS+=-Werror-implicit-function-declaration +COPTS+=-Werror-implicit-function-declaration -Wformat -Werror=format Index: bin/Makefile.inc === RCS file: /cvs/src/bin/Makefile.inc,v retrieving revision 1.6 diff -u -p -r1.6 Makefile.inc --- bin/Makefile.inc11 Jul 2014 13:13:04 - 1.6 +++ bin/Makefile.inc6 Jan 2016 18:55:07 - @@ -2,4 +2,4 @@ BINDIR?= /bin LDSTATIC= ${STATIC} -COPTS+=-Werror-implicit-function-declaration +COPTS+=-Werror-implicit-function-declaration -Wformat -Werror=format
patch for resolv.conf(5)
The resolver supports more than 3 nameservers. Index: resolv.conf.5 === RCS file: /cvs/src/share/man/man5/resolv.conf.5,v retrieving revision 1.48 diff -u -p -r1.48 resolv.conf.5 --- resolv.conf.5 23 Nov 2015 18:04:53 - 1.48 +++ resolv.conf.5 28 Jul 2016 20:21:37 - @@ -118,8 +118,8 @@ Scoped IPv6 address notation is accepted for details). .Pp Up to -.Dv MAXNS -(currently 3) name servers may be listed, one per line. +.Dv ASR_MAXNS +(currently 5) name servers may be listed, one per line. If there are multiple servers, the resolver library queries them in the order listed. If no
pmapassert
Hi, personally, i like running w/pmap asserts w/o DEBUG too, and this would allow just that, effortless switching between KDASSERT/assert. -Artturi Index: sys/arch/arm/include/pmap.h === RCS file: /cvs/src/sys/arch/arm/include/pmap.h,v retrieving revision 1.40 diff -u -p -u -r1.40 pmap.h --- sys/arch/arm/include/pmap.h 22 Mar 2016 23:35:01 - 1.40 +++ sys/arch/arm/include/pmap.h 28 Jul 2016 14:36:48 - @@ -77,6 +77,8 @@ #include #endif +#definePMAPASSERT KDASSERT + /* * a pmap describes a processes' 4GB virtual address space. this * virtual address space can be broken up into 4096 1MB regions which Index: sys/arch/arm/arm/pmap7.c === RCS file: /cvs/src/sys/arch/arm/arm/pmap7.c,v retrieving revision 1.28 diff -u -p -u -r1.28 pmap7.c --- sys/arch/arm/arm/pmap7.c27 Jul 2016 21:12:49 - 1.28 +++ sys/arch/arm/arm/pmap7.c28 Jul 2016 14:36:49 - @@ -832,7 +832,7 @@ pmap_free_l2_bucket(pmap_t pm, struct l2 pt_entry_t *ptep; u_short l1idx; - KDASSERT(count <= l2b->l2b_occupancy); + PMAPASSERT(count <= l2b->l2b_occupancy); /* * Update the bucket's reference count according to how many @@ -919,7 +919,7 @@ pmap_l2ptp_ctor(void *v) * correct. */ l2b = pmap_get_l2_bucket(pmap_kernel(), va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(va)]; pte = *ptep; @@ -1004,7 +1004,7 @@ pmap_clearbit(struct vm_page *pg, u_int pv->pv_flags &= ~maskbits; l2b = pmap_get_l2_bucket(pm, va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(va)]; npte = opte = *ptep; @@ -1152,7 +1152,7 @@ pmap_page_remove(struct vm_page *pg) pm = pv->pv_pmap; l2b = pmap_get_l2_bucket(pm, pv->pv_va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)]; if (*ptep != 0) { @@ -1253,8 +1253,8 @@ pmap_enter(pmap_t pm, vaddr_t va, paddr_ NPDEBUG(PDB_ENTER, printf("pmap_enter: pm %p va 0x%lx pa 0x%lx prot %x flag %x\n", pm, va, pa, prot, flags)); - KDASSERT((flags & PMAP_WIRED) == 0 || (flags & PROT_MASK) != 0); - KDASSERT(((va | pa) & PGOFSET) == 0); + PMAPASSERT((flags & PMAP_WIRED) == 0 || (flags & PROT_MASK) != 0); + PMAPASSERT(((va | pa) & PGOFSET) == 0); /* * Get a pointer to the page. Later on in this function, we @@ -1593,7 +1593,7 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, v va, pa, prot)); l2b = pmap_get_l2_bucket(pmap_kernel(), va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(va)]; opte = *ptep; @@ -1642,7 +1642,7 @@ pmap_kremove(vaddr_t va, vsize_t len) next_bucket = eva; l2b = pmap_get_l2_bucket(pmap_kernel(), va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); sptep = ptep = &l2b->l2b_kva[l2pte_index(va)]; mappings = 0; @@ -1664,7 +1664,7 @@ pmap_kremove(vaddr_t va, vsize_t len) va += PAGE_SIZE; ptep++; } - KDASSERT(mappings <= l2b->l2b_occupancy); + PMAPASSERT(mappings <= l2b->l2b_occupancy); l2b->l2b_occupancy -= mappings; } cpu_cpwait(); @@ -1688,7 +1688,7 @@ pmap_extract(pmap_t pm, vaddr_t va, padd /* * These should only happen for pmap_kernel() */ - KDASSERT(pm == pmap_kernel()); + PMAPASSERT(pm == pmap_kernel()); pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET); } else { /* @@ -2116,7 +2116,7 @@ pmap_unwire(pmap_t pm, vaddr_t va) NPDEBUG(PDB_WIRING, printf("pmap_unwire: pm %p, va 0x%08lx\n", pm, va)); l2b = pmap_get_l2_bucket(pm, va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(va)]; pte = *ptep; @@ -2337,7 +2337,7 @@ pmap_grow_map(vaddr_t va, pt_entry_t cac *pap = pa; l2b = pmap_get_l2_bucket(pmap_kernel(), va); - KDASSERT(l2b != NULL); + PMAPASSERT(l2b != NULL); ptep = &l2b->l2b_kva[l2pte_index(va)]; *ptep = L2_S_PROTO | pa | cache_mode | @@ -2450,7 +2450,7 @@ pmap_growkernel(vaddr_t maxkvaddr) printf("pmap_growkernel: growing kernel from 0x%lx to 0x%lx\n", pmap_curmaxkvaddr, maxkvaddr)); - KDASSERT(maxkvaddr <= virtual_end); + PMAPASSERT(maxkvaddr <= virtual_end); /*
Re: Regression tests for calendar(1)
Thus said "Andy Bradford" on 28 Jul 2016 02:56:59 -0600: > Not enough? Different style required? Does the patch need to be broken > up? Or a different approach? Specifically, I originally had in mind, a single monolithic input file (generated with as many possible combinations of rules as I did in the current wdout.in) with 366+ test outputs (one for each day of the year, with maybe a few more from a non-leap year), but wasn't certain if that was necessary. Thanks, Andy -- TAI64 timestamp: 4000579a1a60
Style update for some files in arch/arm
I found a few files that could use updated function declarations. Here is my diff: Index: sys/arch/arm/arm/conf.c === RCS file: /cvs/src/sys/arch/arm/arm/conf.c,v retrieving revision 1.46 diff -u -r1.46 conf.c --- sys/arch/arm/arm/conf.c23 May 2016 00:05:34 -1.46 +++ sys/arch/arm/arm/conf.c28 Jul 2016 14:26:46 - @@ -403,8 +403,7 @@ * Returns true if dev is /dev/mem or /dev/kmem. */ int -iskmemdev(dev) -dev_t dev; +iskmemdev(dev_t dev) { return (major(dev) == mem_no && minor(dev) < 2); } @@ -413,8 +412,7 @@ * Returns true if dev is /dev/zero. */ int -iszerodev(dev) -dev_t dev; +iszerodev(dev_t dev) { return (major(dev) == mem_no && minor(dev) == 3); } Index: sys/arch/arm/arm/vm_machdep.c === RCS file: /cvs/src/sys/arch/arm/arm/vm_machdep.c,v retrieving revision 1.17 diff -u -r1.17 vm_machdep.c --- sys/arch/arm/arm/vm_machdep.c24 Apr 2016 01:31:02 -1.17 +++ sys/arch/arm/arm/vm_machdep.c28 Jul 2016 14:26:46 - @@ -96,13 +96,8 @@ * accordingly. */ void -cpu_fork(p1, p2, stack, stacksize, func, arg) -struct proc *p1; -struct proc *p2; -void *stack; -size_t stacksize; -void (*func) (void *); -void *arg; +cpu_fork(struct proc *p1, struct proc *p2, void *stack, +size_t stacksize, void (*func) (void *), void *arg) { struct pcb *pcb = (struct pcb *)&p2->p_addr->u_pcb; struct trapframe *tf; @@ -166,9 +161,7 @@ * do not need to pass an access_type to pmap_enter(). */ void -vmapbuf(bp, len) -struct buf *bp; -vsize_t len; +vmapbuf(struct buf *bp, vsize_t len) { vaddr_t faddr, taddr, off; paddr_t fpa; @@ -204,9 +197,7 @@ * Unmap a previously-mapped user I/O request. */ void -vunmapbuf(bp, len) -struct buf *bp; -vsize_t len; +vunmapbuf(struct buf *bp, vsize_t len) { vaddr_t addr, off; @@ -227,5 +218,3 @@ bp->b_data = bp->b_saveaddr; bp->b_saveaddr = 0; } - -/* End of vm_machdep.c */ -- -Rob Tate
Re: jot(1) bugs, test suite
Here's a full patch including two small manpage tweaks. It contains the three hunks that fix FreeBSD's regress tests from my previous mail: * initialize begin, ender, step, reps (from attila) * set steps to -1 if ender < begin (adapted from FreeBSD) * properly skip "%%" in the format string (from OpenBSD r1.8, pjanzen) In addition, get rid of the nasty mask loop and just compute whatever we need to compute in the most sensible order. This simplifies the code quite a bit and is inspired by dsl@NetBSD's r1.21. Note that the output loop only depends on reps, begin and step, so we never need to compute ender and we only need to compute something else if ender was specified. We now only produce infinite output if it was explicitly requested by setting reps or steps to zero on the command line. Also note that if randomized output is requested, there's never the need to compute anything, so just skip that piece of code in that case. I will import a tweaked and expanded version of the regress tests when the tree is fully unlocked. Index: jot.1 === RCS file: /var/cvs/src/usr.bin/jot/jot.1,v retrieving revision 1.21 diff -u -p -r1.21 jot.1 --- jot.1 17 Jul 2016 04:15:25 - 1.21 +++ jot.1 27 Jul 2016 19:27:38 - @@ -104,11 +104,10 @@ in which case the data is inserted rathe The last four arguments indicate, respectively, the maximum number of data, the lower bound, the upper bound, and the step size. -While at least one of them must appear, -any of the other three may be omitted, and +Any of these may be omitted, and will be considered as such if given as .Ql - . -Any three of these arguments determines the fourth. +Any three of these arguments determine the fourth. If four are specified and the given and computed values of .Ar reps conflict, the lower value is used. Index: jot.c === RCS file: /var/cvs/src/usr.bin/jot/jot.c,v retrieving revision 1.28 diff -u -p -r1.28 jot.c --- jot.c 17 Jul 2016 04:04:46 - 1.28 +++ jot.c 28 Jul 2016 11:26:16 - @@ -52,12 +52,17 @@ #defineENDER_DEF 100 #defineSTEP_DEF1 +#defineSTEP1 +#defineENDER 2 +#defineBEGIN 4 +#defineREPS8 + #defineis_default(s) (strcmp((s), "-") == 0) -static double begin; -static double ender; -static double s; -static longreps; +static double begin = BEGIN_DEF; +static double ender = ENDER_DEF; +static double step = STEP_DEF; +static longreps = REPS_DEF; static boolrandomize; static boolinfinity; static boolboring; @@ -131,9 +136,9 @@ main(int argc, char *argv[]) switch (argc) { /* examine args right to left, falling thru cases */ case 4: if (!is_default(argv[3])) { - if (!sscanf(argv[3], "%lf", &s)) + if (!sscanf(argv[3], "%lf", &step)) errx(1, "Bad s value: %s", argv[3]); - mask |= 01; + mask |= STEP; if (randomize) warnx("random seeding not supported"); } @@ -141,7 +146,7 @@ main(int argc, char *argv[]) if (!is_default(argv[2])) { if (!sscanf(argv[2], "%lf", &ender)) ender = argv[2][strlen(argv[2])-1]; - mask |= 02; + mask |= ENDER; if (prec == -1) n = getprec(argv[2]); } @@ -149,7 +154,7 @@ main(int argc, char *argv[]) if (!is_default(argv[1])) { if (!sscanf(argv[1], "%lf", &begin)) begin = argv[1][strlen(argv[1])-1]; - mask |= 04; + mask |= BEGIN; if (prec == -1) prec = getprec(argv[1]); if (n > prec) /* maximum precision */ @@ -159,114 +164,65 @@ main(int argc, char *argv[]) if (!is_default(argv[0])) { if (!sscanf(argv[0], "%ld", &reps)) errx(1, "Bad reps value: %s", argv[0]); - mask |= 010; + mask |= REPS; if (prec == -1) prec = 0; } break; case 0: - usage(); + /* Use defaults. */ break; default: errx(1, "Too many arguments. What do you mean by %s?", argv[4]); } getformat(); - while (mask)/* 4 bit mask has 1's where last 4 args were given */ - switch (mask) { /* fill in the 0's by default or computation */
Followup patch for regression to calendar(1)
Hello, Here's the followup patch that accounts for the missed events. Specifically, some kinds of events actually can have a differing month (specifically Easter and Weekly events like Every Monday). This allows all tests to pass (from previous email): Index: day.c === RCS file: /home/cvs/src/usr.bin/calendar/day.c,v retrieving revision 1.33 diff -u -p -r1.33 day.c --- day.c 13 Jul 2016 21:32:01 - 1.33 +++ day.c 28 Jul 2016 08:46:54 - @@ -543,7 +543,9 @@ isnow(char *endp, int bodun) tdiff = difftime(ttmp, f_time)/ SECSPERDAY; if (tdiff <= offset + f_dayAfter || (bodun && tdiff == -1)) { - if ((tmtmp.tm_mon == month) && + if (((tmtmp.tm_mon == month) || +(flags & F_SPECIAL) || +(interval == WEEKLY)) && (tdiff >= 0 || (bodun && tdiff == -1))) { if ((tmp = malloc(sizeof(struct match))) == NULL) -- TAI64 timestamp: 40005799c9d4
Regression tests for calendar(1)
Hello, A few weeks ago I submitted a patch to calendar(1) that helped it handle fifth weekday events and 31st events, and afterward, I noticed that there were no regression tests. In writing them, I discovered that while the patch fixed these two particular cases, it broke others. I'll send a potential fix which passes all the tests in a following email. But here is a potential set of regressions and comments/suggestions are appreciated. Are there too many tests? Not enough? Different style required? Does the patch need to be broken up? Thanks. Index: Makefile === RCS file: /home/cvs/src/regress/usr.bin/Makefile,v retrieving revision 1.32 diff -u -p -r1.32 Makefile --- Makefile26 Jul 2015 17:29:41 - 1.32 +++ Makefile28 Jul 2016 08:25:26 - @@ -1,7 +1,7 @@ # $OpenBSD: Makefile,v 1.32 2015/07/26 17:29:41 zhuk Exp $ # $NetBSD: Makefile,v 1.1 1997/12/30 23:27:11 cgd Exp $ -SUBDIR+= basename bc dc diff diff3 dirname doas file grep gzip +SUBDIR+= basename bc calendar dc diff diff3 dirname doas file grep gzip SUBDIR+= m4 mandoc openssl sdiff sed signify sort tsort SUBDIR+= xargs Index: calendar/20160101.wdout === RCS file: calendar/20160101.wdout diff -N calendar/20160101.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160101.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,8 @@ +Jan 01*First Friday +Jan 01*First Friday in Jan +Jan 02*First Saturday +Jan 02*First Saturday in Jan +Jan 03*First Sunday +Jan 03*First Sunday in Jan +Jan 04*First Monday +Jan 04*First Monday in Jan Index: calendar/20160114.manout === RCS file: calendar/20160114.manout diff -N calendar/20160114.manout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160114.manout28 Jul 2016 08:25:26 - @@ -0,0 +1,2 @@ +Jan 14*Every Thursday +Jan 15*15th of every month Index: calendar/20160115.wdout === RCS file: calendar/20160115.wdout diff -N calendar/20160115.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160115.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,8 @@ +Jan 15*Third Friday +Jan 15*Third Friday in Jan +Jan 16*Third Saturday +Jan 16*Third Saturday in Jan +Jan 17*Third Sunday +Jan 17*Third Sunday in Jan +Jan 18*Third Monday +Jan 18*Third Monday in Jan Index: calendar/20160129.wdout === RCS file: calendar/20160129.wdout diff -N calendar/20160129.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160129.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,9 @@ +Jan 29*Fifth Friday +Jan 29*Fifth Friday in Jan +Jan 30*Fifth Saturday +Jan 30*Fifth Saturday in Jan +Jan 31*Fifth Sunday +Jan 31*Fifth Sunday in Jan +Feb 01*First Monday +Feb 01*First Monday in Feb +Feb 01*Fifth Monday in Jan Index: calendar/20160131.monout === RCS file: calendar/20160131.monout diff -N calendar/20160131.monout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160131.monout28 Jul 2016 08:25:26 - @@ -0,0 +1,3 @@ +Jan 31*Every Sunday +Feb 01*First of Month +Feb 01*Every Monday Index: calendar/20160201.wdout === RCS file: calendar/20160201.wdout diff -N calendar/20160201.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160201.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,6 @@ +Feb 01*First Monday +Feb 01*First Monday in Feb +Feb 01*Fifth Monday in Jan +Feb 02*First Tuesday +Feb 02*First Tuesday in Feb +Feb 02*Fifth Tuesday in Jan Index: calendar/20160203.wdout === RCS file: calendar/20160203.wdout diff -N calendar/20160203.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160203.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,6 @@ +Feb 03*First Wednesday +Feb 03*First Wednesday in Feb +Feb 03*Fifth Wednesday in Jan +Feb 04*First Thursday +Feb 04*First Thursday in Feb +Feb 04*Fifth Thursday in Jan Index: calendar/20160229.wdout === RCS file: calendar/20160229.wdout diff -N calendar/20160229.wdout --- /dev/null 1 Jan 1970 00:00:00 - +++ calendar/20160229.wdout 28 Jul 2016 08:25:26 - @@ -0,0 +1,5 @@ +Feb 29*Fifth Monday +Feb 29*Fifth Monday in Feb +Mar 01*First Tuesday +Mar 01*Firs
Re: arm: pmap uvm_fault findings
On Wed, Jul 27, 2016 at 08:06:57PM +0200, Patrick Wildt wrote: > On Tue, Jul 26, 2016 at 06:43:18PM +0200, Patrick Wildt wrote: > > Hi, > > > > I've been trying to debug a pmap issue on ARM. I have no solution, but > > I would like to share my findings so far. > > > > First of all, the panic/uvm_fault: > > > > > > login: > > uvm_fault(0xca06c858, 0, 1, 0) -> e > > Fatal kernel mode data abort: 'Translation Fault (P)' > > trapframe: 0xc986bd98 > > DFSR=0007, DFAR=000c, spsr=6113 > > r0 =, r1 =ccaa7148, r2 =00136000, r3 = > > r4 =0012, r5 =ccaa7148, r6 =3213, r7 =0005 > > r8 =3213000e, r9 =0021, r10=cc634698, r11=c986be34 > > r12=cd43a9a0, ssp=c986bde8, slr=c054c1d0, pc =c054c1d0 > > > > Stopped at pmap_enter+0x178: ldr r6, [r0, #0x00c] > > ddb> trace > > pmap_enter+0xc > > scp=0xc054c064 rlv=0xc04f60c0 (uvm_fault+0xa28) > > rsp=0xc986be38 rfp=0xc986bf54 > > r10=0x r9=0x0001 r8=0x r7=0xc050fe80 > > r6=0x r5=0xc4a5aad0 r4=0x0001 > > uvm_fault+0xc > > scp=0xc04f56a4 rlv=0xc0547e68 (data_abort_handler+0x264) > > rsp=0xc986bf58 rfp=0xc986bfac > > r10=0xc986bfb0 r9=0x0007 r8=0xc986a000 r7=0x0001 > > r6=0xca06c858 r5=0x0001 r4=0x00136000 > > data_abort_handler+0xc > > scp=0xc0547c10 rlv=0xc05477bc (exception_exit) > > rsp=0xc986bfb0 rfp=0xbffc2430 > > r10=0x00da776c r9=0x0001 r8=0x60165dbc r7=0x > > r6=0x0200 r5=0x00d0c920 r4=0x4188e9f4 > > > > The faulting instruction is in pmap_enter() of pamp7.c: > > > > if (opg) { > > /* > > * Replacing an existing mapping with a new > > one. > > * It is part of our managed memory so we > > * must remove it from the PV list > > */ > > pve = pmap_remove_pv(opg, pm, va); > > pve is NULL -> oflags = pve->pv_flags; > > } else > > > > How did we come here? pmap_enter() was called to enter mapping for a > > given virtual and physical address. The VA is 0x136000. Then it looked > > if there is already a mapping at the given address. Turns out there is! > > opte (old pagetable entry) is set to 0x429f202c. This is an "invalid" > > (means not active) page entry pointing to the physical page 0x429f2000. > > Using the vm_pages struct for that physical address, we can have a look > > at its virtual addresses. > > > > vm_pages: > > 0xc4f86754: 429f1000 > > 0xc4f86758: 0 > > 0xc4f8675c: 0 > > 0xc4f86760: 3 > > 0xc4f86764: 0 > > 0xc4f86768: 0 > > 0xc4f8676c: 0 > > 0xc4f86770: c47263f0 > > 0xc4f86774: c4f86590 > > 0xc4f86778: c4a721d0 > > 0xc4f8677c: c520d200 > > 0xc4f86780: 0 > > 0xc4f86784: 0 > > 0xc4f86788: ca32b230 > > 0xc4f8678c: 0 > > 0xc4f86790: 0 > > 0xc4f86794: 0 > > 0xc4f86798: 14 > > 0xc4f8679c: 41 > > 0xc4f867a0: 0 > > 0xc4f867a4: 429f2000 <-- vm_page.phys_addr > > 0xc4f867a8: 0 > > 0xc4f867ac: cd43a9a0 <-- vm_page.mdpage.pvh_list > > 0xc4f867b0: 3 > > 0xc4f867b4: 0 > > 0xc4f867b8: 0 > > 0xc4f867bc: 0 > > 0xc4f867c0: > > 0xc4f867c4: > > 0xc4f867c8: c4f50760 > > 0xc4f867cc: c4c67990 > > 0xc4f867d0: c50374d0 > > 0xc4f867d4: 0 > > 0xc4f867d8: 0 > > 0xc4f867dc: c0714248 > > 0xc4f867e0: cf2c6000 > > 0xc4f867e4: 0 > > 0xc4f867e8: 4d > > 0xc4f867ec: 385 > > 0xc4f867f0: 1 > > 0xc4f867f4: 429f3000 > > > > vm_page.mdpage.pvh_list: > > 0xcd43a9a0: 0 <-- next ptr in list > > 0xcd43a9a4: ccaa7148 <- pmap > > 0xcd43a9a8: 717c7000 <- va > > 0xcd43a9ac: b <- flags > > > > This means, the physical page already has a VA. Oh, and it belongs > > to the same pmap. Have a look at register r5, that's the pmap we want > > to enter a mapping for. But it's not the kernel pmap: > > > > ddb> print kernel_pmap_store > > c073b8f4 > > > > So wait, the only VA for that physical address is 0x717c7000; but the > > VA I used to look the physical page up is 0x136000. That is weird. > > > > So now we got a pmap_enter() for a physical address and a virtual > > address, where the virtual address is already used by the same pmap > > for another physical address. But that physical address thinks a > > completely different VA is using it. > > > > The phys address behind the mapping is 0x429f2000. The phys address > > it wanted to map the VA to is in R6: 0x3213. > > > > That's probably not enough to find the exact fault, but it's a writeup > > of what I have found so far. > > > > Patrick > > So, I found a suspicious place, added printfs, triggered the bug again > and voila, I think I got it. > > I was looking for places w