Browse code

improve handling of RAR archives

git-svn: trunk@2648

Tomasz Kojm authored on 2007/01/29 05:22:16
Showing 4 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sun Jan 28 21:20:05 CET 2007 (tk)
2
+---------------------------------
3
+  * libclamav: improve handling of RAR archives, thanks to Edwin
4
+
1 5
 Sat Jan 27 13:54:35 CET 2007 (acab)
2 6
 -----------------------------------
3 7
   * libclamav/pe.c: fix debug message logic, fixed handling of non aligned raw
... ...
@@ -192,12 +192,20 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c
192 192
 	continue;
193 193
     }
194 194
 */
195
+    return ret;
196
+}
197
+
198
+static int cli_unrar_checklimits(const cli_ctx *ctx, const rar_metadata_t *metadata, unsigned int files)
199
+{
195 200
     if(ctx->limits) {
196 201
 	if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) {
197 202
 	    if((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size >= ctx->limits->maxratio) {
198 203
 		cli_dbgmsg("RAR: Max ratio reached (normal: %u, compressed: %u, max: %ld)\n", metadata->unpack_size, metadata->pack_size, ctx->limits->maxratio);
199
-		*ctx->virname = "Oversized.RAR";
200
-		return CL_VIRUS;
204
+		if(BLOCKMAX) {
205
+		    *ctx->virname = "Oversized.RAR";
206
+		    return CL_VIRUS;
207
+		}
208
+		return CL_EMAXSIZE;
201 209
 	    }
202 210
 	}
203 211
 
... ...
@@ -207,7 +215,7 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c
207 207
 		*ctx->virname = "RAR.ExceededFileSize";
208 208
 		return CL_VIRUS;
209 209
 	    }
210
-	    return CL_SUCCESS;
210
+	    return CL_EMAXSIZE;
211 211
 	}
212 212
 
213 213
 	if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) {
... ...
@@ -216,11 +224,11 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c
216 216
 		*ctx->virname = "RAR.ExceededFilesLimit";
217 217
 		return CL_VIRUS;
218 218
 	    }
219
-	    return CL_BREAK;
219
+	    return CL_EMAXFILES;
220 220
 	}
221 221
     }
222 222
 
223
-    return ret;
223
+    return CL_SUCCESS;
224 224
 }
225 225
 
226 226
 static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check)
... ...
@@ -255,6 +263,16 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
255 255
     do {
256 256
 	int rc;
257 257
 	rar_state.unpack_data->ofd = -1;
258
+	ret = cli_unrar_extract_next_prepare(&rar_state,dir);
259
+	if(ret != CL_SUCCESS) 
260
+	    break;
261
+	ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count);
262
+	if(ret && ret != CL_VIRUS) {
263
+	    ret = CL_CLEAN;
264
+	    continue;
265
+	} else if(ret == CL_VIRUS) {
266
+	    break;
267
+	}
258 268
 	ret = cli_unrar_extract_next(&rar_state,dir);
259 269
 	if(rar_state.unpack_data->ofd > 0) {
260 270
 	    lseek(rar_state.unpack_data->ofd,0,SEEK_SET);
... ...
@@ -1527,26 +1527,25 @@ int cli_unrar_open(int fd, const char *dirname, rar_state_t* state)
1527 1527
 	return CL_SUCCESS;
1528 1528
 }
1529 1529
 
