git: 9front

Download patch

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