So, it looks like this is the patch that fixes the infinite loop. Comments, etc, appreciated. Security folks, does this look to you like it does the job, and can I upload it for sarge?
No word about a new upstream for sid. Will probably apply manually. -- ----------------------------------------------------------------- | ,''`. Stephen Gran | | : :' : [EMAIL PROTECTED] | | `. `' Debian user, admin, and developer | | `- http://www.debian.org | -----------------------------------------------------------------
diff -u clamav-0.84/libclamav/others.c clamav-0.84/libclamav/others.c
--- clamav-0.84/libclamav/others.c
+++ clamav-0.84/libclamav/others.c
@@ -608,0 +609,86 @@
+
+/* Implement a generic bitset */
+
+#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 = malloc(sizeof(bitset_t));
+ if (!bs) {
+ return NULL;
+ }
+ bs->length = BITSET_DEFAULT_SIZE;
+ bs->bitset = 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 *) 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));
+}
+
diff -u clamav-0.84/debian/changelog clamav-0.84/debian/changelog
--- clamav-0.84/debian/changelog
+++ clamav-0.84/debian/changelog
@@ -1,12 +1,19 @@
+clamav (0.84-2.sarge.5) stable-security; urgency=low
+
+ * Applied upstream fix for possible infinite loop
+ [libclamav/others.c libclamav/others.h
+ libclamav/ole2_extract.c CAN-2005-3239]
+
+ -- Stephen Gran <[EMAIL PROTECTED]> Sat, 22 Oct 2005 22:26:18 +0100
+
clamav (0.84-2.sarge.4) stable-security; urgency=high
* Non-maintainer upload by the Security Team
only in patch2:
unchanged:
--- clamav-0.84.orig/libclamav/others.h
+++ clamav-0.84/libclamav/others.h
@@ -23,6 +23,12 @@
#include <stdlib.h>
#include "cltypes.h"
+typedef struct bitset_tag
+{
+ unsigned char *bitset;
+ unsigned long length;
+} bitset_t;
+
void cli_warnmsg(const char *str, ...);
void cli_errmsg(const char *str, ...);
void cli_dbgmsg(const char *str, ...);
@@ -40,5 +46,8 @@
char *cli_gentemp(const char *dir);
unsigned int cli_rndnum(unsigned int max);
int cli_filecopy(const char *src, const char *dest);
-
+bitset_t *cli_bitset_init();
+void cli_bitset_free(bitset_t *bs);
+int cli_bitset_set(bitset_t *bs, unsigned long bit_offset);
+int cli_bitset_test(bitset_t *bs, unsigned long bit_offset);
#endif
only in patch2:
unchanged:
--- clamav-0.84.orig/libclamav/ole2_extract.c
+++ clamav-0.84/libclamav/ole2_extract.c
@@ -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
@@ -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,6 +803,11 @@
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");
@@ -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;
}
signature.asc
Description: Digital signature

