Several missing bounds checks were discovered in libzipfile(the affected version is 4.4.4, 5.0.2, 5.1.1). It could occur while uncompressing a specially crafted file.
http://androidxref.com/5.1.1_r6/xref/system/core/libzipfile/centraldir.c
The patch is as follows:
--- a/centraldir.c 2016-08-17 11:44:37.661604000 +0800
+++ b/centraldir.c 2016-08-17 12:09:49.273598000 +0800
@@ -32,6 +32,11 @@
return buf[0] | (buf[1] << 8);
}
+static int is_valid_pointer(const void* ptr, const void *start, const void *end)
+{
+ return (ptr >= start) && (ptr < end);
+}
+
static int
read_central_dir_values(Zipfile* file, const unsigned char* buf, int len)
{
@@ -102,23 +107,48 @@
entry->fileName = NULL;
}
p += entry->fileNameLength;
-
+ if (!is_valid_pointer(p, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
// extra field
p += extraFieldLength;
+ if (!is_valid_pointer(p, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
// comment, if any
p += fileCommentLength;
+ if (!is_valid_pointer(p, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
*buf = p;
// the size of the extraField in the central dir is how much data there is,
// but the one in the local file header also contains some padding.
p = file->buf + localHeaderRelOffset;
+ if (!is_valid_pointer(p, file->buf, file->buf + file->bufsize) ||
+ !is_valid_pointer(p + 0x1d, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
extraFieldLength = read_le_short(&p[0x1c]);
dataOffset = localHeaderRelOffset + LFH_SIZE
+ entry->fileNameLength + extraFieldLength;
entry->data = file->buf + dataOffset;
+ if (!is_valid_pointer(entry->data, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
+ if (entry->compressionMethod == STORED &&
+ entry->uncompressedSize > (unsigned int) (file->buf + file->bufsize - entry->data)) {
+ fprintf(stderr, "unkown error\n");
+ return -1;
+ }
#if 0
printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d "
"entry->fileNameLength=%d extraFieldLength=%d\n",
@@ -199,6 +229,10 @@
// Loop through and read the central dir entries.
p = buf + file->centralDirOffest;
+ if (!is_valid_pointer(p, file->buf, file->buf + file->bufsize)) {
+ fprintf(stderr, "invalid pointer\n");
+ return -1;
+ }
len = (buf+bufsize)-p;
for (i=0; i < file->totalEntryCount; i++) {
Zipentry* entry = malloc(sizeof(Zipentry));
These vulnerabilities may result in corruption of sensitive information, a crash, or code execution among other things.
fastboot update xxx.zip