1530
-int cli_unrar_extract_next(rar_state_t* state,const char* dirname)
1530
+int cli_unrar_extract_next_prepare(rar_state_t* state,const char* dirname)
1531 1531
 {
1532
-	int retval;
1533 1532
 	unsigned char filename[1024];
1534 1533
 	int ofd;
1535 1534
 
1536 1535
 	rar_metadata_t *new_metadata;
1537
-	file_header_t *file_header = read_block(state->fd, FILE_HEAD);
1538
-		if (!file_header) {
1536
+	state->file_header = read_block(state->fd, FILE_HEAD);
1537
+		if (!state->file_header) {
1539 1538
 		return CL_BREAK;/* end of archive */
1540 1539
 		}
1541 1540
 		new_metadata = cli_malloc(sizeof(rar_metadata_t));
1542 1541
 		if (!new_metadata) {
1543 1542
 		return CL_EMEM;
1544 1543
 		}
1545
-		new_metadata->pack_size = file_header->pack_size;
1546
-		new_metadata->unpack_size = file_header->unpack_size;
1547
-		new_metadata->crc = file_header->file_crc;
1548
-		new_metadata->method = file_header->method;
1549
-		new_metadata->filename = strdup(file_header->filename);
1544
+		new_metadata->pack_size = state->file_header->pack_size;
1545
+		new_metadata->unpack_size = state->file_header->unpack_size;
1546
+		new_metadata->crc = state->file_header->file_crc;
1547
+		new_metadata->method = state->file_header->method;
1548
+		new_metadata->filename = strdup(state->file_header->filename);
1550 1549
 		new_metadata->next = NULL;
1551 1550
 		new_metadata->encrypted = FALSE;
1552 1551
 	if (state->metadata_tail == NULL) {
... ...
@@ -1555,7 +1554,7 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname)
1555 1555
 		state->metadata_tail->next = new_metadata;
1556 1556
 		state->metadata_tail = new_metadata;
1557 1557
 		}
1558
-		if (file_header->flags & LHD_COMMENT) {
1558
+		if (state->file_header->flags & LHD_COMMENT) {
1559 1559
 			comment_header_t *comment_header;
1560 1560
 
1561 1561
 			cli_dbgmsg("File comment present\n");
... ...
@@ -1585,54 +1584,62 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname)
1585 1585
 				free(comment_header);
1586 1586
 			}
1587 1587
 		}
