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