shithub: riscv

Download patch

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();