ref: 2149600d129944f60cbc858bc669193af0523409
parent: 128ea44a89c7905612ad2fa5a61a9325ddfb5e1e
author: cinap_lenrek <[email protected]>
date: Mon Aug 26 23:47:18 EDT 2019
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.
--- a/sys/src/9/bcm/trap.c
+++ b/sys/src/9/bcm/trap.c
@@ -87,8 +87,6 @@
{
int n, insyscall;
char buf[ERRMAX];
- static int cnt, lastpid;
- static ulong lastva;
if(up == nil) {
dumpregs(ureg);
@@ -96,20 +94,7 @@
}
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);
--- a/sys/src/9/bcm64/trap.c
+++ b/sys/src/9/bcm64/trap.c
@@ -472,7 +472,7 @@
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 */
--- a/sys/src/9/kw/trap.c
+++ b/sys/src/9/kw/trap.c
@@ -319,8 +319,6 @@
{
int n, insyscall;
char buf[ERRMAX];
- static int cnt, lastpid;
- static ulong lastva;
if(up == nil) {
dumpregs(ureg);
@@ -328,21 +326,7 @@
}
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);
--- a/sys/src/9/mtx/trap.c
+++ b/sys/src/9/mtx/trap.c
@@ -321,7 +321,7 @@
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);
--- a/sys/src/9/omap/trap.c
+++ b/sys/src/9/omap/trap.c
@@ -333,7 +333,7 @@
}
insyscall = up->insyscall;
up->insyscall = 1;
- n = fault(va, read);
+ n = fault(va, ureg->pc, read);
if(n < 0){
if(!user){
dumpregs(ureg);
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -735,7 +735,7 @@
insyscall = up->insyscall;
up->insyscall = 1;
- n = fault(addr, read);
+ n = fault(addr, ureg->pc, read);
if(n < 0){
if(!user){
dumpregs(ureg);
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -708,7 +708,7 @@
splx(s);
nexterror();
}
- n = fault(addr, read);
+ n = fault(addr, ureg->pc, read);
if(n < 0){
if(!user){
dumpregs(ureg);
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -142,7 +142,6 @@
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 @@
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 @@
(*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 @@
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 @@
}
int
-fault(uintptr addr, int read)
+fault(uintptr addr, uintptr pc, int read)
{
Segment *s;
char *sps;
@@ -298,7 +302,9 @@
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 */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -105,7 +105,7 @@
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);
--- a/sys/src/9/ppc/trap.c
+++ b/sys/src/9/ppc/trap.c
@@ -324,7 +324,7 @@
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);
--- a/sys/src/9/teg2/trap.c
+++ b/sys/src/9/teg2/trap.c
@@ -607,7 +607,7 @@
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];
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -598,7 +598,7 @@
}
static void
-fault386(Ureg* ureg, void* )
+fault386(Ureg* ureg, void*)
{
ulong addr;
int read, user, n, insyscall;
@@ -621,7 +621,7 @@
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);
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -98,7 +98,7 @@
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: