shithub: riscv

Download patch

ref: 8fd1aa262681ee7380df46dd8fc0db066969320a
parent: 4ed396d438554c2dea8521b0e5a7ee51826d4125
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Apr 13 18:19:37 EDT 2016

libc: fix out of bounds access in dirpackage(), simplify

- dirpackage() was not checking if the stat entry lies within
the buffer. fixed.

- simplify dirpackage(), as we process all the bytes from
the buffer, we do not need to track "ss" here as its the same
as "ts".

- zero Dir* array pointer early in dirread() and dirreadall()
and avoid calling dirpackage on <= buffer length.

--- a/sys/src/libc/9sys/dirread.c
+++ b/sys/src/libc/9sys/dirread.c
@@ -7,29 +7,22 @@
 dirpackage(uchar *buf, long ts, Dir **d)
 {
 	char *s;
-	long ss, i, n, nn, m;
+	long i, n, nn, m;
 
-	*d = nil;
-	if(ts <= 0)
-		return 0;
-
 	/*
 	 * first find number of all stats, check they look like stats, & size all associated strings
 	 */
-	ss = 0;
 	n = 0;
 	for(i = 0; i < ts; i += m){
+		if(i+BIT16SZ >= ts)
+			return -1;
 		m = BIT16SZ + GBIT16(&buf[i]);
-		if(statcheck(&buf[i], m) < 0)
-			break;
-		ss += m;
+		if(i+m > ts || statcheck(&buf[i], m) < 0)
+			return -1;
 		n++;
 	}
 
-	if(i != ts)
-		return -1;
-
-	*d = malloc(n * sizeof(Dir) + ss);
+	*d = malloc(n * sizeof(Dir) + ts);
 	if(*d == nil)
 		return -1;
 
@@ -39,8 +32,8 @@
 	s = (char*)*d + n * sizeof(Dir);
 	nn = 0;
 	for(i = 0; i < ts; i += m){
-		m = BIT16SZ + GBIT16((uchar*)&buf[i]);
-		if(nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
+		m = BIT16SZ + GBIT16(&buf[i]);
+		if(i+m > ts || nn >= n || convM2D(&buf[i], m, *d + nn, s) != m){
 			free(*d);
 			*d = nil;
 			return -1;
@@ -58,11 +51,12 @@
 	uchar *buf;
 	long ts;
 
+	*d = nil;
 	buf = malloc(DIRMAX);
 	if(buf == nil)
 		return -1;
 	ts = read(fd, buf, DIRMAX);
-	if(ts >= 0)
+	if(ts > 0)
 		ts = dirpackage(buf, ts, d);
 	free(buf);
 	return ts;
@@ -74,6 +68,7 @@
 	uchar *buf, *nbuf;
 	long n, ts;
 
+	*d = nil;
 	buf = nil;
 	ts = 0;
 	for(;;){
@@ -88,7 +83,7 @@
 			break;
 		ts += n;
 	}
-	if(ts >= 0)
+	if(ts > 0)
 		ts = dirpackage(buf, ts, d);
 	free(buf);
 	if(ts == 0 && n < 0)