[Pkg-clamav-devel] Bug#740059: clamav: LibClamAV Error: CRITICAL: fmap() failed

Sebastian Andrzej Siewior sebastian at breakpoint.cc
Fri Apr 11 20:07:07 UTC 2014


tags 740059 + upstream
forwarded 740059 https://bugzilla.clamav.net/show_bug.cgi?id=10971
thanks

On 2014-03-15 20:37:01 [+0100], Sebastian Andrzej Siewior wrote:
> On 2014-03-16 00:16:38 [+0700], Ста Деюс wrote:
> > Здравствуй, Sebastian.
 
Hello Ста,

the patch below is what I sent to clamav's bugzilla. It drops the memory
constrain a little which means it should be fine on 64bit. Now I wait what
upstream says.

>From 0a6fe67b724919a8c5583a762b7e10330c06b271 Mon Sep 17 00:00:00 2001
From: Sebastian Andrzej Siewior <sebastian at breakpoint.cc>
Date: Thu, 10 Apr 2014 23:08:02 +0200
Subject: [PATCH] libclamav: fmap: try to mmap() the file instead read it
 completly

On unix platform the fmap_check_empty() function maps the complete file
by allocating the memory via mmap() with the write flag on. On systems
with not a lot of memory it means that a file can't be scanned. For
instance a 1GiB file on a system with 512MiB of memory.
This patch changes the behaviour to what we have on win32:
- the malloc() cl_fmap_t structure
- mmap() the file as RO only. Since it content is backed by file on disk
  we mmap() any file as long as our virtual memory space is large
  enough. That means this will fail on 32bit architectures which try
  scan a file which is ~2.8GiB. This failed before as well but now we
  aleast not limited by our physical memory.

Signed-off-by: Sebastian Andrzej Siewior <sebastian at breakpoint.cc>
---
 libclamav/fmap.c |   85 +++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 71 insertions(+), 14 deletions(-)

diff --git a/libclamav/fmap.c b/libclamav/fmap.c
index 09b2306..929b496 100644
--- a/libclamav/fmap.c
+++ b/libclamav/fmap.c
@@ -52,6 +52,7 @@ static inline unsigned int fmap_which_page(fmap_t *m, size_t at);
 /* pread proto here in order to avoid the use of XOPEN and BSD_SOURCE
    which may in turn prevent some mmap constants to be defined */
 ssize_t pread(int fd, void *buf, size_t count, off_t offset);
+static cl_fmap_t *cl_fmap_mmap_fd(int fd, size_t offset, size_t len);
 
 /* vvvvv POSIX STUFF BELOW vvvvv */
 static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
@@ -61,12 +62,8 @@ static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
 
 
 fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
-    unsigned int pages, mapsz, hdrsz;
-    unsigned short dumb = 1;
-    int pgsz = cli_getpagesize();
     STATBUF st;
     fmap_t *m;
-    void *handle = (void*)(ssize_t)fd;
 
     *empty = 0;
     if(FSTAT(fd, &st)) {
@@ -84,10 +81,11 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
 	cli_warnmsg("fmap: attempted oof mapping\n");
 	return NULL;
     }
-    m = cl_fmap_open_handle((void*)(ssize_t)fd, offset, len, pread_cb, 1);
+    m = cl_fmap_mmap_fd(fd, offset, len);
     if (!m)
 	return NULL;
     m->mtime = st.st_mtime;
+    m->handle = (void*)(long)fd;
     m->handle_is_fd = 1;
     return m;
 }
@@ -161,6 +159,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) { /* WIN3
 }
 #endif /* _WIN32 */
 
+/* vvvvv MEMORY STUFF BELOW vvvvv */
+
+static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock);
+static void mem_unneed_off(fmap_t *m, size_t at, size_t len);
+static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint);
+static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len);
+
+static void unmap_none(fmap_t *m) {}
+
 /* vvvvv SHARED STUFF BELOW vvvvv */
 
 #define FM_MASK_COUNT 0x3fffffff
@@ -277,6 +284,65 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
     return m;
 }
 
+static void unmap_free_mmap(fmap_t *m)
+{
+	void *data = (void *)m->data;
+	munmap(data, m->real_len);
+	free(m);
+}
+
+static cl_fmap_t *cl_fmap_mmap_fd(int fd, size_t offset, size_t len)
+{
+    cl_fmap_t *m;
+    void *data;
+    int pgsz = cli_getpagesize();
+
+    if(offset < 0 || offset != fmap_align_to(offset, pgsz)) {
+	cli_warnmsg("fmap: attempted mapping with unaligned offset\n");
+	return NULL;
+    }
+    if(!len) {
+	cli_dbgmsg("fmap: attempted void mapping\n");
+	return NULL;
+    }
+    if (offset >= len) {
+	cli_warnmsg("fmap: attempted oof mapping\n");
+	return NULL;
+    }
+
+    m = cli_calloc(1, sizeof(*m));
+    if (!m) {
+	    cli_warnmsg("fmap: map allocation failed 1\n");
+	    return NULL;
+    }
+
+    data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, offset);
+    if (data == MAP_FAILED) {
+	    cli_warnmsg("fmap: mmap() in file failed: %m\n");
+	    goto err_free;
+    }
+
+    if(!m) {
+	cli_warnmsg("fmap: map allocation failed 2\n");
+	return NULL;
+    }
+    m->data = data;
+    m->len = len;
+    m->real_len = len;
+    m->pgsz = pgsz;
+    m->pages = fmap_align_items(len, pgsz);;
+    m->unmap = unmap_free_mmap;
+    m->need = mem_need;
+    m->need_offstr = mem_need_offstr;
+    m->gets = mem_gets;
+    m->unneed_off = mem_unneed_off;
+    m->offset = offset;
+    return m;
+err_free:
+    free(m);
+    return NULL;
+}
+
 static void fmap_aging(fmap_t *m) {
 #ifdef ANONYMOUS_MAP
     if(!m->aging) return;
@@ -639,15 +705,6 @@ static const void *handle_gets(fmap_t *m, char *dst, size_t *at, size_t max_len)
     return dst;
 }
 
-/* vvvvv MEMORY STUFF BELOW vvvvv */
-
-static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock);
-static void mem_unneed_off(fmap_t *m, size_t at, size_t len);
-static const void *mem_need_offstr(fmap_t *m, size_t at, size_t len_hint);
-static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len);
-
-static void unmap_none(fmap_t *m) {}
-
 extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
 {
     int pgsz = cli_getpagesize();
-- 
1.7.10.4



More information about the Pkg-clamav-devel mailing list