ref: fcc336b9023e30f32652ba644663d356e00bf66b
parent: 0c705580ab670e94b3a792967b428ad841ce570f
author: cinap_lenrek <[email protected]>
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();