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.
This commit is contained in:
cinap_lenrek 2016-04-13 22:19:37 +02:00
parent 4ed396d438
commit 8fd1aa2626

View file

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