ref: e28813a99c0e9554658f9a460fa8a3b7c2144225
parent: 3cbbeb8c5a5370bcee98f90257c86fde4b981037
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sat Mar 7 13:59:06 EST 2015
kernel: catch address overflow in syssegfree() the "to" address can overflow in syssegfree() causing wrong number of pages to be passed to mfreeseg(). with the current implementation of mfreeseg() however, this doesnt cause any data corruption but was just freeing an unexpected number of pages. this change checks for this condition in syssegfree() and errors out instead. also mfreeseg() was changed to take ulong argument for number of pages instead of int to keep it consistent with other routines that work with page counts.
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -167,7 +167,7 @@
void mallocsummary(void);
Block* mem2bl(uchar*, int);
ulong mcountseg(Segment*);
-void mfreeseg(Segment*, uintptr, int);
+void mfreeseg(Segment*, uintptr, ulong);
void microdelay(int);
uvlong mk64fract(uvlong, uvlong);
void mkqid(Qid*, vlong, ulong, int);
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -479,12 +479,15 @@
* called with s locked
*/
void
-mfreeseg(Segment *s, uintptr start, int pages)
+mfreeseg(Segment *s, uintptr start, ulong pages)
{int i, j, size;
uintptr soff;
Page *pg;
+ if(pages == 0)
+ return;
+
if((s->type&SG_TYPE) == SG_PHYSICAL)
return;
@@ -500,12 +503,12 @@
j = (soff&(PTEMAPMEM-1))/BY2PG;
size = s->mapsize;
- for(i = soff/PTEMAPMEM; i < size; i++) {- if(pages <= 0)
- return;
+ for(i = soff/PTEMAPMEM; i < size; i++, j = 0) { if(s->map[i] == nil) {- pages -= PTEPERTAB-j;
- j = 0;
+ j = PTEPERTAB - j;
+ if(j >= pages)
+ return;
+ pages -= j;
continue;
}
while(j < PTEPERTAB) {@@ -518,7 +521,6 @@
return;
j++;
}
- j = 0;
}
}
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -823,19 +823,23 @@
uintptr from, to;
from = va_arg(list, uintptr);
+ to = va_arg(list, ulong);
+ to += from;
+ if(to < from)
+ error(Ebadarg);
s = seg(up, from, 1);
if(s == nil)
error(Ebadarg);
- to = va_arg(list, ulong);
- to += from;
to &= ~(BY2PG-1);
from = PGROUND(from);
-
+ if(from >= to) {+ qunlock(s);
+ return 0;
+ }
if(to > s->top) {qunlock(s);
error(Ebadarg);
}
-
mfreeseg(s, from, (to - from) / BY2PG);
qunlock(s);
flushmmu();
--
⑨