summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2015-03-07 18:59:06 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2015-03-07 18:59:06 +0100
commitfcc336b9023e30f32652ba644663d356e00bf66b (patch)
tree2feb24c90a51a16c34ec77d46d196d682a838f8a /sys
parent0c705580ab670e94b3a792967b428ad841ce570f (diff)
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/src/9/port/portfns.h2
-rw-r--r--sys/src/9/port/segment.c16
-rw-r--r--sys/src/9/port/sysproc.c12
3 files changed, 18 insertions, 12 deletions
diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h
index d1e26d7e0..a93ddd2ab 100644
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -167,7 +167,7 @@ void* mallocalign(ulong, ulong, long, ulong);
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);
diff --git a/sys/src/9/port/segment.c b/sys/src/9/port/segment.c
index c64a4efbf..295c8551f 100644
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -479,12 +479,15 @@ mcountseg(Segment *s)
* 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 @@ mfreeseg(Segment *s, uintptr start, int pages)
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 @@ mfreeseg(Segment *s, uintptr start, int pages)
return;
j++;
}
- j = 0;
}
}
diff --git a/sys/src/9/port/sysproc.c b/sys/src/9/port/sysproc.c
index b787a3d6a..4b26d0970 100644
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -823,19 +823,23 @@ syssegfree(va_list list)
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();