Merge "app: aboot: check for buffer over reads"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 83d1531..3daaef5 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -2263,6 +2263,8 @@
 	int index = INVALID_PTN;
 	uint32_t i;
 	uint8_t lun = 0;
+	/*End of the sparse image address*/
+	uint32_t data_end = (uint32_t)data + sz;
 
 	index = partition_get_index(arg);
 	ptn = partition_get_offset(index);
@@ -2272,28 +2274,34 @@
 	}
 
 	size = partition_get_size(index);
-	if (ROUND_TO_PAGE(sz,511) > size) {
-		fastboot_fail("size too large");
-		return;
-	}
 
 	lun = partition_get_lun(index);
 	mmc_set_lun(lun);
 
+	if (sz < sizeof(sparse_header_t)) {
+		fastboot_fail("size too low");
+		return;
+	}
+
 	/* Read and skip over sparse image header */
 	sparse_header = (sparse_header_t *) data;
+
 	if (((uint64_t)sparse_header->total_blks * (uint64_t)sparse_header->blk_sz) > size) {
 		fastboot_fail("size too large");
 		return;
 	}
 
-	data += sparse_header->file_hdr_sz;
-	if(sparse_header->file_hdr_sz > sizeof(sparse_header_t))
+	data += sizeof(sparse_header_t);
+
+	if (data_end < (uint32_t)data) {
+		fastboot_fail("buffer overreads occured due to invalid sparse header");
+		return;
+	}
+
+	if(sparse_header->file_hdr_sz != sizeof(sparse_header_t))
 	{
-		/* Skip the remaining bytes in a header that is longer than
-		 * we expected.
-		 */
-		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+		fastboot_fail("sparse header size mismatch");
+		return;
 	}
 
 	dprintf (SPEW, "=== Sparse Image Header ===\n");
@@ -2318,17 +2326,20 @@
 		chunk_header = (chunk_header_t *) data;
 		data += sizeof(chunk_header_t);
 
+		if (data_end < (uint32_t)data) {
+			fastboot_fail("buffer overreads occured due to invalid sparse header");
+			return;
+		}
+
 		dprintf (SPEW, "=== Chunk Header ===\n");
 		dprintf (SPEW, "chunk_type: 0x%x\n", chunk_header->chunk_type);
 		dprintf (SPEW, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
 		dprintf (SPEW, "total_size: 0x%x\n", chunk_header->total_sz);
 
-		if(sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
+		if(sparse_header->chunk_hdr_sz != sizeof(chunk_header_t))
 		{
-			/* Skip the remaining bytes in a header that is longer than
-			 * we expected.
-			 */
-			data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+			fastboot_fail("chunk header size mismatch");
+			return;
 		}
 
 		chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
@@ -2359,6 +2370,11 @@
 				return;
 			}
 
+			if (data_end < (uint32_t)data + chunk_data_sz) {
+				fastboot_fail("buffer overreads occured due to invalid sparse header");
+				return;
+			}
+
 			if(mmc_write(ptn + ((uint64_t)total_blocks*sparse_header->blk_sz),
 						chunk_data_sz,
 						(unsigned int*)data))
@@ -2389,6 +2405,10 @@
 				return;
 			}
 
+			if (data_end < (uint32_t)data + sizeof(uint32_t)) {
+				fastboot_fail("buffer overreads occured due to invalid sparse header");
+				return;
+			}
 			fill_val = *(uint32_t *)data;
 			data = (char *) data + sizeof(uint32_t);
 			chunk_blk_cnt = chunk_data_sz / sparse_header->blk_sz;
@@ -2441,7 +2461,15 @@
 				return;
 			}
 			total_blocks += chunk_header->chunk_sz;
+			if ((uint32_t)data > UINT_MAX - chunk_data_sz) {
+				fastboot_fail("integer overflow occured");
+				return;
+			}
 			data += chunk_data_sz;
+			if (data_end < (uint32_t)data) {
+				fastboot_fail("buffer overreads occured due to invalid sparse header");
+				return;
+			}
 			break;
 
 			default: