summaryrefslogtreecommitdiff
path: root/sys/src/9/port/fault.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2019-08-27 03:47:18 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2019-08-27 03:47:18 +0200
commit2149600d129944f60cbc858bc669193af0523409 (patch)
tree89cd2d2b36e204bbb50ed2159ebdbf7f2cd7e01c /sys/src/9/port/fault.c
parent128ea44a89c7905612ad2fa5a61a9325ddfb5e1e (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/port/fault.c')
-rw-r--r--sys/src/9/port/fault.c20
1 files changed, 13 insertions, 7 deletions
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 */