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.
This commit is contained in:
cinap_lenrek 2015-03-07 18:59:06 +01:00
parent 0c705580ab
commit fcc336b902
3 changed files with 18 additions and 12 deletions

View file

@ -167,7 +167,7 @@ void* mallocalign(ulong, ulong, long, ulong);
void mallocsummary(void); void mallocsummary(void);
Block* mem2bl(uchar*, int); Block* mem2bl(uchar*, int);
ulong mcountseg(Segment*); ulong mcountseg(Segment*);
void mfreeseg(Segment*, uintptr, int); void mfreeseg(Segment*, uintptr, ulong);
void microdelay(int); void microdelay(int);
uvlong mk64fract(uvlong, uvlong); uvlong mk64fract(uvlong, uvlong);
void mkqid(Qid*, vlong, ulong, int); void mkqid(Qid*, vlong, ulong, int);

View file

@ -479,12 +479,15 @@ mcountseg(Segment *s)
* called with s locked * called with s locked
*/ */
void void
mfreeseg(Segment *s, uintptr start, int pages) mfreeseg(Segment *s, uintptr start, ulong pages)
{ {
int i, j, size; int i, j, size;
uintptr soff; uintptr soff;
Page *pg; Page *pg;
if(pages == 0)
return;
if((s->type&SG_TYPE) == SG_PHYSICAL) if((s->type&SG_TYPE) == SG_PHYSICAL)
return; return;
@ -500,12 +503,12 @@ mfreeseg(Segment *s, uintptr start, int pages)
j = (soff&(PTEMAPMEM-1))/BY2PG; j = (soff&(PTEMAPMEM-1))/BY2PG;
size = s->mapsize; size = s->mapsize;
for(i = soff/PTEMAPMEM; i < size; i++) { for(i = soff/PTEMAPMEM; i < size; i++, j = 0) {
if(pages <= 0)
return;
if(s->map[i] == nil) { if(s->map[i] == nil) {
pages -= PTEPERTAB-j; j = PTEPERTAB - j;
j = 0; if(j >= pages)
return;
pages -= j;
continue; continue;
} }
while(j < PTEPERTAB) { while(j < PTEPERTAB) {
@ -518,7 +521,6 @@ mfreeseg(Segment *s, uintptr start, int pages)
return; return;
j++; j++;
} }
j = 0;
} }
} }

View file

@ -823,19 +823,23 @@ syssegfree(va_list list)
uintptr from, to; uintptr from, to;
from = va_arg(list, uintptr); from = va_arg(list, uintptr);
to = va_arg(list, ulong);
to += from;
if(to < from)
error(Ebadarg);
s = seg(up, from, 1); s = seg(up, from, 1);
if(s == nil) if(s == nil)
error(Ebadarg); error(Ebadarg);
to = va_arg(list, ulong);
to += from;
to &= ~(BY2PG-1); to &= ~(BY2PG-1);
from = PGROUND(from); from = PGROUND(from);
if(from >= to) {
qunlock(s);
return 0;
}
if(to > s->top) { if(to > s->top) {
qunlock(s); qunlock(s);
error(Ebadarg); error(Ebadarg);
} }
mfreeseg(s, from, (to - from) / BY2PG); mfreeseg(s, from, (to - from) / BY2PG);
qunlock(s); qunlock(s);
flushmmu(); flushmmu();