--- clamav/clamav-devel/libclamav/others.c	2005/10/03 13:19:09	1.67
+++ clamav/clamav-devel/libclamav/others.c	2005/10/25 22:38:45	1.69
@@ -681,3 +681,88 @@
 
     return close(d);
 }
+
+/* Implement a generic bitset, trog@clamav.net */
+
+#define BITS_PER_CHAR (8)
+#define BITSET_DEFAULT_SIZE (1024)
+#define FALSE (0)
+#define TRUE (1)
+
+static unsigned long nearest_power(unsigned long num)
+{
+	unsigned long n = BITSET_DEFAULT_SIZE;
+
+	while (n < num) {
+		n <<= 1;
+		if (n == 0) {
+			return num;
+		}
+	}
+	return n;
+}
+
+bitset_t *cli_bitset_init()
+{
+	bitset_t *bs;
+	
+	bs = cli_malloc(sizeof(bitset_t));
+	if (!bs) {
+		return NULL;
+	}
+	bs->length = BITSET_DEFAULT_SIZE;
+	bs->bitset = cli_calloc(BITSET_DEFAULT_SIZE, 1);
+	return bs;
+}
+
+void cli_bitset_free(bitset_t *bs)
+{
+	if (!bs) {
+		return;
+	}
+	if (bs->bitset) {
+		free(bs->bitset);
+	}
+	free(bs);
+}
+
+static bitset_t *bitset_realloc(bitset_t *bs, unsigned long min_size)
+{
+	unsigned long new_length;
+	
+	new_length = nearest_power(min_size);
+	bs->bitset = (unsigned char *) cli_realloc(bs->bitset, new_length);
+	if (!bs->bitset) {
+		return NULL;
+	}
+	memset(bs->bitset+bs->length, 0, new_length-bs->length);
+	bs->length = new_length;
+	return bs;
+}
+
+int cli_bitset_set(bitset_t *bs, unsigned long bit_offset)
+{
+	unsigned long char_offset;
+	
+	char_offset = bit_offset / BITS_PER_CHAR;
+	bit_offset = bit_offset % BITS_PER_CHAR;
+
+	if (char_offset >= bs->length) {
+		bs = bitset_realloc(bs, char_offset+1);
+		if (!bs) {
+			return FALSE;
+		}
+	}
+	bs->bitset[char_offset] |= ((unsigned char)1 << bit_offset);
+	return TRUE;
+}
+
+int cli_bitset_test(bitset_t *bs, unsigned long bit_offset)
+{
+	unsigned long char_offset;
+	
+	char_offset = bit_offset / BITS_PER_CHAR;
+	bit_offset = bit_offset % BITS_PER_CHAR;
+	
+	return (bs->bitset[char_offset] & ((unsigned char)1 << bit_offset));
+}
--- clamav/clamav-devel/libclamav/ole2_extract.c	2005/03/18 13:52:06	1.35
+++ clamav/clamav-devel/libclamav/ole2_extract.c	2005/10/18 10:32:06	1.36
@@ -111,6 +111,7 @@
 	int32_t sbat_root_start __attribute__ ((packed));
 	unsigned char *m_area;
 	off_t m_length;
+	bitset_t *bitset;
 } ole2_header_t;
 
 typedef struct property_tag
@@ -468,7 +469,7 @@
 	if ((prop_index < 0) || (rec_level > 100) || (*file_count > 100000)) {
 		return;
 	}
-	
+
 	if (limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
 		cli_dbgmsg("OLE2: File limit reached (max: %d)\n", limits->maxfiles);
 		return;
@@ -507,6 +508,17 @@
 	prop_block[index].size = ole2_endian_convert_32(prop_block[index].size);
 	
 	print_ole2_property(&prop_block[index]);
+
+	/* Check we aren't in a loop */
+	if (cli_bitset_test(hdr->bitset, (unsigned long) prop_index)) {
+		/* Loop in property tree detected */
+		cli_dbgmsg("OLE2: Property tree loop detected at index %d\n", prop_index);
+		return;
+	}
+	if (!cli_bitset_set(hdr->bitset, (unsigned long) prop_index)) {
+		return;
+	}
+
 	switch (prop_block[index].type) {
 		case 5: /* Root Entry */
 			if ((prop_index != 0) || (rec_level !=0) ||
@@ -745,7 +757,7 @@
 	
 	/* size of header - size of other values in struct */
 	hdr_size = sizeof(struct ole2_header_tag) - sizeof(int32_t) -
-			sizeof(unsigned char *) - sizeof(off_t);
+			sizeof(unsigned char *) - sizeof(off_t) - sizeof(bitset_t *);
 
 	hdr.m_area = NULL;
 
@@ -791,7 +803,12 @@
 	hdr.xbat_count = ole2_endian_convert_32(hdr.xbat_count);
 
 	hdr.sbat_root_start = -1;
-	
+
+	hdr.bitset = cli_bitset_init();
+	if (!hdr.bitset) {
+		return CL_EOLE2;
+	}
+
 	if (strncmp(hdr.magic, magic_id, 8) != 0) {
 		cli_dbgmsg("OLE2 magic failed!\n");
 #ifdef HAVE_MMAP
@@ -799,6 +816,7 @@
 			munmap(hdr.m_area, hdr.m_length);
 		}
 #endif
+		cli_bitset_free(hdr.bitset);
 		return CL_EOLE2;
 	}
 
@@ -831,5 +849,6 @@
 		munmap(hdr.m_area, hdr.m_length);
 	}
 #endif
+	cli_bitset_free(hdr.bitset);
 	return 0;
 }