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.
This commit is contained in:
parent
128ea44a89
commit
2149600d12
13 changed files with 26 additions and 51 deletions
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue