Hello!

On Wed, 19 May 2004, Trog wrote:

> > Currently, ole2 scanning currently very slow on complex documents, even
> > when mfs is used for temp disk. Below are time's of scanning ole-based
> > metadata file (from 1C financial software, catched in wild due to
> > scanning timeouts; available on request) and simple profiling results for
> > ole2 extracting. All done under FreeBSD 4.9, 2.66GHz P4.
> >
> > As far as I see, the problem is enourmous number of read() syscalls.
> > Probably we should consider using mmap'ed file access, or implement some
> > internal buffering. Is it planned?
>
> Now 0.71 is out, I have committed code to CVS to use mmap() during ole2
> unpacking.

Thanx, looks much faster (~10 secs instead of 1min).

Attached patch also adds limits->maxfiles support to ole2 extraction code
(with total number of created files & dirs checked). I think it could be
useful for DoS prevention and additional speedup on busy systems.

Maxim Dounin
Rambler
Index: ole2_extract.c
===================================================================
RCS file: /cvsroot/clamav/clamav-devel/libclamav/ole2_extract.c,v
retrieving revision 1.19
diff -u -r1.19 ole2_extract.c
--- ole2_extract.c      19 May 2004 08:09:50 -0000      1.19
+++ ole2_extract.c      19 May 2004 19:41:42 -0000
@@ -457,14 +457,20 @@
 
 static void ole2_walk_property_tree(int fd, ole2_header_t *hdr, const char *dir, 
int32_t prop_index,
                                int (*handler)(int fd, ole2_header_t *hdr, property_t 
*prop, const char *dir),
-                               int rec_level, int file_count)
+                               const struct cl_limits *limits,
+                               int rec_level, int *file_count)
 {
        property_t prop_block[4];
        int32_t index, current_block, count=0, i;
        unsigned char *dirname;
        current_block = hdr->prop_start;
        
-       if ((prop_index < 0) || (rec_level > 100) || (file_count > 100000)) {
+       cli_dbgmsg("rec_level %d, file_count %d\n", rec_level, *file_count);
+       if ((prop_index < 0) || (rec_level > 100) || (*file_count > 100000)) {
+               return;
+       }
+       if(limits && limits->maxfiles && (*file_count > limits->maxfiles)) {
+               cli_dbgmsg("OLE2: Files limit reached (max: %d)\n", limits->maxfiles);
                return;
        }
        
@@ -499,32 +505,34 @@
        switch (prop_block[index].type) {
                case 5: /* Root Entry */
                        if ((prop_index != 0) || (rec_level !=0) ||
-                                       (file_count != 0)) {
+                                       (*file_count != 0)) {
                                /* Can only have RootEntry as the top */
                                cli_dbgmsg("ERROR: illegal Root Entry\n");
                                return;
                        }
                        hdr->sbat_root_start = prop_block[index].start_block;
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].prev, handler, rec_level+1, 
file_count);
+                               prop_block[index].prev, handler, limits, rec_level+1, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].next, handler, rec_level+1, 
file_count);
+                               prop_block[index].next, handler, limits, rec_level+1, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].child, handler, rec_level+1, 
file_count);
+                               prop_block[index].child, handler, limits, rec_level+1, 
file_count);
                        break;
                case 2: /* File */
+                       (*file_count)++;
                        if (!handler(fd, hdr, &prop_block[index], dir)) {
                                cli_dbgmsg("ERROR: handler failed\n");
                                return;
                        }
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].prev, handler, rec_level, 
file_count+1);
+                               prop_block[index].prev, handler, limits, rec_level, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].next, handler, rec_level, 
file_count+1);
+                               prop_block[index].next, handler, limits, rec_level, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].child, handler, rec_level, 
file_count+1);
+                               prop_block[index].child, handler, limits, rec_level, 
file_count);
                        break;
                case 1: /* Directory */
+                       (*file_count)++;
                        dirname = (char *) cli_malloc(strlen(dir)+8);
                        if (!dirname)  {
                                return;
@@ -536,11 +544,11 @@
                        }
                        cli_dbgmsg("OLE2 dir entry: %s\n",dirname);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].prev, handler, rec_level+1, 
file_count);
+                               prop_block[index].prev, handler, limits, rec_level+1, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dir,
-                               prop_block[index].next, handler, rec_level+1, 
file_count);
+                               prop_block[index].next, handler, limits, rec_level+1, 
file_count);
                        ole2_walk_property_tree(fd, hdr, dirname,
-                               prop_block[index].child, handler, rec_level+1, 
file_count);
+                               prop_block[index].child, handler, limits, rec_level+1, 
file_count);
                        free(dirname);
                        break;
                default:
@@ -687,11 +695,12 @@
        return TRUE;
 }
 
-int cli_ole2_extract(int fd, const char *dirname)
+int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits)
 {
        ole2_header_t hdr;
        int hdr_size;
        struct stat statbuf;
+       int file_count;
        
        cli_dbgmsg("in cli_ole2_extract()\n");
        
@@ -763,7 +772,8 @@
        
        /* OR */
        
-       ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, 0, 0);
+       file_count = 0;
+       ole2_walk_property_tree(fd, &hdr, dirname, 0, handler_writefile, limits, 0, 
&file_count);
 
 #ifdef HAVE_MMAP
        if (hdr.m_area != NULL) {
Index: ole2_extract.h
===================================================================
RCS file: /cvsroot/clamav/clamav-devel/libclamav/ole2_extract.h,v
retrieving revision 1.1
diff -u -r1.1 ole2_extract.h
--- ole2_extract.h      23 Jan 2004 11:17:16 -0000      1.1
+++ ole2_extract.h      19 May 2004 19:41:42 -0000
@@ -23,6 +23,8 @@
 #ifndef __OLE2_EXTRACT_H
 #define __OLE2_EXTRACT_H
 
-int cli_ole2_extract(int fd, const char *dirname);
+#include "clamav.h"
+
+int cli_ole2_extract(int fd, const char *dirname, const struct cl_limits *limits);
 
 #endif
Index: scanners.c
===================================================================
RCS file: /cvsroot/clamav/clamav-devel/libclamav/scanners.c,v
retrieving revision 1.66
diff -u -r1.66 scanners.c
--- scanners.c  11 May 2004 23:30:57 -0000      1.66
+++ scanners.c  19 May 2004 19:41:43 -0000
@@ -894,7 +894,7 @@
        return CL_ETMPDIR;
     }
 
-    if((ret = cli_ole2_extract(desc, dir))) {
+    if((ret = cli_ole2_extract(desc, dir, limits))) {
        cli_errmsg("ScanOLE2 -> %s\n", cl_strerror(ret));
        cli_rmdirs(dir);
        free(dir);

Reply via email to