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;
 }

Attachment: signature.asc
Description: Digital signature

Reply via email to