diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-08-27 03:47:18 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2019-08-27 03:47:18 +0200 |
commit | 2149600d129944f60cbc858bc669193af0523409 (patch) | |
tree | 89cd2d2b36e204bbb50ed2159ebdbf7f2cd7e01c /sys/src/9 | |
parent | 128ea44a89c7905612ad2fa5a61a9325ddfb5e1e (diff) |
kernel: catch execution read fault on SG_NOEXEC segment
fault() now has an additional pc argument that is
used to detect fault on a non-executable segment.
that is, we check on read fault if the segment
has the SG_NOEXEC attribute and the program counter
is within faulting page.
Diffstat (limited to 'sys/src/9')
-rw-r--r-- | sys/src/9/bcm/trap.c | 17 | ||||
-rw-r--r-- | sys/src/9/bcm64/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/kw/trap.c | 18 | ||||
-rw-r--r-- | sys/src/9/mtx/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/omap/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/pc/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/pc64/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/port/fault.c | 20 | ||||
-rw-r--r-- | sys/src/9/port/portfns.h | 2 | ||||
-rw-r--r-- | sys/src/9/ppc/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/teg2/trap.c | 2 | ||||
-rw-r--r-- | sys/src/9/xen/trap.c | 4 | ||||
-rw-r--r-- | sys/src/9/zynq/trap.c | 2 |
13 files changed, 26 insertions, 51 deletions
diff --git a/sys/src/9/bcm/trap.c b/sys/src/9/bcm/trap.c index 8522eacd2..5affb4070 100644 --- a/sys/src/9/bcm/trap.c +++ b/sys/src/9/bcm/trap.c @@ -87,8 +87,6 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) { int n, insyscall; char buf[ERRMAX]; - static int cnt, lastpid; - static ulong lastva; if(up == nil) { dumpregs(ureg); @@ -96,20 +94,7 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) } insyscall = up->insyscall; up->insyscall = 1; - /* this is quite helpful during mmu and cache debugging */ - if(va == lastva && up->pid == lastpid) { - ++cnt; - if (cnt >= 2) - /* fault() isn't fixing the underlying cause */ - panic("fault: %d consecutive faults for va %#lux", - cnt+1, va); - } else { - cnt = 0; - lastva = va; - lastpid = up->pid; - } - - n = fault(va, read); + n = fault(va, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/bcm64/trap.c b/sys/src/9/bcm64/trap.c index e64e41e77..3d74362a3 100644 --- a/sys/src/9/bcm64/trap.c +++ b/sys/src/9/bcm64/trap.c @@ -472,7 +472,7 @@ faultarm64(Ureg *ureg) case 8: case 9: case 10: case 11: // Access flag fault. case 12: case 13: case 14: case 15: // Permission fault. case 48: // tlb conflict fault. - if(fault(addr, read) == 0) + if(fault(addr, ureg->pc, read) == 0) break; /* wet floor */ diff --git a/sys/src/9/kw/trap.c b/sys/src/9/kw/trap.c index 131413c11..0ced0bd6e 100644 --- a/sys/src/9/kw/trap.c +++ b/sys/src/9/kw/trap.c @@ -319,8 +319,6 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) { int n, insyscall; char buf[ERRMAX]; - static int cnt, lastpid; - static ulong lastva; if(up == nil) { dumpregs(ureg); @@ -328,21 +326,7 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) } insyscall = up->insyscall; up->insyscall = 1; - - /* this is quite helpful during mmu and cache debugging */ - if(va == lastva && up->pid == lastpid) { - ++cnt; - if (cnt >= 2) - /* fault() isn't fixing the underlying cause */ - panic("fault: %d consecutive faults for va %#lux", - cnt+1, va); - } else { - cnt = 0; - lastva = va; - lastpid = up->pid; - } - - n = fault(va, read); + n = fault(va, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/mtx/trap.c b/sys/src/9/mtx/trap.c index 17c2b7e3d..3072e0849 100644 --- a/sys/src/9/mtx/trap.c +++ b/sys/src/9/mtx/trap.c @@ -321,7 +321,7 @@ faultpower(Ureg *ureg, ulong addr, int read) user = (ureg->srr1 & MSR_PR) != 0; insyscall = up->insyscall; up->insyscall = 1; - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/omap/trap.c b/sys/src/9/omap/trap.c index 3e27f08b4..e8802849e 100644 --- a/sys/src/9/omap/trap.c +++ b/sys/src/9/omap/trap.c @@ -333,7 +333,7 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) } insyscall = up->insyscall; up->insyscall = 1; - n = fault(va, read); + n = fault(va, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/pc/trap.c b/sys/src/9/pc/trap.c index 0d74f0a98..97931807f 100644 --- a/sys/src/9/pc/trap.c +++ b/sys/src/9/pc/trap.c @@ -735,7 +735,7 @@ fault386(Ureg* ureg, void*) insyscall = up->insyscall; up->insyscall = 1; - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/pc64/trap.c b/sys/src/9/pc64/trap.c index f1db63c23..0f6eed294 100644 --- a/sys/src/9/pc64/trap.c +++ b/sys/src/9/pc64/trap.c @@ -708,7 +708,7 @@ faultamd64(Ureg* ureg, void*) splx(s); nexterror(); } - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index f7732bbc3..4b6e12f67 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -142,7 +142,6 @@ done: static int fixfault(Segment *s, uintptr addr, int read) { - int type; Pte **pte, *etp; uintptr soff, mmuphys; Page **pg, *old, *new; @@ -159,8 +158,7 @@ fixfault(Segment *s, uintptr addr, int read) if(pg > etp->last) etp->last = pg; - type = s->type & SG_TYPE; - switch(type) { + switch(s->type & SG_TYPE) { default: panic("fault"); return -1; @@ -221,6 +219,12 @@ fixfault(Segment *s, uintptr addr, int read) (*pg)->modref = PG_MOD|PG_REF; break; } + +#ifdef PTENOEXEC + if((s->type & SG_NOEXEC) != 0) + mmuphys |= PTENOEXEC; +#endif + qunlock(s); putmmu(addr, mmuphys, *pg); @@ -246,12 +250,12 @@ mapphys(Segment *s, uintptr addr, int attr) mmuphys |= PTERONLY; #ifdef PTENOEXEC - if((attr & SG_NOEXEC) == SG_NOEXEC) + if((attr & SG_NOEXEC) != 0) mmuphys |= PTENOEXEC; #endif #ifdef PTEDEVICE - if((attr & SG_DEVICE) == SG_DEVICE) + if((attr & SG_DEVICE) != 0) mmuphys |= PTEDEVICE; else #endif @@ -266,7 +270,7 @@ mapphys(Segment *s, uintptr addr, int attr) } int -fault(uintptr addr, int read) +fault(uintptr addr, uintptr pc, int read) { Segment *s; char *sps; @@ -298,7 +302,9 @@ fault(uintptr addr, int read) if((attr & SG_TYPE) == SG_PHYSICAL) attr |= s->pseg->attr; - if((attr & SG_FAULT) != 0 || !read && (attr & SG_RONLY) != 0) { + if((attr & SG_FAULT) != 0 + || read? (attr & SG_NOEXEC) != 0 && (addr & -BY2PG) == (pc & -BY2PG): + (attr & SG_RONLY) != 0) { qunlock(s); up->psstate = sps; if(up->kp && up->nerrlab) /* for segio */ diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index c92706888..993dd4758 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -105,7 +105,7 @@ void exit(int); uvlong fastticks(uvlong*); uvlong fastticks2ns(uvlong); uvlong fastticks2us(uvlong); -int fault(uintptr, int); +int fault(uintptr, uintptr, int); void fdclose(int, int); Chan* fdtochan(int, int, int, int); int findmount(Chan**, Mhead**, int, int, Qid); diff --git a/sys/src/9/ppc/trap.c b/sys/src/9/ppc/trap.c index 7cc28c101..ebfb87fe6 100644 --- a/sys/src/9/ppc/trap.c +++ b/sys/src/9/ppc/trap.c @@ -324,7 +324,7 @@ faultpower(Ureg *ureg, ulong addr, int read) user = (ureg->srr1 & MSR_PR) != 0; insyscall = up->insyscall; up->insyscall = 1; - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/teg2/trap.c b/sys/src/9/teg2/trap.c index a956666ec..dfd57b2a5 100644 --- a/sys/src/9/teg2/trap.c +++ b/sys/src/9/teg2/trap.c @@ -607,7 +607,7 @@ faultarm(Ureg *ureg, uintptr va, int user, int read) insyscall = up->insyscall; up->insyscall = 1; - n = fault(va, read); /* goes spllo */ + n = fault(va, ureg->pc, read); /* goes spllo */ splhi(); if(n < 0){ char buf[ERRMAX]; diff --git a/sys/src/9/xen/trap.c b/sys/src/9/xen/trap.c index 1ab080c60..e8e401585 100644 --- a/sys/src/9/xen/trap.c +++ b/sys/src/9/xen/trap.c @@ -598,7 +598,7 @@ unexpected(Ureg* ureg, void*) } static void -fault386(Ureg* ureg, void* ) +fault386(Ureg* ureg, void*) { ulong addr; int read, user, n, insyscall; @@ -621,7 +621,7 @@ fault386(Ureg* ureg, void* ) panic("fault but up is zero; pc 0x%8.8lux addr 0x%8.8lux\n", ureg->pc, addr); insyscall = up->insyscall; up->insyscall = 1; - n = fault(addr, read); + n = fault(addr, ureg->pc, read); if(n < 0){ if(!user){ dumpregs(ureg); diff --git a/sys/src/9/zynq/trap.c b/sys/src/9/zynq/trap.c index cb35b4a9d..d9ceee74c 100644 --- a/sys/src/9/zynq/trap.c +++ b/sys/src/9/zynq/trap.c @@ -98,7 +98,7 @@ faultarm(Ureg *ureg, ulong fsr, uintptr addr) case 0x0B: /* domain fault L2 */ case 0x0D: /* permission fault L1 */ case 0x0F: /* permission fault L2 */ - if(fault(addr, read) == 0) + if(fault(addr, ureg->pc, read) == 0) break; /* wet floor */ default: |