1588
-	if (lseek(state->fd, file_header->start_offset+file_header->head_size, SEEK_SET) !=
1589
-							file_header->start_offset+file_header->head_size) {
1590
-		cli_dbgmsg("Seek failed: %ld\n", state->offset+file_header->head_size);
1591
-			free(file_header->filename);
1592
-			free(file_header);
1588
+		return CL_SUCCESS;
1589
+}
1590
+
1591
+int cli_unrar_extract_next(rar_state_t* state,const char* dirname)
1592
+{
1593
+	int ofd;
1594
+	int retval;
1595
+
1596
+	if (lseek(state->fd, state->file_header->start_offset+state->file_header->head_size, SEEK_SET) !=
1597
+							state->file_header->start_offset+state->file_header->head_size) {
1598
+		cli_dbgmsg("Seek failed: %ld\n", state->offset+state->file_header->head_size);
1599
+			free(state->file_header->filename);
1600
+			free(state->file_header);
1593 1601
 		return CL_ERAR;
1594 1602
         	}
1595
-		if (file_header->flags & LHD_PASSWORD) {
1596
-			cli_dbgmsg("PASSWORDed file: %s\n", file_header->filename);
1603
+		if (state->file_header->flags & LHD_PASSWORD) {
1604
+			cli_dbgmsg("PASSWORDed file: %s\n", state->file_header->filename);
1597 1605
 		state->metadata_tail->encrypted = TRUE;
1598 1606
 		} else /*if (file_header->unpack_size)*/ {
1599 1607
 		snprintf(state->filename, 1024, "%s/%lu.ura", dirname, state->file_count);
1600 1608
 		ofd = open(state->filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600);
1601 1609
 			if (ofd < 0) {
1602
-				free(file_header->filename);
1603
-				free(file_header);
1610
+				free(state->file_header->filename);
1611
+				free(state->file_header);
1604 1612
 				cli_dbgmsg("ERROR: Failed to open output file\n");
1605 1613
 			return CL_EOPEN;
1606 1614
 			}
1607 1615
 		state->unpack_data->ofd = ofd;
1608
-			if (file_header->method == 0x30) {
1616
+			if (state->file_header->method == 0x30) {
1609 1617
 				cli_dbgmsg("Copying stored file (not packed)\n");
1610
-			copy_file_data(state->fd, ofd, file_header->pack_size);
1618
+			copy_file_data(state->fd, ofd, state->file_header->pack_size);
1611 1619
 			} else {
1612
-			state->unpack_data->dest_unp_size = file_header->unpack_size;
1613
-			state->unpack_data->pack_size = file_header->pack_size;
1614
-				if (file_header->unpack_ver <= 15) {
1620
+			state->unpack_data->dest_unp_size = state->file_header->unpack_size;
1621
+			state->unpack_data->pack_size = state->file_header->pack_size;
1622
+				if (state->file_header->unpack_ver <= 15) {
1615 1623
 				retval = rar_unpack(state->fd, 15, (state->file_count>1) &&
1616 1624
 						((state->main_hdr->flags&MHD_SOLID)!=0), state->unpack_data);
1617 1625
 				} else {
1618
-				if ((state->file_count == 1) && (file_header->flags & LHD_SOLID)) {
1626
+				if ((state->file_count == 1) && (state->file_header->flags & LHD_SOLID)) {
1619 1627
 						cli_warnmsg("RAR: First file can't be SOLID.\n");
1620 1628
 					return CL_ERAR;
1621 1629
 					} else {
1622
-					retval = rar_unpack(state->fd, file_header->unpack_ver,
1623
-							file_header->flags & LHD_SOLID,	state->unpack_data);
1630
+					retval = rar_unpack(state->fd, state->file_header->unpack_ver,
1631
+							state->file_header->flags & LHD_SOLID,	state->unpack_data);
1624 1632
 					}
1625 1633
 				}
1626
-				cli_dbgmsg("Expected File CRC: 0x%x\n", file_header->file_crc);
1634
+				cli_dbgmsg("Expected File CRC: 0x%x\n", state->file_header->file_crc);
1627 1635
 			cli_dbgmsg("Computed File CRC: 0x%x\n", state->unpack_data->unp_crc^0xffffffff);
1628 1636
 			if (state->unpack_data->unp_crc != 0xffffffff) {
1629
-				if (file_header->file_crc != (state->unpack_data->unp_crc^0xffffffff)) {
1637
+				if (state->file_header->file_crc != (state->unpack_data->unp_crc^0xffffffff)) {
1630 1638
 						cli_warnmsg("RAR CRC error. Please report the bug at http://bugs.clamav.net/\n");
1631 1639
 					}
1632 1640
 				}
1633 1641
 				if (!retval) {
1634 1642
 					cli_dbgmsg("Corrupt file detected\n");
1635
-					if (file_header->flags & LHD_SOLID) {
1643
+					if (state->file_header->flags & LHD_SOLID) {
1636 1644
 						cli_dbgmsg("SOLID archive, can't continue\n");
1637 1645
 					return CL_ERAR;
1638 1646
 					}
... ...
@@ -1640,14 +1647,14 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname)
1640 1640
 			}
1641 1641
 		
1642 1642
 		}
1643
-	if (lseek(state->fd, file_header->next_offset, SEEK_SET) != file_header->next_offset) {
1644
-			cli_dbgmsg("ERROR: seek failed: %ld\n", file_header->next_offset);
1645
-			free(file_header->filename);
1646
-			free(file_header);
1643
+	if (lseek(state->fd, state->file_header->next_offset, SEEK_SET) != state->file_header->next_offset) {
1644
+			cli_dbgmsg("ERROR: seek failed: %ld\n", state->file_header->next_offset);
1645
+			free(state->file_header->filename);
1646
+			free(state->file_header);
1647 1647
 			return CL_ERAR;
1648 1648
 		}
1649
-		free(file_header->filename);
1650
-		free(file_header);
1649
+		free(state->file_header->filename);
1650
+		free(state->file_header);
1651 1651
 	unpack_free_data(state->unpack_data);
1652 1652
 	state->file_count++;
1653 1653
 	return CL_SUCCESS;
... ...
@@ -293,6 +293,7 @@ typedef struct unpack_data_tag
293 293
 } unpack_data_t;
294 294
 
295 295
 typedef struct rar_state_tag {
296
+	file_header_t* file_header;
296 297
 	rar_metadata_t *metadata;
297 298
 	rar_metadata_t *metadata_tail;
298 299
 	unpack_data_t *unpack_data;
... ...
@@ -327,6 +328,7 @@ enum BLOCK_TYPES
327 327
 
328 328
 
329 329
 int cli_unrar_extract_next(rar_state_t* state,const char* dirname);
330
+int cli_unrar_extract_next_prepare(rar_state_t* state,const char* dirname);
330 331
 int cli_unrar_open(int fd, const char *dirname, rar_state_t* state);
331 332
 void cli_unrar_close(rar_state_t* state);
332 333
 unsigned int rar_get_char(int fd, unpack_data_t *unpack_data);