[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6230-g2215872
aCaB
acab at clamav.net
Sun Aug 22 14:11:14 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit 22158726cfd7630db7bc12fdaab77e5703c548c3
Author: aCaB <acab at clamav.net>
Date: Sun Aug 22 15:32:07 2010 +0200
merge --squash clamav-0.96.2
diff --git a/ChangeLog b/ChangeLog
index 9fc89c7..9e11328 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,561 @@
+Thu Aug 12 18:49:37 CEST 2010 (tk)
+----------------------------------
+ * V 0.96.2
+
+Thu Aug 12 13:18:24 CEST 2010 (tk)
+----------------------------------
+ * contrib: add safe_clamd from Luca (bb#2026)
+
+Wed Aug 11 13:39:11 EEST 2010 (edwin)
+-------------------------------------
+ * freshclam: uses private symbol which changed proto, change name to prevent crash (bb #2187)
+
+Tue Aug 10 14:01:27 CEST 2010 (tk)
+----------------------------------
+ * clamdscan: fix parsing of virus names in extended mode and --stream (bb#2184)
+
+Mon Aug 9 19:46:58 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/detect.cpp: Mac OS X can run 64-bit apps on 32-bit kernel (bb #2153).
+
+Mon Aug 9 16:49:44 CEST 2010 (tk)
+----------------------------------
+ * libclamav/others.h: bump f-level
+
+Mon Aug 9 13:21:31 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: fix handling of --datadir (bb#2180)
+
+Mon Aug 9 13:02:26 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher-ac.c: improve offset handling (bb#2170)
+
+Sun Aug 8 15:59:41 CEST 2010 (acab)
+------------------------------------
+ * libclamav/7z/Archive/7z/7zDecode.c: shut up a warning (bb#2172)
+
+Fri Aug 6 13:47:18 CEST 2010 (acab)
+------------------------------------
+ * libclamav/autoit.c: properly resume from empty files
+ regression introduced in ac867aad (bb#2171)
+
+Fri Aug 6 11:37:14 CEST 2010 (tk)
+----------------------------------
+ * libclamav/elf.c: fix zero mem alloc warning (bb#2173)
+
+Thu Aug 5 11:58:56 CEST 2010 (acab)
+------------------------------------
+ * win32: fix libclamav's triple and fix GetVersion (bb#2152 and bb#2153)
+
+Mon Aug 2 23:05:50 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode.c: save lsig counts/offsets (bb #2055).
+
+Mon Aug 2 21:51:32 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/{bytecode,matcher}.c: matchicon API (bb #2139)
+
+Mon Aug 2 17:16:24 CEST 2010 (acab)
+------------------------------------
+ * libclamav/pe_icons.c: BE fixes (bb#2151)
+
+Mon Aug 2 16:08:04 CEST 2010 (tk)
+----------------------------------
+ * freshclam/manager.c: don't call cli_bytecode_prepare() when Bytecode is
+ disabled in freshclam.conf (bb#2149)
+
+Mon Aug 2 15:37:19 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher: make icon sigs work with bytecode (bb#2137)
+
+Fri Jul 30 17:46:14 CEST 2010 (acab)
+------------------------------------
+ * libclamav/others.h: bump CLI_MAX_ALLOCATION by 5 MB (needed by lzma - bb#2124)
+
+Fri Jul 30 15:51:06 CEST 2010 (acab)
+------------------------------------
+ * libclamav, unit_tests: use cached PE metadata when matching icons (better fix for
+ bb#2064, partially reverts d932a6d)
+ add some unit tests for ign2, ldb, idb
+
+Fri Jul 30 15:15:35 CEST 2010 (tk)
+----------------------------------
+ * freshclam: fix parsing of extended log entries
+
+Fri Jul 30 14:20:50 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/pdf.c: improve extraction of PDF objects (bb #1596, #1994, #2029).
+
+Thu Jul 29 16:56:00 CEST 2010 (acab)
+------------------------------------
+ * libclamav/matcher.c: make cli_lsig_eval use cached executable metadata rather
+ than parsing the file again
+
+Thu Jul 29 14:07:31 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav: introduce BC_STARTUP bytecode that can turn off JIT (bb #2078, #2101)
+
+Thu Jul 29 03:54:45 CEST 2010 (acab)
+------------------------------------
+ * libclamav/scanners.c: use fmap in scan_embpe
+
+Thu Jul 29 02:40:16 CEST 2010 (acab)
+------------------------------------
+ * libclamav: use fmap in autoit
+
+Tue Jul 27 14:16:59 CEST 2010 (acab)
+------------------------------------
+ * clamav-milter: noisily fallback on default value if MaxFileSize is set
+ to 0 (bb#2081)
+
+Mon Jul 26 13:16:07 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/phishcheck.c: don't phishcheck email addresses (bb #2067)
+
+Mon Jul 26 12:55:20 EEST 2010 (edwin)
+------------------------------------
+ * clamd/session.c: treat MULTISCAN as CONTSCAN on non-directories (bb #1869).
+
+Sat Jul 24 17:43:16 CEST 2010 (acab)
+------------------------------------
+ * win32: upgrade project files to vs10
+
+Fri Jul 23 22:32:18 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode_vm.c: fix use of uninitialized value (bb #2140).
+
+Thu Jul 22 22:32:08 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/bytecode2llvm.cpp: detect PaX and fallback to intepreter if
+ needed (bb #2092).
+ * libclamav/bytecode.c: selfcheck on startup (bb #2092).
+
+Thu Jul 22 16:36:32 CEST 2010 (tk)
+----------------------------------
+ * libclamav/mspack.c: fix write error
+
+Wed Jul 21 18:54:13 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: fix build problem (bb#2133)
+
+Mon Jul 19 18:48:08 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: add support for creating cdiffs with arbitrary
+ long lines (bb#2014)
+
+Fri Jul 16 11:11:27 CEST 2010 (tk)
+----------------------------------
+ * freshclam: remove empty temporary directories on EXIT_n (bb#2116)
+
+Mon Jul 12 12:27:44 CEST 2010 (tk)
+----------------------------------
+ * libclamunrar/unrar.c: fix error path memory leaks (bb#2100)
+ Thanks to Martin Olsen
+
+Tue Jul 6 19:19:39 CEST 2010 (tk)
+----------------------------------
+ * clamd: add ExtendedDetectionInfo (bb#1228, #1626)
+
+Mon Jul 5 17:30:11 CEST 2010 (tk)
+----------------------------------
+ * libclamav: fix some error messages (bb#2083)
+
+Thu Jul 1 18:22:58 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher.c: fix counting of logical subsigs matched at boundaries (bb#2053)
+
+Tue Jun 29 13:51:06 CEST 2010 (tk)
+----------------------------------
+ * freshclam: fix memleak when testing safebrowsing.cvd (bb#2091)
+
+Tue Jun 29 12:08:42 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/mpool.c: reduce memory waste due to alignment (~14% improvement).
+
+Tue Jun 29 12:05:59 EEST 2010 (edwin)
+-------------------------------------
+ * clamdtop/clamdtop.c: fix display of sizes (off by 1000/1024).
+
+Mon Jun 28 18:42:48 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: drop compatibility limit
+
+Thu Jun 24 20:04:02 CEST 2010 (tk)
+----------------------------------
+ * libclamav: reduce memory usage for MD5 sigs (bb#2057)
+
+Wed Jun 23 09:39:14 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher.c: fix possible use of uninit value (bb#2084)
+
+Mon Jun 21 20:07:09 CEST 2010 (tk)
+----------------------------------
+ * libclamav: report correct offset via cli_ac_result (bb#2076)
+
+Fri Jun 18 15:41:08 CEST 2010 (tk)
+----------------------------------
+ * libclamav: minimize header parsing (bb#2065)
+
+Thu Jun 17 17:11:04 EEST 2010 (edwin)
+-------------------------------------
+* libclamav/c++/llvm: apply PowerPC workaround from LLVM PR5201.
+
+Wed Jun 16 16:52:46 CEST 2010 (tk)
+----------------------------------
+ * libclamav/special.c: avoid false MS02-002 detections for corrupted files (bb#2074)
+
+Tue Jun 15 18:07:00 CEST 2010 (tk)
+----------------------------------
+ * libclamav: avoid scanpe() warnings for corrupted files (bb#2049)
+
+Tue Jun 15 16:13:07 CEST 2010 (tk)
+----------------------------------
+ * clamd/clamd.c: be more verbose when daemonize() fails (bb#2062)
+
+Thu Jun 10 19:58:01 CEST 2010 (acab)
+------------------------------------
+ * libclamav/pe*: fix virusnames being hijacked by idb sigs (bb#2064)
+
+Thu Jun 10 16:06:56 CEST 2010 (tk)
+----------------------------------
+ * libclamav/str.c: fix cli_isnumber() (bb#2070)
+
+Thu Jun 10 12:15:17 CEST 2010 (tk)
+----------------------------------
+ * sigtool: print match count and offsets in --test-sigs mode (bb#2054)
+ IMPORTANT NOTE: --test-sigs now only works against the final target file
+ (after all processing, normalization, etc. for which the tested
+ signature was directly created)
+
+Wed Jun 9 13:38:11 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/{matcher-bm.c, sha256.c}: improve DB load time (bb #1860).
+
+Tue Jun 8 16:32:47 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: add --datadir (bb#2063)
+
+Tue Jun 8 12:47:25 CEST 2010 (tk)
+----------------------------------
+ * shared/cdiff.c: fix handling of massive XCHGs (bb#2017)
+
+Fri Jun 4 18:04:37 CEST 2010 (tk)
+----------------------------------
+ * libclamav/cvd.c: load daily.ign[2] files from CVDs (bb#2061)
+
+Wed Jun 2 10:08:00 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/others_common.c: fix typo (bb #2060).
+
+Mon May 31 16:57:31 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/{bytecode.c, others_common.c}: don't attempt to allocate 0 bytes (bb #2042).
+
+Mon May 31 13:18:45 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/readdb.c: fix memory leak in .idb handling
+
+Fri May 28 18:45:46 EEST 2010 (edwin)
+-------------------------------------
+ * clamd, libclamav: fix some error path leaks (bb #1990)
+
+Fri May 28 13:24:21 CEST 2010 (tk)
+----------------------------------
+ * freshclam/manager.c: randomize getaddrinfo()'s results (bb#2021)
+
+Tue May 25 14:36:41 CEST 2010 (tk)
+----------------------------------
+ * clamscan: add support for loading multiple dbs at command line with
+ -d (bb#2033)
+
+Wed May 19 12:21:02 CEST 2010 (acab)
+------------------------------------
+ * libclamav/7z/Archive/7z/7zIn.c: fix possible(?) null dereference reported
+ by clang (bb#1909)
+
+Wed May 19 12:19:27 CEST 2010 (acab)
+------------------------------------
+ * libclamav/pe_icons.c: properly round down when scaling (bb#2031)
+
+Wed May 19 13:15:06 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/pdf.c: bb #2016
+
+Wed May 19 00:03:19 CEST 2010 (tk)
+----------------------------------
+ * libclamav/readdb.c: properly reject .info files passed on cmdline (bb#2025)
+
+Tue May 18 23:35:43 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher-bm.c: fix offset check (bb#2032)
+
+Tue May 18 20:20:15 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/fmap.c: fix bug introduced in clamav-0.96-51-g3e3b587.
+
+Mon May 17 19:03:51 CEST 2010 (acab)
+------------------------------------
+ * libclamav/pe.c: properly resume stringtable loop (bb#2027)
+ Note: 0.96 is NOT affected as the min VI sig has got FL=53
+ 3rd parties must avoid VI sigs with FL=51
+
+Sat May 15 22:31:46 CEST 2010 (acab)
+------------------------------------
+ * fmap: check for anon maps are avail (bb#1940)
+
+Fri May 14 17:16:19 EEST 2010 (edwin)
+-------------------------------------
+ * unit_tests: add bytecode.cvd load test
+
+Fri May 14 11:28:52 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode.c: handle global gep parameter correctly (bb #1955)
+
+Thu May 13 23:40:11 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/llvm: Update to LLVM 2.7 release.
+
+Thu May 13 23:35:55 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode*, unit_tests: add new unit tests for bytecode API and fix bugs.
+
+Thu May 13 12:41:24 EEST 2010 (edwin)
+------------------------------------
+ * libclamav/c++: Relax bounds checks. Was rejecting correct code.
+
+Wed May 12 19:10:39 CEST 2010 (acab)
+------------------------------------
+ * docs/man: add clamav.milter.conf.5
+
+Wed May 12 14:21:23 CEST 2010 (tk)
+----------------------------------
+ * freshclam: fix handling of temporary files
+
+Tue May 11 22:44:06 CEST 2010 (tk)
+----------------------------------
+ * freshclam: add new option TestDatabases
+
+Tue May 11 21:33:49 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/filtering.c: fix handling of alternates and negated alternates (bb #2004)
+
+Tue May 11 15:31:40 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/readdb.c: read the entire .cbc files, fix loading of bytecode.cvd
+
+Tue May 11 11:36:21 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/pdf.c: New PDF parser with better javascript support (bb #1596).
+
+Mon May 10 17:00:16 CEST 2010 (tk)
+----------------------------------
+ * tools: make sure the libclamav version is high enough (bb#2013)
+
+Mon May 10 14:51:24 CEST 2010 (tk)
+----------------------------------
+ * sigtool/sigtool.c: fix error msg (bb#2002)
+
+Mon May 10 14:11:51 CEST 2010 (acab)
+------------------------------------
+ * win32: simulate gai_strerror
+
+Mon May 10 03:43:43 CEST 2010 (acab)
+------------------------------------
+ * libclamav: Use mpool in win32 (well, sort of) as the mighty crt allocator
+ chokes when loading about one milion signatures
+
+Sat May 8 00:18:13 CEST 2010 (acab)
+------------------------------------
+ * libclamav/fmap.c: make oof need stfu (bb#2000)
+
+Fri May 7 21:12:35 CEST 2010 (tk)
+----------------------------------
+ * clamdscan: respect ExcludePath in --fdpass mode (bb#1923)
+
+Fri Apr 9 17:01:07 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/llvm/test: Fix make check failure on x86-32 (bb #1942)
+
+Fri May 7 15:45:55 CEST 2010 (tk)
+----------------------------------
+ * libclamav/readdb.c: add checks to enforce lsig compatibility with 0.95.x (bb#2008)
+
+Fri May 7 16:30:50 EEST 2010 (edwin)
+-------------------------------------
+ * clamscan/manager.c: don't closedir(NULL) (bb #2010)
+
+Fri May 7 13:06:48 EEST 2010 (edwin)
+-------------------------------------
+ * configure: darwin* IS thread safe (bb #1534)
+
+Fri May 7 10:48:48 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/configure: add check that correct libstdc++ version is used (bb #1971)
+
+Fri May 7 10:07:24 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/cache.c: support building without pthreads (bb #1897).
+
+Fri May 7 09:56:57 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode*: add match_offsets support.
+
+Wed May 5 21:28:04 CEST 2010 (tk)
+----------------------------------
+ * shared/output.c: workaround FreeBSD's file locking issue (bb#1918)
+
+Wed May 5 14:12:46 CEST 2010 (tk)
+----------------------------------
+ * freshclam/notify.c: fix warning message (bb#1972)
+ Thanks to Gianluigi Tiesi
+
+Tue May 4 21:58:19 CEST 2010 (tk)
+----------------------------------
+ * libclamav: make lsigs working in cli_scanscript() (bb#1998)
+
+Tue May 4 19:37:58 CEST 2010 (acab)
+------------------------------------
+ * libclamav/fmap.c: nicely handle EINTR
+
+Tue May 4 18:47:31 CEST 2010 (acab)
+------------------------------------
+ * libclamav: no ERROR on void mapping (bb#1968)
+
+Tue May 4 16:47:57 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher-ac.c: fix counting of subsig matches (bb#2001)
+
+Sun May 2 19:13:29 CEST 2010 (acab)
+------------------------------------
+ * clamav-milter: add VirusAction (bb#1867)
+
+Sat May 1 02:05:17 CEST 2010 (acab)
+------------------------------------
+ * m4: On solaris 8 bzlib.h uses FILE without including stdio.h (bb#1985)
+
+Fri Apr 30 12:45:47 CEST 2010 (tk)
+----------------------------------
+ * clamconf: warn about dbdir mismatch in clamd and freshclam (bb#1978)
+
+Thu Apr 29 09:49:10 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/configure: Mac OS X doesn't have -pthread (bb #1995)
+
+Thu Apr 29 09:45:29 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/llvm/include/llvm/ADT/SmallVector.h: Fix crash with -ftree-vectorize/-O3(bb #1984).
+
+Tue Apr 27 16:34:38 CEST 2010 (tk)
+----------------------------------
+ * libclamav: fix some limit settings (bb#1973)
+
+Mon Apr 26 18:18:47 EEST 2010 (edwin)
+-------------------------------------
+ * bytecode: min/max functionality level support.
+
+Mon Apr 26 16:12:50 CEST 2010 (tk)
+----------------------------------
+ * libclamav/others.c: bump f-level
+
+Mon Apr 26 16:06:56 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher-ac.c: fix handling of VI/MACRO special offsets (bb#1957)
+
+Fri Apr 23 21:38:19 EEST 2010 (edwin)
+-------------------------------------
+ * configure: fix Apple-style universal build (bb #1988).
+
+Thu Apr 22 22:34:52 CEST 2010 (acab)
+------------------------------------
+ * libclamav/fmap.c: downgrade warning when the kernel doesn't want a map back
+
+Thu Apr 22 18:03:30 CEST 2010 (tk)
+----------------------------------
+ * libclamav: avoid loading duplicate databases (bb#1962)
+
+Mon Apr 19 17:12:06 EEST 2010 (edwin)
+-------------------------------------
+ * clamconf: print information about platform and build.
+
+Thu Apr 15 20:04:16 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/configure: disable gcc 3.4.6 by default, you can still use it with --enable-llvm (bb #1935).
+
+Thu Apr 15 16:27:00 CEST 2010 (tk)
+----------------------------------
+ * docs/man/freshclam.conf.5.in: document LogFileMaxSize (bb#1960)
+
+Wed Apr 14 21:44:18 CEST 2010 (tk)
+----------------------------------
+ * freshclam/manager.c: add support for X-HostID to allow custom UserAgent
+ strings in --submit-stats (bb#1905)
+ Thanks to Andreas Schulze
+
+Wed Apr 14 21:14:28 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/bytecode.c: fix cli_unlink warnings (bb #1956).
+
+Tue Apr 13 16:17:35 EEST 2010 (edwin)
+-------------------------------------
+ * clambc, clamd,clamdtop,libclamav,unit_tests: fix compiler warnings (bb #1872,
+ bb #1934, bb #1935)
+
+Tue Apr 13 16:13:05 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++: allow building with gcc 3.4.6 (bb #1934).
+
+Tue Apr 13 13:12:47 EEST 2010 (edwin)
+-------------------------------------
+ * unit_tests/check_common.sh: fix make check on AIX (bb #1917).
+
+Mon Apr 12 18:02:06 CEST 2010 (tk)
+----------------------------------
+ * freshclam/manager.c: better handle daylight saving time changes (bb#1920)
+
+Sat Apr 10 16:36:11 CEST 2010 (acab)
+------------------------------------
+ * libclamav/pe.c: more relaxed vinfo parser - try to mimic winxp's
+
+Wed Apr 7 16:27:42 CEST 2010 (tk)
+----------------------------------
+ * sigtool: handle .idb files
+
+Wed Apr 7 12:42:19 CEST 2010 (tk)
+----------------------------------
+ * libclamav/matcher.c: return proper virus name in icon detector (bb#1933)
+
+Mon Apr 5 22:41:40 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/bytecode2llvm.cpp: Fix load of multiple unsigned bytecodes (bb #1924)
+
+Sat Apr 3 21:05:35 EEST 2010 (edwin)
+-------------------------------------
+ * contrib/split-tarball.sh: update to work with 0.96
+
+Sat Apr 3 20:30:39 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/Makefile.{am,in}: Fix unit test failure with non-English locale (bb #1922)
+
+Fri Apr 2 16:22:26 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/llvm/lib/Support/Allocator.cpp: Fix SpecificBumpPtrAllocator
+ destructor iteration. Thanks to Nicolas Capens.
+
+Fri Apr 2 16:19:26 EEST 2010 (edwin)
+-------------------------------------
+ * libclamav/c++/llvm/lib/ExecutionEngine/JIT/JIT.cpp:
+ Fix the previous PowerPC workaround to not crash when not using the JIT.
+
+Fri Apr 2 13:09:54 EEST 2010 (edwin)
+------------------------------------
+ * libclamav/c++/{bytecode2llvm.cpp,llvm/lib/ExecutionEngine/JIT/JIT.cpp,
+ llvm/lib/Target/PowerPC/PPCISelLowering.cpp}: Workaround LLVM JIT PowerPC relocation bug (bb #1921).
+ Based on Gary Benson's workaround for OpenJDK Shark / IcedTea.
+
+Fri Apr 2 13:07:50 EEST 2010 (edwin)
+-------------------------------------
+ * unit_tests: Fix matchwithread.cbc
+
Wed May 19 14:54:41 CEST 2010 (tk)
----------------------------------
* V 0.96.1
diff --git a/NEWS b/NEWS
index 4bee821..2383c65 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,9 @@
-0.96.1
+0.96.2
------
-This is a bugfix release, please refer to the ChangeLog for the complete
-list of changes.
+ClamAV 0.96.2 brings a new PDF parser, performance and memory improvements,
+and a number of bugfixes and minor enhancements. This upgrade is recommended
+for all users.
--
The ClamAV team (http://www.clamav.net/team)
diff --git a/README b/README
index 2659fc3..7677151 100644
--- a/README
+++ b/README
@@ -2,6 +2,15 @@ Note: This README/NEWS file refers to the source tarball. Some things described
here may not be available in binary packages.
--
+0.96.2
+------
+
+ClamAV 0.96.2 brings a new PDF parser, performance and memory improvements,
+and a number of bugfixes and minor enhancements. This upgrade is recommended
+for all users.
+
+--
+The ClamAV team (http://www.clamav.net/team)
0.96.1
------
@@ -1538,7 +1547,7 @@ Noteworthy changes in this version:
-) documentation:
+ new Spanish documentation on ClamAV and Sendmail integration by
Erick Ivaan Lopez Carreon
- + included clamdoc.pdf Turkish translation by yavuz kaya and Ýbrahim erken
+ + included clamdoc.pdf Turkish translation by yavuz kaya and �brahim erken
+ included clamav-mirror-howto.pdf by Luca Gibelli
+ included clamd+daemontools HOWTO by Jesse D. Guardiani
+ included signatures.pdf
diff --git a/clamav-config.h.in b/clamav-config.h.in
index b78c02f..2946ae2 100644
--- a/clamav-config.h.in
+++ b/clamav-config.h.in
@@ -21,7 +21,7 @@
/* enable clamuko */
#undef CLAMUKO
-/* disable loading of unsigned bytecode */
+/* enable loading of unsigned bytecode */
#undef CL_BCUNSIGNED
/* enable debugging */
diff --git a/clamav-milter/clamav-milter.c b/clamav-milter/clamav-milter.c
index 4bc54e7..7f347a7 100644
--- a/clamav-milter/clamav-milter.c
+++ b/clamav-milter/clamav-milter.c
@@ -39,6 +39,7 @@
#include "shared/output.h"
#include "shared/optparser.h"
#include "shared/misc.h"
+#include "libclamav/default.h"
#include "connpool.h"
#include "netcode.h"
@@ -351,6 +352,10 @@ int main(int argc, char **argv) {
}
maxfilesize = optget(opts, "MaxFileSize")->numarg;
+ if(!maxfilesize) {
+ logg("^Invalid MaxFileSize, using default (%d)\n", CLI_DEFAULT_MAXFILESIZE);
+ maxfilesize = CLI_DEFAULT_MAXFILESIZE;
+ }
readtimeout = optget(opts, "ReadTimeout")->numarg;
cpool_init(opts);
diff --git a/clambc/bcrun.c b/clambc/bcrun.c
index abce4c8..c9b9735 100644
--- a/clambc/bcrun.c
+++ b/clambc/bcrun.c
@@ -295,7 +295,7 @@ int main(int argc, char *argv[])
if (optget(opts, "force-interpreter")->enabled) {
bcs.engine = NULL;
} else {
- rc = cli_bytecode_init(&bcs, BYTECODE_ENGINE_MASK);
+ rc = cli_bytecode_init(&bcs);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Unable to init bytecode engine: %s\n", cl_strerror(rc));
optfree(opts);
@@ -339,7 +339,7 @@ int main(int argc, char *argv[])
optfree(opts);
exit(4);
}
- rc = cli_bytecode_prepare(&bcs, BYTECODE_ENGINE_MASK);
+ rc = cli_bytecode_prepare2(engine, &bcs, BYTECODE_ENGINE_MASK);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Unable to prepare bytecode: %s\n", cl_strerror(rc));
optfree(opts);
diff --git a/clamconf/clamconf.c b/clamconf/clamconf.c
index fa6c0af..9fca9ca 100644
--- a/clamconf/clamconf.c
+++ b/clamconf/clamconf.c
@@ -39,6 +39,7 @@
#include "libclamav/clamav.h"
#include "libclamav/others.h"
#include "libclamav/bytecode.h"
+#include "libclamav/bytecode_detect.h"
#include "target.h"
#ifndef _WIN32
@@ -211,17 +212,12 @@ static void help(void)
return;
}
-static void print_platform(void)
+static void print_platform(struct cli_environment *env)
{
-#ifdef HAVE_UNAME_SYSCALL
- struct utsname name;
-#endif
printf("\nPlatform information\n--------------------\n");
-#ifdef HAVE_UNAME_SYSCALL
- uname(&name);
- printf("uname: %s %s %s %s\n", name.sysname, name.release, name.version,
- name.machine);
-#endif
+ printf("uname: %s %s %s %s\n",
+ env->sysname, env->release, env->version, env->machine);
+
printf("OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE"\n");
#ifdef C_LINUX
@@ -232,15 +228,6 @@ static void print_platform(void)
perror("failed to determine");
}
}
-#elif defined(_WIN32)
- {
- /* get just some basic information, since getting the full version
- * is too complicated */
- uint32_t dwVersion = GetVersion();
- printf("Full OS version: %d.%d (%d)\n",
- dwVersion&0xff, (dwVersion>>8)&0xff,
- dwVersion<0x80000000 ? dwVersion>>16 : 0);
- }
#else
/* e.g. Solaris */
if (!access("/etc/release", R_OK)) {
@@ -259,31 +246,64 @@ static void print_platform(void)
printf("zlib version: %s (%s)\n",
ZLIB_VERSION, zlibVersion());
#endif
+ if (env->triple[0])
+ printf("Triple: %s\n", env->triple);
+ if (env->cpu[0])
+ printf("CPU: %s, %s\n", env->cpu, env->big_endian ? "Big-endian" : "Little-endian");
+ printf("platform id: 0x%08x%08x%08x\n",
+ env->platform_id_a,
+ env->platform_id_b,
+ env->platform_id_c);
}
-static void print_build(void)
+static void print_build(struct cli_environment *env)
{
+ const char *name;
+ const char *version = NULL;
printf("\nBuild information\n-----------------\n");
/* Try to print information about some commonly used compilers */
#ifdef __GNUC__
- printf("GNU C: %s (%u.%u.%u)\n", __VERSION__, __GNUC__, __GNUC_MINOR__,
- __GNUC_PATCHLEVEL__);
-#endif
-#ifdef __INTEL_COMPILER
- printf("Intel Compiler %u\n", __INTEL_COMPILER);
-#endif
-#ifdef _MSC_VER
- printf("Microsoft Visual C++ %u\n", _MSC_VER);
-#endif
-#ifdef __SUNPRO_C
- printf("Sun studio %u\n", __SUNPRO_C);
+ version = __VERSION__;
#endif
+ switch (env->compiler) {
+ case compiler_gnuc:
+ name = "GNU C";
+ break;
+ case compiler_clang:
+ name = "Clang";
+ break;
+ case compiler_llvm:
+ name = "LLVM-GCC";
+ break;
+ case compiler_intel:
+ name = "Intel Compiler";
+ break;
+ case compiler_msc:
+ name = "Microsoft Visual C++";
+ break;
+ case compiler_sun:
+ name = "Sun studio";
+ break;
+ default:
+ name = NULL;
+ }
+ if (name)
+ printf("%s: %s%s(%u.%u.%u)\n", name,
+ version ? version : "",
+ version ? " " : "",
+ env->c_version >> 16,
+ (env->c_version >> 8)&0xff,
+ (env->c_version)&0xff);
cli_printcxxver();
#if defined(BUILD_CPPFLAGS) && defined(BUILD_CFLAGS) && defined(BUILD_CXXFLAGS) && defined(BUILD_LDFLAGS) && defined(BUILD_CONFIGURE_FLAGS)
printf("CPPFLAGS: %s\nCFLAGS: %s\nCXXFLAGS: %s\nLDFLAGS: %s\nConfigure: %s\n",
BUILD_CPPFLAGS, BUILD_CFLAGS, BUILD_CXXFLAGS, BUILD_LDFLAGS,
BUILD_CONFIGURE_FLAGS);
#endif
+ printf("sizeof(void*) = %d\n", env->sizeof_ptr);
+ printf("Engine flevel: %d, dconf: %d\n",
+ env->functionality_level,
+ env->dconf_level);
}
int main(int argc, char **argv)
@@ -295,6 +315,7 @@ int main(int argc, char **argv)
unsigned int i, j;
struct cl_cvd *cvd;
unsigned int flevel;
+ struct cli_environment env;
opts = optparse(NULL, argc, argv, 1, OPT_CLAMCONF, 0, NULL);
@@ -415,7 +436,8 @@ int main(int argc, char **argv)
}
}
}
- print_platform();
- print_build();
+ cli_detect_environment(&env);
+ print_platform(&env);
+ print_build(&env);
return 0;
}
diff --git a/clamd/clamd.c b/clamd/clamd.c
index 7e327dd..bf199ec 100644
--- a/clamd/clamd.c
+++ b/clamd/clamd.c
@@ -42,6 +42,7 @@
#include <grp.h>
#endif
#include <signal.h>
+#include <errno.h>
#if defined(USE_SYSLOG) && !defined(C_AIX)
#include <syslog.h>
@@ -431,6 +432,18 @@ int main(int argc, char **argv)
break;
}
}
+ if((opt = optget(opts,"BytecodeMode"))->enabled) {
+ enum bytecode_mode mode;
+ if (!strcmp(opt->strarg, "ForceJIT"))
+ mode = CL_BYTECODE_MODE_JIT;
+ else if(!strcmp(opt->strarg, "ForceInterpreter"))
+ mode = CL_BYTECODE_MODE_INTERPRETER;
+ else if(!strcmp(opt->strarg, "Test"))
+ mode = CL_BYTECODE_MODE_TEST;
+ else
+ mode = CL_BYTECODE_MODE_AUTO;
+ cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode);
+ }
if((opt = optget(opts,"BytecodeTimeout"))->enabled) {
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg);
}
@@ -528,7 +541,7 @@ int main(int argc, char **argv)
gengine = engine;
atexit(free_engine);
if(daemonize() == -1) {
- logg("!daemonize() failed\n");
+ logg("!daemonize() failed: %s\n", strerror(errno));
ret = 1;
break;
}
diff --git a/clamd/clamuko.c b/clamd/clamuko.c
index 1ab875e..b560856 100644
--- a/clamd/clamuko.c
+++ b/clamd/clamuko.c
@@ -33,6 +33,7 @@
#include <string.h>
#include "libclamav/clamav.h"
+#include "libclamav/scanners.h"
#include "shared/optparser.h"
#include "shared/output.h"
@@ -73,8 +74,10 @@ static void *clamukolegacyth(void *arg)
unsigned long mask = 0;
const struct optstruct *pt;
short int scan;
- int sizelimit = 0;
+ int sizelimit = 0, extinfo;
struct stat sb;
+ char virhash[33];
+ unsigned int virsize;
clamuko_scanning = 0;
@@ -166,6 +169,8 @@ static void *clamukolegacyth(void *arg)
else
logg("Clamuko: File size limit disabled.\n");
+ extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;
+
while(1) {
if(dazukoGetAccess(&acc) == 0) {
@@ -180,8 +185,11 @@ static void *clamukolegacyth(void *arg)
}
}
- if(scan && cl_scanfile(acc->filename, &virname, NULL, tharg->engine, tharg->options) == CL_VIRUS) {
- logg("Clamuko: %s: %s FOUND\n", acc->filename, virname);
+ if(scan && cli_scanfile_stats(acc->filename, &virname, virhash, &virsize, NULL, tharg->engine, tharg->options) == CL_VIRUS) {
+ if(extinfo && virsize)
+ logg("Clamuko: %s: %s(%s:%u) FOUND\n", acc->filename, virname, virhash, virsize);
+ else
+ logg("Clamuko: %s: %s FOUND\n", acc->filename, virname);
virusaction(acc->filename, virname, tharg->opts);
acc->deny = 1;
} else
diff --git a/clamd/clamukofs.c b/clamd/clamukofs.c
index cb6202b..e4a1586 100644
--- a/clamd/clamukofs.c
+++ b/clamd/clamukofs.c
@@ -32,6 +32,7 @@
#include <pthread.h>
#include "libclamav/clamav.h"
+#include "libclamav/scanners.h"
#include "shared/optparser.h"
#include "shared/output.h"
@@ -82,14 +83,14 @@ static void *clamuko_scanth(void *arg)
{
struct thrarg *tharg = (struct thrarg *) arg;
sigset_t sigset;
- unsigned int sizelimit = 0;
+ unsigned int sizelimit = 0, virsize;
struct stat sb;
dazukofs_handle_t scan_hndl;
struct dazukofs_access acc;
const char *groupname = "ClamAV";
- int skip_scan = 0;
+ int skip_scan = 0, extinfo;
const char *virname;
- char filename[4096];
+ char filename[4096], virhash[33];
/* ignore all signals */
sigfillset(&sigset);
@@ -130,6 +131,8 @@ static void *clamuko_scanth(void *arg)
else
logg("Clamuko: File size limit disabled.\n");
+ extinfo = optget(tharg->opts, "ExtendedDetectionInfo")->enabled;
+
while(1) {
if(dazukofs_get_access(scan_hndl, &acc)) {
if(!shutdown_hndl)
@@ -152,10 +155,13 @@ static void *clamuko_scanth(void *arg)
acc.deny = 0;
/* reset skip flag */
skip_scan = 0;
- } else if(cl_scandesc(acc.fd, &virname, NULL, tharg->engine,
+ } else if(cli_scandesc_stats(acc.fd, &virname, virhash, &virsize, NULL, tharg->engine,
tharg->options) == CL_VIRUS) {
dazukofs_get_filename(&acc, filename, sizeof(filename));
- logg("Clamuko: %s: %s FOUND\n", filename, virname);
+ if(extinfo && virsize)
+ logg("Clamuko: %s: %s(%s:%u) FOUND\n", filename, virname, virhash, virsize);
+ else
+ logg("Clamuko: %s: %s FOUND\n", filename, virname);
/* we can not perform any special action because it will
* trigger DazukoFS recursively */
acc.deny = 1;
diff --git a/clamd/scanner.c b/clamd/scanner.c
index dc5f68e..a15e320 100644
--- a/clamd/scanner.c
+++ b/clamd/scanner.c
@@ -51,6 +51,7 @@
#include "libclamav/clamav.h"
#include "libclamav/others.h"
+#include "libclamav/scanners.h"
#include "shared/optparser.h"
#include "shared/output.h"
@@ -77,6 +78,8 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
const char *virname;
int ret;
int type = scandata->type;
+ char virhash[33];
+ unsigned int virsize;
/* detect disconnected socket,
* this should NOT detect half-shutdown sockets (SHUT_WR) */
@@ -156,6 +159,7 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
if(cl_engine_addref(scandata->engine)) {
logg("!cl_engine_addref() failed\n");
free(filename);
+ free(client_conn);
return CL_EMEM;
} else {
client_conn->engine = scandata->engine;
@@ -164,7 +168,9 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
pthread_mutex_unlock(&reload_mutex);
if(!thrmgr_group_dispatch(scandata->thr_pool, scandata->group, client_conn, 1)) {
logg("!thread dispatch failed\n");
+ cl_engine_free(scandata->engine);
free(filename);
+ free(client_conn);
return CL_EMEM;
}
}
@@ -190,7 +196,7 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
thrmgr_setactivetask(filename,
type == TYPE_MULTISCAN ? "MULTISCANFILE" : NULL);
- ret = cl_scanfile(filename, &virname, &scandata->scanned, scandata->engine, scandata->options);
+ ret = cli_scanfile_stats(filename, &virname, virhash, &virsize, &scandata->scanned, scandata->engine, scandata->options);
thrmgr_setactivetask(NULL, NULL);
if (thrmgr_group_need_terminate(scandata->conn->group)) {
@@ -201,11 +207,16 @@ int scan_callback(struct stat *sb, char *filename, const char *msg, enum cli_ftw
if (ret == CL_VIRUS) {
scandata->infected++;
- if (conn_reply(scandata->conn, filename, virname, "FOUND") == -1) {
+ if(!optget(scandata->opts, "ExtendedDetectionInfo")->enabled)
+ virsize = 0;
+ if (conn_reply_virus(scandata->conn, filename, virname, virhash, virsize) == -1) {
free(filename);
return CL_ETIMEOUT;
}
- logg("~%s: %s FOUND\n", filename, virname);
+ if(virsize)
+ logg("~%s: %s(%s:%u) FOUND\n", filename, virname, virhash, virsize);
+ else
+ logg("~%s: %s FOUND\n", filename, virname);
virusaction(filename, virname, scandata->opts);
} else if (ret != CL_CLEAN) {
scandata->errors++;
@@ -268,7 +279,8 @@ int scanfd(const int fd, const client_conn_t *conn, unsigned long int *scanned,
int ret;
const char *virname;
struct stat statbuf;
- char fdstr[32];
+ char fdstr[32], virhash[33];
+ unsigned int virsize;
if (stream)
strncpy(fdstr, "stream", sizeof(fdstr));
@@ -282,7 +294,7 @@ int scanfd(const int fd, const client_conn_t *conn, unsigned long int *scanned,
}
thrmgr_setactivetask(fdstr, NULL);
- ret = cl_scandesc(fd, &virname, scanned, engine, options);
+ ret = cli_scandesc_stats(fd, &virname, virhash, &virsize, scanned, engine, options);
thrmgr_setactivetask(NULL, NULL);
if (thrmgr_group_need_terminate(conn->group)) {
@@ -291,9 +303,14 @@ int scanfd(const int fd, const client_conn_t *conn, unsigned long int *scanned,
}
if(ret == CL_VIRUS) {
- if (conn_reply(conn, fdstr, virname, "FOUND") == -1)
+ if(!optget(opts, "ExtendedDetectionInfo")->enabled)
+ virsize = 0;
+ if (conn_reply_virus(conn, fdstr, virname, virhash, virsize) == -1)
ret = CL_ETIMEOUT;
- logg("%s: %s FOUND\n", fdstr, virname);
+ if(virsize)
+ logg("%s: %s(%s:%u) FOUND\n", fdstr, virname, virhash, virsize);
+ else
+ logg("%s: %s FOUND\n", fdstr, virname);
virusaction(fdstr, virname, opts);
} else if(ret != CL_CLEAN) {
if (conn_reply(conn, fdstr, cl_strerror(ret), "ERROR") == -1)
@@ -312,12 +329,12 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
{
int ret, sockfd, acceptd;
int tmpd, bread, retval, firsttimeout, timeout, btread;
- unsigned int port = 0, portscan, min_port, max_port;
+ unsigned int port = 0, portscan, min_port, max_port, virsize;
unsigned long int quota = 0, maxsize = 0;
short bound = 0;
const char *virname;
char buff[FILEBUFF];
- char peer_addr[32];
+ char peer_addr[32], virhash[33];
struct sockaddr_in server;
struct sockaddr_in peer;
socklen_t addrlen;
@@ -445,7 +462,7 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
if(retval == 1) {
lseek(tmpd, 0, SEEK_SET);
thrmgr_setactivetask(peer_addr, NULL);
- ret = cl_scandesc(tmpd, &virname, scanned, engine, options);
+ ret = cli_scandesc_stats(tmpd, &virname, virhash, &virsize, scanned, engine, options);
thrmgr_setactivetask(NULL, NULL);
} else {
ret = -1;
@@ -459,8 +476,13 @@ int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *en
closesocket(sockfd);
if(ret == CL_VIRUS) {
- mdprintf(odesc, "stream: %s FOUND%c", virname, term);
- logg("stream(%s@%u): %s FOUND\n", peer_addr, port, virname);
+ if(optget(opts, "ExtendedDetectionInfo")->enabled && virsize) {
+ mdprintf(odesc, "stream: %s(%s:%u) FOUND%c", virname, virhash, virsize, term);
+ logg("stream(%s@%u): %s(%s:%u) FOUND\n", peer_addr, port, virname, virhash, virsize);
+ } else {
+ mdprintf(odesc, "stream: %s FOUND%c", virname, term);
+ logg("stream(%s@%u): %s FOUND\n", peer_addr, port, virname);
+ }
virusaction("stream", virname, opts);
} else if(ret != CL_CLEAN) {
if(retval == 1) {
diff --git a/clamd/session.c b/clamd/session.c
index 5aa7ed9..772290c 100644
--- a/clamd/session.c
+++ b/clamd/session.c
@@ -154,6 +154,22 @@ int conn_reply(const client_conn_t *conn, const char *path,
return mdprintf(conn->sd, "%s %s%c", msg, status, conn->term);
}
+int conn_reply_virus(const client_conn_t *conn, const char *file,
+ const char *virname, const char *virhash, unsigned int virsize)
+{
+ if (conn->id) {
+ if (virsize)
+ return mdprintf(conn->sd, "%u: %s: %s(%s:%u) FOUND%c", conn->id, file,
+ virname, virhash, virsize, conn->term);
+ return mdprintf(conn->sd, "%u: %s: %s FOUND%c", conn->id, file, virname,
+ conn->term);
+ }
+ if (virsize)
+ return mdprintf(conn->sd, "%s: %s(%s:%u) FOUND%c", file, virname, virhash,
+ virsize, conn->term);
+ return mdprintf(conn->sd, "%s: %s FOUND%c", file, virname, conn->term);
+}
+
int conn_reply_error(const client_conn_t *conn, const char *msg)
{
return conn_reply(conn, NULL, msg, "ERROR");
@@ -222,6 +238,16 @@ int command(client_conn_t *conn, int *virus)
break;
case COMMAND_MULTISCAN: {
int multiscan, max, alive;
+ struct stat sb;
+
+ /* use MULTISCAN only for directories (bb #1869) */
+ if (stat(conn->filename, &sb) == 0 &&
+ !S_ISDIR(sb.st_mode)) {
+ thrmgr_setactivetask(NULL, "CONTSCAN");
+ type = TYPE_CONTSCAN;
+ break;
+ }
+
pthread_mutex_lock(&conn->thrpool->pool_mutex);
multiscan = conn->thrpool->thr_multiscan;
max = conn->thrpool->thr_max;
diff --git a/clamd/session.h b/clamd/session.h
index 90192b8..b34f516 100644
--- a/clamd/session.h
+++ b/clamd/session.h
@@ -92,6 +92,7 @@ int execute_or_dispatch_command(client_conn_t *conn, enum commands command, cons
int conn_reply(const client_conn_t *conn, const char *path, const char *msg, const char *status);
int conn_reply_single(const client_conn_t *conn, const char *path, const char *status);
+int conn_reply_virus(const client_conn_t *conn, const char *file, const char *virname, const char *virhash, unsigned int virsize);
int conn_reply_error(const client_conn_t *conn, const char *msg);
int conn_reply_errno(const client_conn_t *conn, const char *path, const char *msg);
#endif
diff --git a/clamdscan/proto.c b/clamdscan/proto.c
index d8a819a..e863cd6 100644
--- a/clamdscan/proto.c
+++ b/clamdscan/proto.c
@@ -312,6 +312,13 @@ int dsresult(int sockd, int scantype, const char *filename, int *printok, int *e
if(!filename) logg("~%s\n", bol);
if(len > 7) {
char *colon = strrchr(bol, ':');
+ if(colon && colon[1] != ' ') {
+ char *colon2;
+ *colon = 0;
+ colon2 = strrchr(bol, ':');
+ *colon = ':';
+ colon = colon2;
+ }
if(!colon) {
logg("Failed to parse reply\n");
return -1;
diff --git a/clamdtop/clamdtop.c b/clamdtop/clamdtop.c
index 5ebdb2b..786e1fc 100644
--- a/clamdtop/clamdtop.c
+++ b/clamdtop/clamdtop.c
@@ -755,7 +755,7 @@ static void output_memstats(struct stats *stats)
if (stats->mem > 0)
snprintf(buf, sizeof(buf),"heap %4luM mmap %4luM unused %3luM",
- stats->lheapu/1024, stats->lmmapu/1024, stats->lreleasable/1024);
+ stats->lheapu/1000, stats->lmmapu/1000, stats->lreleasable/1000);
else
snprintf(buf, sizeof(buf), "heap N/A mmap N/A unused N/A");
mvwprintw(mem_window, 1, 1, "Mem: ");
@@ -764,14 +764,14 @@ static void output_memstats(struct stats *stats)
mvwprintw(mem_window, 2, 1, "Libc: ");
if (stats->mem > 0)
snprintf(buf, sizeof(buf),"used %4luM free %4luM total %4luM",
- stats->ltotalu/1024, stats->ltotalf/1024, (stats->ltotalu+stats->ltotalf)/1024);
+ stats->ltotalu/1000, stats->ltotalf/1000, (stats->ltotalu+stats->ltotalf)/1000);
else
snprintf(buf, sizeof(buf), "used N/A free N/A total N/A");
print_colored(mem_window, buf);
mvwprintw(mem_window, 3, 1, "Pool: ");
snprintf(buf, sizeof(buf), "count %4u used %4luM total %4luM",
- stats->pools_cnt, stats->lpoolu/1024, stats->lpoolt/1024);
+ stats->pools_cnt, stats->lpoolu/1000, stats->lpoolt/1000);
print_colored(mem_window, buf);
totalmem = stats->lheapu + stats->lmmapu + stats->lpoolt;
diff --git a/clamscan/manager.c b/clamscan/manager.c
index e0e42df..7c0b4aa 100644
--- a/clamscan/manager.c
+++ b/clamscan/manager.c
@@ -404,6 +404,18 @@ int scanmanager(const struct optstruct *opts)
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_SECURITY, CL_BYTECODE_TRUST_ALL);
if((opt = optget(opts,"bytecode-timeout"))->enabled)
cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg);
+ if((opt = optget(opts,"bytecode-mode"))->enabled) {
+ enum bytecode_mode mode;
+ if (!strcmp(opt->strarg, "ForceJIT"))
+ mode = CL_BYTECODE_MODE_JIT;
+ else if(!strcmp(opt->strarg, "ForceInterpreter"))
+ mode = CL_BYTECODE_MODE_INTERPRETER;
+ else if(!strcmp(opt->strarg, "Test"))
+ mode = CL_BYTECODE_MODE_TEST;
+ else
+ mode = CL_BYTECODE_MODE_AUTO;
+ cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode);
+ }
if((opt = optget(opts, "tempdir"))->enabled) {
if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
@@ -414,12 +426,14 @@ int scanmanager(const struct optstruct *opts)
}
if((opt = optget(opts, "database"))->active) {
- if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) {
- logg("!%s\n", cl_strerror(ret));
- cl_engine_free(engine);
- return 2;
+ while(opt) {
+ if((ret = cl_load(opt->strarg, engine, &info.sigs, dboptions))) {
+ logg("!%s\n", cl_strerror(ret));
+ cl_engine_free(engine);
+ return 2;
+ }
+ opt = opt->nextarg;
}
-
} else {
char *dbdir = freshdbdir();
diff --git a/configure b/configure
index 83beda1..e66e4e0 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.65 for ClamAV 0.96.1.
+# Generated by GNU Autoconf 2.65 for ClamAV 0.96.2.
#
# Report bugs to <http://bugs.clamav.net/>.
#
@@ -703,8 +703,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='ClamAV'
PACKAGE_TARNAME='clamav'
-PACKAGE_VERSION='0.96.1'
-PACKAGE_STRING='ClamAV 0.96.1'
+PACKAGE_VERSION='0.96.2'
+PACKAGE_STRING='ClamAV 0.96.2'
PACKAGE_BUGREPORT='http://bugs.clamav.net/'
PACKAGE_URL='http://www.clamav.net/'
@@ -1540,7 +1540,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures ClamAV 0.96.1 to adapt to many kinds of systems.
+\`configure' configures ClamAV 0.96.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1611,7 +1611,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of ClamAV 0.96.1:";;
+ short | recursive ) echo "Configuration of ClamAV 0.96.2:";;
esac
cat <<\_ACEOF
@@ -1768,7 +1768,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-ClamAV configure 0.96.1
+ClamAV configure 0.96.2
generated by GNU Autoconf 2.65
Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2232,7 +2232,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by ClamAV $as_me 0.96.1, which was
+It was created by ClamAV $as_me 0.96.2, which was
generated by GNU Autoconf 2.65. Invocation command line was
$ $0 $@
@@ -3346,7 +3346,7 @@ fi
# Define the identity of the package.
PACKAGE='clamav'
- VERSION='0.96.1'
+ VERSION='0.96.2'
# Some tools Automake needs.
@@ -3475,7 +3475,7 @@ AM_BACKSLASH='\'
$as_echo "#define PACKAGE PACKAGE_NAME" >>confdefs.h
-VERSION="0.96.1"
+VERSION="0.96.2"
cat >>confdefs.h <<_ACEOF
#define VERSION "$VERSION"
@@ -3483,7 +3483,7 @@ _ACEOF
LC_CURRENT=7
-LC_REVISION=3
+LC_REVISION=4
LC_AGE=1
LIBCLAMAV_VERSION="$LC_CURRENT":"$LC_REVISION":"$LC_AGE"
@@ -13985,7 +13985,7 @@ mmap((void *)0, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"; then :
ac_cv_c_mmap_anonymous='MAP_ANONYMOUS'
else
@@ -14014,7 +14014,8 @@ rm -f core conftest.err conftest.$ac_objext \
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_mmap_anonymous" >&5
@@ -15795,6 +15796,9 @@ else
#define BZ2_bzReadOpen bzReadOpen
#define BZ2_bzReadClose bzReadClose
#define BZ2_bzRead bzRead
+#define BZ2_bzDecompressInit bzDecompressInit
+#define BZ2_bzDecompress bzDecompress
+#define BZ2_bzDecompressEnd bzDecompressEnd
#endif
const unsigned char poc[] = {
@@ -20488,7 +20492,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by ClamAV $as_me 0.96.1, which was
+This file was extended by ClamAV $as_me 0.96.2, which was
generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -20555,7 +20559,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-ClamAV config.status 0.96.1
+ClamAV config.status 0.96.2
configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
@@ -23076,7 +23080,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by ClamAV $as_me 0.96.1, which was
+This file was extended by ClamAV $as_me 0.96.2, which was
generated by GNU Autoconf 2.65. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -23143,7 +23147,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-ClamAV config.status 0.96.1
+ClamAV config.status 0.96.2
configured by $0, generated by GNU Autoconf 2.65,
with options \\"\$ac_cs_config\\"
diff --git a/configure.in b/configure.in
index a396155..60e8112 100644
--- a/configure.in
+++ b/configure.in
@@ -20,7 +20,7 @@ dnl MA 02110-1301, USA.
AC_PREREQ([2.59])
dnl For a release change [devel] to the real version [0.xy]
dnl also change VERSION below
-AC_INIT([ClamAV], [0.96.1], [http://bugs.clamav.net/], [clamav], [http://www.clamav.net/])
+AC_INIT([ClamAV], [0.96.2], [http://bugs.clamav.net/], [clamav], [http://www.clamav.net/])
AH_BOTTOM([#include "platform.h"])
dnl put configure auxiliary into config
@@ -42,11 +42,11 @@ dnl the date in the version
AC_DEFINE([PACKAGE], PACKAGE_NAME, [Name of package])
dnl change this on a release
-VERSION="0.96.1"
+VERSION="0.96.2"
AC_DEFINE_UNQUOTED([VERSION],"$VERSION",[Version number of package])
LC_CURRENT=7
-LC_REVISION=3
+LC_REVISION=4
LC_AGE=1
LIBCLAMAV_VERSION="$LC_CURRENT":"$LC_REVISION":"$LC_AGE"
AC_SUBST([LIBCLAMAV_VERSION])
diff --git a/contrib/safe_clamd/safe_clamd b/contrib/safe_clamd/safe_clamd
new file mode 100755
index 0000000..a5aba8c
--- /dev/null
+++ b/contrib/safe_clamd/safe_clamd
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+# safe_clamd - a script to start clamd and restart if it dies unexpectedly
+# Please report bugs at https://wwws.clamav.net/bugzilla/show_bug.cgi?id=2026
+# Usage:
+# start with ./safe_clamd
+# stop by sending a TERM signal to the safe_clamd process
+
+{
+####################### CONFIGURATION #######################
+# path to clamd.conf
+CLAMDCONF='/usr/local/etc/clamd.conf'
+# path to clamd binary
+CLAMDBIN='/usr/local/sbin/clamd'
+# interval between checks
+SLEEPINTERVAL=3
+# after a successful restart, sleep for $THROTTLE secs before attempting to restart clamd again
+THROTTLE=30
+##################### END CONFIGURATION #####################
+
+# Do not touch anything below this line, unless you know what you are doing
+trap "signalClamd HUP" SIGHUP
+trap "signalClamd TERM" SIGTERM
+trap "signalClamd USR2" SIGUSR2
+
+getPid() {
+ PIDFILE=`grep ^PidFile $CLAMDCONF | sed -e 's/^PidFile\s*//'`
+ if [ -z "PIDFILE" ]
+ then
+ # missing PidFile directive
+ echo "Please enable the PidFile directive in $CLAMDCONF. See man clamd.conf for more info."
+ exit 1
+ fi
+ CLAMDPID=`cat $PIDFILE 2>/dev/null | grep -Eo '^[0-9]+$'`
+ if [ -z "$CLAMDPID" ]
+ then
+ # empty pidfile
+ CLAMDPID=0
+ return
+ fi
+ if ps p $CLAMDPID | grep -v grep | grep $CLAMDBIN > /dev/null
+ then
+ # good pid
+ return
+ fi
+ # invalid pid
+ CLAMDPID=0
+}
+
+startClamd() {
+ rm -f $PIDFILE
+ if test -f $PIDFILE
+ then
+ echo "ERROR: cannot remove $PIDFILE"
+ exit 1
+ else
+ $CLAMDBIN $args
+ if [ $? -ne 0 ]
+ then
+ exit $?
+ fi
+ sleep $THROTTLE
+ fi
+}
+
+signalClamd() {
+ getPid
+ if [ $CLAMDPID -gt 0 ]; then
+ echo "Sending $1 to pid $CLAMDPID..."
+ kill -$1 $CLAMDPID
+ else
+ echo "$CLAMDBIN is not running."
+ fi
+ if [ "$1" == "TERM" ]; then
+ echo Exiting $0 ...
+ exit
+ fi
+}
+
+args=$@
+
+# start clamd
+# if it start successfully, enter loop
+# every 5 secs, find pid, verify it belongs to clamd, kill -0
+# restart it if dead
+while [ true ]; do
+ if test -r "$CLAMDCONF"
+ then
+ if test -x "$CLAMDBIN"
+ then
+ # retrieve pid
+ getPid
+ # pid found?
+ if [ $CLAMDPID -gt 0 ]
+ then
+ if kill -0 $CLAMDPID > /dev/null 2>/dev/null
+ then
+ # pid is alive, sleep before next check
+ sleep $SLEEPINTERVAL
+ else
+ # stale pid
+ rm -f $PIDFILE
+ startClamd
+ fi
+ else
+ # pid does not belong to clamd
+ startClamd
+ fi
+ else
+ echo $CLAMDBIN not found
+ exit 1
+ fi
+ else
+ echo $CLAMDCONF not found
+ exit 1
+ fi
+done
+
+} &
diff --git a/docs/clamdoc.pdf b/docs/clamdoc.pdf
index 550cea4..06073f9 100644
Binary files a/docs/clamdoc.pdf and b/docs/clamdoc.pdf differ
diff --git a/docs/clamdoc.tex b/docs/clamdoc.tex
index 78bbf5d..02240e5 100644
--- a/docs/clamdoc.tex
+++ b/docs/clamdoc.tex
@@ -71,7 +71,7 @@
\vspace{3cm}
\begin{flushright}
\rule[-1ex]{8cm}{3pt}\\
- \huge Clam AntiVirus 0.96.1\\
+ \huge Clam AntiVirus 0.96.2\\
\huge \emph{User Manual}\\
\end{flushright}
@@ -127,7 +127,7 @@
\item{POSIX compliant, portable}
\item{Fast scanning}
\item{Supports on-access scanning (Linux and FreeBSD only)}
- \item{Detects over 775.000 viruses, worms and trojans, including
+ \item{Detects over 800.000 viruses, worms and trojans, including
Microsoft Office macro viruses, mobile malware, and other threats}
\item{Built-in bytecode interpreter allows the ClamAV signature writers
to create and distribute very complex detection routines and
diff --git a/docs/html/clamdoc.html b/docs/html/clamdoc.html
index b69bd12..7cd654d 100644
--- a/docs/html/clamdoc.html
+++ b/docs/html/clamdoc.html
@@ -56,7 +56,7 @@ original version by: Nikos Drakos, CBLU, University of Leeds
<BR>
<BR>
<DIV ALIGN="RIGHT">
-<BR> <BIG CLASS="HUGE">Clam AntiVirus 0.96.1
+<BR> <BIG CLASS="HUGE">Clam AntiVirus 0.96.2
<BR> <BIG CLASS="HUGE"><SPAN CLASS="textit">User Manual</SPAN>
<BR>
</BIG></BIG></DIV>
@@ -227,7 +227,7 @@ original version by: Nikos Drakos, CBLU, University of Leeds
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/index.html b/docs/html/index.html
index b69bd12..7cd654d 100644
--- a/docs/html/index.html
+++ b/docs/html/index.html
@@ -56,7 +56,7 @@ original version by: Nikos Drakos, CBLU, University of Leeds
<BR>
<BR>
<DIV ALIGN="RIGHT">
-<BR> <BIG CLASS="HUGE">Clam AntiVirus 0.96.1
+<BR> <BIG CLASS="HUGE">Clam AntiVirus 0.96.2
<BR> <BIG CLASS="HUGE"><SPAN CLASS="textit">User Manual</SPAN>
<BR>
</BIG></BIG></DIV>
@@ -227,7 +227,7 @@ original version by: Nikos Drakos, CBLU, University of Leeds
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node1.html b/docs/html/node1.html
index 4a7ba17..c6ff3c5 100644
--- a/docs/html/node1.html
+++ b/docs/html/node1.html
@@ -182,7 +182,7 @@ ClamAV and Clam AntiVirus are trademarks of Sourcefire, Inc.
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node10.html b/docs/html/node10.html
index 51564a4..2554721 100644
--- a/docs/html/node10.html
+++ b/docs/html/node10.html
@@ -61,7 +61,7 @@ Binary packages</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node11.html b/docs/html/node11.html
index c8f4925..2fb2f68 100644
--- a/docs/html/node11.html
+++ b/docs/html/node11.html
@@ -81,7 +81,7 @@ Installation</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node12.html b/docs/html/node12.html
index 7ad39cd..ea6c4e6 100644
--- a/docs/html/node12.html
+++ b/docs/html/node12.html
@@ -133,7 +133,7 @@ the package for these compilers are usually called: gcc, g++, or gcc-c++.
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node13.html b/docs/html/node13.html
index cea94fc..fa5af03 100644
--- a/docs/html/node13.html
+++ b/docs/html/node13.html
@@ -75,7 +75,7 @@ Installing on shell account</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node14.html b/docs/html/node14.html
index acbde2b..03bab0d 100644
--- a/docs/html/node14.html
+++ b/docs/html/node14.html
@@ -69,7 +69,7 @@ Adding new system user and group</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node15.html b/docs/html/node15.html
index af9d649..64f224c 100644
--- a/docs/html/node15.html
+++ b/docs/html/node15.html
@@ -75,7 +75,7 @@ Compilation of base package</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node16.html b/docs/html/node16.html
index 2c42b4b..c495031 100644
--- a/docs/html/node16.html
+++ b/docs/html/node16.html
@@ -65,7 +65,7 @@ Compilation with clamav-milter enabled</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node17.html b/docs/html/node17.html
index 0218a06..8274544 100644
--- a/docs/html/node17.html
+++ b/docs/html/node17.html
@@ -142,7 +142,7 @@ All 4 tests passed
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node18.html b/docs/html/node18.html
index 2aaedb3..ea232cb 100644
--- a/docs/html/node18.html
+++ b/docs/html/node18.html
@@ -96,7 +96,7 @@ $ CK_FORK=no ./libtool --mode=execute valgrind unit_tests/check-clamav
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node19.html b/docs/html/node19.html
index 80bc19d..61d93ba 100644
--- a/docs/html/node19.html
+++ b/docs/html/node19.html
@@ -87,7 +87,7 @@ Configuration</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node2.html b/docs/html/node2.html
index 23a1220..82383c3 100644
--- a/docs/html/node2.html
+++ b/docs/html/node2.html
@@ -79,7 +79,7 @@ Introduction</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node20.html b/docs/html/node20.html
index d5c2cd4..0e56a2d 100644
--- a/docs/html/node20.html
+++ b/docs/html/node20.html
@@ -79,7 +79,7 @@ clamd</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node21.html b/docs/html/node21.html
index cab8e9b..8087b94 100644
--- a/docs/html/node21.html
+++ b/docs/html/node21.html
@@ -90,7 +90,7 @@ On-access scanning</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node22.html b/docs/html/node22.html
index b8b1f64..30de980 100644
--- a/docs/html/node22.html
+++ b/docs/html/node22.html
@@ -70,7 +70,7 @@ clamav-milter</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node23.html b/docs/html/node23.html
index 682e447..e00246c 100644
--- a/docs/html/node23.html
+++ b/docs/html/node23.html
@@ -75,7 +75,7 @@ Testing</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node24.html b/docs/html/node24.html
index 2305c8a..dc8ce08 100644
--- a/docs/html/node24.html
+++ b/docs/html/node24.html
@@ -140,7 +140,7 @@ N * * * * /usr/local/bin/freshclam --quiet
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node25.html b/docs/html/node25.html
index 250c468..1b27119 100644
--- a/docs/html/node25.html
+++ b/docs/html/node25.html
@@ -77,7 +77,7 @@ Closest mirrors</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node26.html b/docs/html/node26.html
index 53f056b..e5b24a3 100644
--- a/docs/html/node26.html
+++ b/docs/html/node26.html
@@ -108,7 +108,7 @@ The only private data that is transferred is an IP address, which is used
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node27.html b/docs/html/node27.html
index e648ffc..1d3cf2b 100644
--- a/docs/html/node27.html
+++ b/docs/html/node27.html
@@ -80,7 +80,7 @@ Usage</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node28.html b/docs/html/node28.html
index dd6e1d9..e6a534f 100644
--- a/docs/html/node28.html
+++ b/docs/html/node28.html
@@ -230,7 +230,7 @@ Scan stream: clamd will return a new port number you should
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node29.html b/docs/html/node29.html
index f5a7a3b..893d9d4 100644
--- a/docs/html/node29.html
+++ b/docs/html/node29.html
@@ -76,7 +76,7 @@ Clam<SPAN CLASS="textbf">d</SPAN>scan</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node3.html b/docs/html/node3.html
index 96a8af4..62dc179 100644
--- a/docs/html/node3.html
+++ b/docs/html/node3.html
@@ -67,7 +67,7 @@ Features</A>
</LI>
<LI>Supports on-access scanning (Linux and FreeBSD only)
</LI>
-<LI>Detects over 775.000 viruses, worms and trojans, including
+<LI>Detects over 800.000 viruses, worms and trojans, including
Microsoft Office macro viruses, mobile malware, and other threats
</LI>
<LI>Built-in bytecode interpreter allows the ClamAV signature writers
@@ -195,7 +195,7 @@ Features</A>
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node30.html b/docs/html/node30.html
index 12197a9..91914f8 100644
--- a/docs/html/node30.html
+++ b/docs/html/node30.html
@@ -92,7 +92,7 @@ SIGTERM signal. In other case you can lose access
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node31.html b/docs/html/node31.html
index 9b6b4dc..bb5f313 100644
--- a/docs/html/node31.html
+++ b/docs/html/node31.html
@@ -70,7 +70,7 @@ Output format</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node32.html b/docs/html/node32.html
index 288e0e0..93d8f28 100644
--- a/docs/html/node32.html
+++ b/docs/html/node32.html
@@ -79,7 +79,7 @@ clamscan</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node33.html b/docs/html/node33.html
index 29e1c93..f3a6a63 100644
--- a/docs/html/node33.html
+++ b/docs/html/node33.html
@@ -83,7 +83,7 @@ Error messages are printed in the following format:
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node34.html b/docs/html/node34.html
index 9334f8b..7c152f2 100644
--- a/docs/html/node34.html
+++ b/docs/html/node34.html
@@ -129,7 +129,7 @@ LibClamAV</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node35.html b/docs/html/node35.html
index f2ede3a..f964f1e 100644
--- a/docs/html/node35.html
+++ b/docs/html/node35.html
@@ -63,7 +63,7 @@ Licence</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node36.html b/docs/html/node36.html
index f5186de..58caff0 100644
--- a/docs/html/node36.html
+++ b/docs/html/node36.html
@@ -79,7 +79,7 @@ Supported formats and features</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node37.html b/docs/html/node37.html
index 8ccf394..be7aa2e 100644
--- a/docs/html/node37.html
+++ b/docs/html/node37.html
@@ -87,7 +87,7 @@ Executables</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node38.html b/docs/html/node38.html
index 0c035a0..5fc84dd 100644
--- a/docs/html/node38.html
+++ b/docs/html/node38.html
@@ -62,7 +62,7 @@ Mail files</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node39.html b/docs/html/node39.html
index a131b26..3da50c5 100644
--- a/docs/html/node39.html
+++ b/docs/html/node39.html
@@ -98,7 +98,7 @@ Archives and compressed files</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node4.html b/docs/html/node4.html
index f75d9dd..8c266ab 100644
--- a/docs/html/node4.html
+++ b/docs/html/node4.html
@@ -86,7 +86,7 @@ Alternatively you can try asking on the <code>#clamav</code> IRC channel - launc
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node40.html b/docs/html/node40.html
index 6bef13e..ad537d1 100644
--- a/docs/html/node40.html
+++ b/docs/html/node40.html
@@ -76,7 +76,7 @@ Documents</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node41.html b/docs/html/node41.html
index 48863e5..b88817e 100644
--- a/docs/html/node41.html
+++ b/docs/html/node41.html
@@ -62,7 +62,7 @@ Data Loss Prevention</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node42.html b/docs/html/node42.html
index 76d2aa0..8061680 100644
--- a/docs/html/node42.html
+++ b/docs/html/node42.html
@@ -75,7 +75,7 @@ Others</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node43.html b/docs/html/node43.html
index 857d7db..0033aff 100644
--- a/docs/html/node43.html
+++ b/docs/html/node43.html
@@ -91,7 +91,7 @@ API</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node44.html b/docs/html/node44.html
index c1e69c4..4b6578c 100644
--- a/docs/html/node44.html
+++ b/docs/html/node44.html
@@ -64,7 +64,7 @@ Header file</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node45.html b/docs/html/node45.html
index 6d9f07f..bb0822c 100644
--- a/docs/html/node45.html
+++ b/docs/html/node45.html
@@ -73,7 +73,7 @@ Initialization</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node46.html b/docs/html/node46.html
index 85f275d..393be24 100644
--- a/docs/html/node46.html
+++ b/docs/html/node46.html
@@ -125,7 +125,7 @@ Load bytecode.
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node47.html b/docs/html/node47.html
index 656111b..9636dd0 100644
--- a/docs/html/node47.html
+++ b/docs/html/node47.html
@@ -69,7 +69,7 @@ Error handling</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node48.html b/docs/html/node48.html
index c8d6896..dcd1228 100644
--- a/docs/html/node48.html
+++ b/docs/html/node48.html
@@ -75,7 +75,7 @@ Engine structure</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node49.html b/docs/html/node49.html
index da5dcce..4c28a67 100644
--- a/docs/html/node49.html
+++ b/docs/html/node49.html
@@ -79,7 +79,7 @@ const char *cl_engine_get_str(const struct cl_engine *engine,
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node5.html b/docs/html/node5.html
index b9e4ba5..ecb58d5 100644
--- a/docs/html/node5.html
+++ b/docs/html/node5.html
@@ -65,7 +65,7 @@ Virus submitting</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node50.html b/docs/html/node50.html
index 9e2e6b4..01dba6c 100644
--- a/docs/html/node50.html
+++ b/docs/html/node50.html
@@ -103,7 +103,7 @@ Database checks</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node51.html b/docs/html/node51.html
index b9b82ef..0748dc4 100644
--- a/docs/html/node51.html
+++ b/docs/html/node51.html
@@ -213,7 +213,7 @@ Allow heuristic match to take precedence. When enabled, if
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node52.html b/docs/html/node52.html
index 577cbe5..05ca466 100644
--- a/docs/html/node52.html
+++ b/docs/html/node52.html
@@ -63,7 +63,7 @@ Memory</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node53.html b/docs/html/node53.html
index 250c012..20b6262 100644
--- a/docs/html/node53.html
+++ b/docs/html/node53.html
@@ -65,7 +65,7 @@ Forking daemons</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node54.html b/docs/html/node54.html
index e5dde99..3e456e1 100644
--- a/docs/html/node54.html
+++ b/docs/html/node54.html
@@ -67,7 +67,7 @@ clamav-config</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node55.html b/docs/html/node55.html
index e8fa45e..6ddf7a3 100644
--- a/docs/html/node55.html
+++ b/docs/html/node55.html
@@ -65,7 +65,7 @@ Example</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node56.html b/docs/html/node56.html
index 7ca6c3b..293b79b 100644
--- a/docs/html/node56.html
+++ b/docs/html/node56.html
@@ -82,7 +82,7 @@ Verification OK.
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node57.html b/docs/html/node57.html
index 983510a..1187c64 100644
--- a/docs/html/node57.html
+++ b/docs/html/node57.html
@@ -613,7 +613,7 @@ Contributors</A>
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node58.html b/docs/html/node58.html
index 5f66f13..675e337 100644
--- a/docs/html/node58.html
+++ b/docs/html/node58.html
@@ -459,7 +459,7 @@ Donors</A>
<!--End of Navigation Panel-->
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node59.html b/docs/html/node59.html
index 978be3c..7c71044 100644
--- a/docs/html/node59.html
+++ b/docs/html/node59.html
@@ -63,7 +63,7 @@ Graphics</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node6.html b/docs/html/node6.html
index e3f266d..478e206 100644
--- a/docs/html/node6.html
+++ b/docs/html/node6.html
@@ -78,7 +78,7 @@ Base package</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node60.html b/docs/html/node60.html
index c301e24..7424b0b 100644
--- a/docs/html/node60.html
+++ b/docs/html/node60.html
@@ -62,7 +62,7 @@ OpenAntiVirus</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node61.html b/docs/html/node61.html
index 6aef439..5c8f30c 100644
--- a/docs/html/node61.html
+++ b/docs/html/node61.html
@@ -134,7 +134,7 @@ Role: coder
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node62.html b/docs/html/node62.html
index 72e4774..2c27c52 100644
--- a/docs/html/node62.html
+++ b/docs/html/node62.html
@@ -64,11 +64,11 @@ Mathematics Department, Macquarie University, Sydney.
The command line arguments were: <BR>
<STRONG>latex2html</STRONG> <TT>-local_icons clamdoc.tex</TT>
<P>
-The translation was initiated by Tomasz Kojm on 2010-05-19
+The translation was initiated by Tomasz Kojm on 2010-08-12
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node7.html b/docs/html/node7.html
index 714be9b..c7db45b 100644
--- a/docs/html/node7.html
+++ b/docs/html/node7.html
@@ -69,7 +69,7 @@ Supported platforms</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node8.html b/docs/html/node8.html
index 4348b6b..97194c4 100644
--- a/docs/html/node8.html
+++ b/docs/html/node8.html
@@ -77,7 +77,7 @@ UNIX</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/html/node9.html b/docs/html/node9.html
index aa358c4..4abfd20 100644
--- a/docs/html/node9.html
+++ b/docs/html/node9.html
@@ -60,7 +60,7 @@ Windows</A>
<BR><HR>
<ADDRESS>
Tomasz Kojm
-2010-05-19
+2010-08-12
</ADDRESS>
</BODY>
</HTML>
diff --git a/docs/man/clamav-milter.conf.5.in b/docs/man/clamav-milter.conf.5.in
index 6b099f9..4786397 100644
--- a/docs/man/clamav-milter.conf.5.in
+++ b/docs/man/clamav-milter.conf.5.in
@@ -123,7 +123,7 @@ Messages from authenticated SMTP users matching this extended POSIX regular expr
.br
Default: unset (no whitelisting based on SMTP auth)
.TP
-\fBSkipAuthenticated SIZE\fR
+\fBMaxFileSize SIZE\fR
Messages larger than this value won\'t be scanned. Make sure this value is lower or equal than StreamMaxLength in clamd.conf
.br
Default: 25M
diff --git a/docs/man/clamd.conf.5.in b/docs/man/clamd.conf.5.in
index 5caa848..b3e454d 100644
--- a/docs/man/clamd.conf.5.in
+++ b/docs/man/clamd.conf.5.in
@@ -1,4 +1,4 @@
-.TH "clamd.conf" "5" "November 2, 2009" "ClamAV @VERSION@" "Clam AntiVirus"
+.TH "clamd.conf" "5" "February 12, 2007" "ClamAV @VERSION@" "Clam AntiVirus"
.SH "NAME"
.LP
\fBclamd.conf\fR \- Configuration file for Clam AntiVirus Daemon
@@ -66,6 +66,11 @@ Enable verbose logging.
.br
Default: no
.TP
+\fBExtendedDetectionInfo BOOL\fR
+Provide additional information about the infected file, such as its size and hash, together with the virus name. It's recommended to enable this option along with SubmitDetectionStats in freshclam.conf.
+.br
+Default: no
+.TP
\fBPidFile STRING\fR
Save the process identifier of a listening daemon (main thread) to a specified file.
.br
diff --git a/docs/man/freshclam.conf.5.in b/docs/man/freshclam.conf.5.in
index 54614a8..19becf4 100644
--- a/docs/man/freshclam.conf.5.in
+++ b/docs/man/freshclam.conf.5.in
@@ -155,7 +155,7 @@ Timeout in seconds when reading from database server.
Default: 30
.TP
\fBSubmitDetectionStats STRING\fR
-When enabled freshclam will submit statistics to the ClamAV Project about the latest virus detections in your environment. The ClamAV maintainers will then use this data to determine what types of malware are the most detected in the field and in what geographic area they are. This feature requires LogTime and LogFile to be enabled in clamd.conf. The path for clamd.conf file must be provided.
+When enabled freshclam will submit statistics to the ClamAV Project about the latest virus detections in your environment. The ClamAV maintainers will then use this data to determine what types of malware are the most detected in the field and in what geographic area they are. This feature requires LogTime and LogFile to be enabled in clamd.conf, it's also recommended to turn on ExtendedDetectionInfo. The path for clamd.conf file must be provided.
.br
Default: disabled
.TP
diff --git a/docs/man/sigtool.1.in b/docs/man/sigtool.1.in
index 4793472..684e571 100644
--- a/docs/man/sigtool.1.in
+++ b/docs/man/sigtool.1.in
@@ -54,7 +54,10 @@ Build a CVD file. \-s, \-\-server is required.
\fB\-\-server\fR
ClamAV Signing Service address (for virus database maintainers only).
.TP
-\fB\-\-unpack FILE, \-u FILE\fR
+\fB\-\-datadir=DIR\fR
+Use DIR as the default database directory for all operations.
+.TP
+\fB\-\-unpack=FILE, \-u FILE\fR
Unpack FILE (CVD) to a current directory.
.TP
\fB\-\-unpack\-current\fR
@@ -79,7 +82,7 @@ Find and display signatures from the local database directory which match the gi
Decode signatures read from the standard input (eg. piped from \-\-find\-sigs)
.TP
\fB\-fREGEX, \-\-test\-sigs=DATABASE TARGET_FILE\fR
-Test all signatures from DATABASE against TARGET_FILE.
+Test all signatures from DATABASE against TARGET_FILE. This option will only give valid results if the target file is the final one (after unpacking, normalization, etc.) for which the signatures were created.
.SH "EXAMPLES"
.LP
.TP
diff --git a/etc/clamd.conf b/etc/clamd.conf
index d464b19..101b25f 100644
--- a/etc/clamd.conf
+++ b/etc/clamd.conf
@@ -51,6 +51,11 @@ Example
# Default: no
#LogVerbose yes
+# Provide additional information about the infected file, such as its
+# size and hash, together with the virus name. It's recommended to enable
+# this option along with SubmitDetectionStats in freshclam.conf.
+#ExtendedDetectionInfo yes
+
# This option allows you to save a process identifier of the listening
# daemon (main thread).
# Default: disabled
diff --git a/etc/freshclam.conf b/etc/freshclam.conf
index ff3e366..18be1a3 100644
--- a/etc/freshclam.conf
+++ b/etc/freshclam.conf
@@ -152,7 +152,8 @@ DatabaseMirror database.clamav.net
# the latest virus detections in your environment. The ClamAV maintainers
# will then use this data to determine what types of malware are the most
# detected in the field and in what geographic area they are.
-# This feature requires LogTime and LogFile to be enabled in clamd.conf.
+# This feature requires LogTime and LogFile to be enabled in clamd.conf,
+# it's also recommended to turn on ExtendedDetectionInfo.
# Default: no
#SubmitDetectionStats /path/to/clamd.conf
diff --git a/freshclam/manager.c b/freshclam/manager.c
index c60f582..7a10243 100644
--- a/freshclam/manager.c
+++ b/freshclam/manager.c
@@ -77,6 +77,7 @@
#include "libclamav/others.h"
#include "libclamav/str.h"
#include "libclamav/cvd.h"
+#include "libclamav/regex_list.h"
extern char updtmpdir[512];
@@ -181,20 +182,24 @@ static int getclientsock(const char *localip, int prot)
return socketfd;
}
+static int qcompare(const void *a, const void *b)
+{
+ return (*(const struct addrinfo **) a)->ai_flags - (*(const struct addrinfo **) b)->ai_flags;
+}
+
static int wwwconnect(const char *server, const char *proxy, int pport, char *ip, const char *localip, int ctimeout, struct mirdat *mdat, int logerr, unsigned int can_whitelist)
{
int socketfd, port, ret;
- unsigned int ips = 0, ignored = 0;
+ unsigned int ips = 0, ignored = 0, i;
#ifdef HAVE_GETADDRINFO
- struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL;
+ struct addrinfo hints, *res = NULL, *rp, *loadbal_rp = NULL, *addrs[128];
char port_s[6], loadbal_ipaddr[46];
- uint32_t loadbal = 1, minsucc = 0xffffffff, minfail = 0xffffffff;
+ uint32_t loadbal = 1, minsucc = 0xffffffff, minfail = 0xffffffff, addrnum = 0;
struct mirdat_ip *md;
#else
struct sockaddr_in name;
struct hostent *host;
unsigned char *ia;
- int i;
#endif
char ipaddr[46];
const char *hostpt;
@@ -237,9 +242,17 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
return -1;
}
- for(rp = res; rp; rp = rp->ai_next) {
+ for(rp = res; rp && addrnum < 128; rp = rp->ai_next) {
+ rp->ai_flags = cli_rndnum(1024);
+ addrs[addrnum] = rp;
+ addrnum++;
+ }
+ qsort(addrs, addrnum, sizeof(struct addrinfo *), qcompare);
+
+ for(i = 0; i < addrnum; i++) {
void *addr;
+ rp = addrs[i];
ips++;
#ifdef SUPPORT_IPv6
if(rp->ai_family == AF_INET6)
@@ -261,7 +274,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
logg("*Ignoring mirror %s (has connected too many times with an outdated version)\n", ipaddr);
ignored++;
- if(!loadbal || rp->ai_next)
+ if(!loadbal || i + 1 < addrnum)
continue;
}
@@ -277,15 +290,15 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
loadbal_rp = rp;
strncpy(loadbal_ipaddr, ipaddr, sizeof(loadbal_ipaddr));
}
- if(rp->ai_next)
+ if(i + 1 < addrnum)
continue;
}
}
if(!loadbal_rp) {
- if(!rp->ai_next) {
+ if(i + 1 == addrnum) {
loadbal = 0;
- rp = res;
+ i = 0;
}
continue;
}
@@ -299,7 +312,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
if(ip)
strcpy(ip, ipaddr);
- if(rp != res)
+ if(rp != loadbal_rp && rp != addrs[0])
logg("Trying host %s (%s)...\n", hostpt, ipaddr);
socketfd = getclientsock(localip, rp->ai_family);
@@ -317,7 +330,7 @@ static int wwwconnect(const char *server, const char *proxy, int pport, char *ip
closesocket(socketfd);
if(loadbal) {
loadbal = 0;
- rp = res;
+ i = 0;
}
continue;
} else {
@@ -569,6 +582,7 @@ int submitstats(const char *clamdcfg, const struct optstruct *opts)
if(!(opt = optget(clamdopt, "LogFile"))->enabled) {
logg("!SubmitDetectionStats: LogFile needs to be enabled in %s\n", clamdcfg);
+ logg("SubmitDetectionStats: Please consider enabling ExtendedDetectionInfo\n");
optfree(clamdopt);
return 56;
}
@@ -683,13 +697,13 @@ int submitstats(const char *clamdcfg, const struct optstruct *opts)
pt2 = &pt[strlen(pt) - 6];
*pt2 = 0;
- if(!(pt2 = strrchr(pt, ':'))) {
+ if(!(pt2 = strrchr(pt, ' ')) || pt2[-1] != ':') {
logg("!SubmitDetectionStats: Incorrect format of the log file (1)\n");
ret = 1;
break;
}
- *pt2 = 0;
- pt2 += 2;
+ pt2[-1] = 0;
+ pt2++;
if((pt = strrchr(pt, *PATHSEP)))
*pt++ = 0;
@@ -1754,7 +1768,7 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
cl_engine_free(engine);
return 55;
}
- if((ret = cli_bytecode_prepare(&engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
+ if(optget(opts, "Bytecode")->enabled && (ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode/*FIXME: dconf has no sense here*/))) {
logg("!Failed to compile/load bytecode: %s\n", cl_strerror(ret));
unlink(newfile);
free(newfile);
@@ -1762,6 +1776,8 @@ static int updatedb(const char *dbname, const char *hostname, char *ip, int *sig
return 55;
}
logg("*Properly loaded %u signatures from new %s\n", newsigs, newdb);
+ if(engine->domainlist_matcher && engine->domainlist_matcher->sha256_pfx_set.keys)
+ cli_hashset_destroy(&engine->domainlist_matcher->sha256_pfx_set);
cl_engine_free(engine);
}
@@ -2013,6 +2029,7 @@ int downloadmanager(const struct optstruct *opts, const char *hostname, const ch
}
mirman_write("mirrors.dat", &mdat);
+ cli_rmdirs(updtmpdir);
if(updated) {
if(optget(opts, "HTTPProxyServer")->enabled) {
@@ -2054,7 +2071,6 @@ int downloadmanager(const struct optstruct *opts, const char *hostname, const ch
free(cmd);
if(newver)
free(newver);
- cli_rmdirs(updtmpdir);
return 75;
}
@@ -2077,6 +2093,5 @@ int downloadmanager(const struct optstruct *opts, const char *hostname, const ch
if(newver)
free(newver);
- cli_rmdirs(updtmpdir);
return 0;
}
diff --git a/libclamav/7z/Archive/7z/7zDecode.c b/libclamav/7z/Archive/7z/7zDecode.c
index 02526f0..69c91f5 100644
--- a/libclamav/7z/Archive/7z/7zDecode.c
+++ b/libclamav/7z/Archive/7z/7zDecode.c
@@ -170,7 +170,10 @@ SRes SzDecode2(const UInt64 *packSizes, const CSzFolder *folder,
outSizeCur = (SizeT)unpackSize;
if (outSizeCur != unpackSize)
return SZ_ERROR_MEM;
- temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
+ if (outSizeCur)
+ temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
+ else
+ temp = 0;
if (temp == 0 && outSizeCur != 0)
return SZ_ERROR_MEM;
outBufCur = tempBuf[1 - ci] = temp;
diff --git a/libclamav/7z/BraIA64.c b/libclamav/7z/BraIA64.c
new file mode 100644
index 0000000..0b4ee85
--- /dev/null
+++ b/libclamav/7z/BraIA64.c
@@ -0,0 +1,67 @@
+/* BraIA64.c -- Converter for IA-64 code
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/libclamav/7z/lzma.txt b/libclamav/7z/lzma.txt
new file mode 100644
index 0000000..d4f4af9
--- /dev/null
+++ b/libclamav/7z/lzma.txt
@@ -0,0 +1,594 @@
+LZMA SDK 4.65
+-------------
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+C++/7zip/Compress/LZMA_Alone
+and call make to recompile it:
+ make -f makefile.gcc clean all
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, you can use
+LIB = -lm -static
+
+
+Files
+---------------------
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description
+methods.txt - Compression method IDs for .7z
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C/ - C files
+ 7zCrc*.* - CRC code
+ Alloc.* - Memory allocation functions
+ Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ LzFind.* - Match finder for LZ (LZMA) encoders
+ LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
+ LzHash.h - Additional file for LZ match finder
+ LzmaDec.* - LZMA decoding
+ LzmaEnc.* - LZMA encoding
+ LzmaLib.* - LZMA Library for DLL calling
+ Types.h - Basic types for another .c files
+ Threads.* - The code for multithreading.
+
+ LzmaLib - LZMA Library (.DLL for Windows)
+
+ LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+
+ Archive - files related to archiving
+ 7z - 7z ANSI-C Decoder
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip Project
+
+ Common - common files for 7-Zip
+
+ Compress - files related to compression/decompression
+
+ Copy - Copy coder
+ RangeCoder - Range Coder (special code of compression/decompression)
+ LZMA - LZMA compression/decompression on C++
+ LZMA_Alone - file->file LZMA compression/decompression
+ Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules
+
+ Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+ Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console archiver
+
+
+
+CS/ - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java/ - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+
+LZMA features
+-------------
+ - Variable dictionary size (up to 1 GB)
+ - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
+ - Estimated decompressing speed:
+ - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
+ - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (16 KB + DictionarySize)
+ - Small code size for decompressing: 5-8 KB
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect the speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+The speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with Intel's Core 2 results.
+ Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
+ Also you can change the number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal
+ default: 1 (normal)
+
+ d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
+ The maximum value for dictionary size is 1 GB = 2^30 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0).
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
+ bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
+ bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
+ hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase the compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Filters
+-------
+You can increase the compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase the compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C source code of such filters in C/Bra*.* files
+
+You can check the compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=arm -m1=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + Types.h
+LzmaUtil/LzmaUtil.c is example application that uses these files.
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+For full code example, look at C/LzmaUtil/LzmaUtil.c code.
+
+
+How To compress data
+--------------------
+
+Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
+LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Check C/LzmaUtil/LzmaUtil.c as example,
+
+When to use: file->file decompressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without
+"NewHandler.cpp". So standard exception will be used. Actually some code of
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/libclamav/Makefile.am b/libclamav/Makefile.am
index 8ee7a2e..99f2375 100644
--- a/libclamav/Makefile.am
+++ b/libclamav/Makefile.am
@@ -142,6 +142,8 @@ libclamav_la_SOURCES = \
matcher-ac.h \
matcher-bm.c \
matcher-bm.h \
+ matcher-md5.c \
+ matcher-md5.h \
matcher.c \
matcher.h \
others.c \
@@ -353,7 +355,10 @@ libclamav_la_SOURCES = \
bytecode_api_impl.h \
bytecode_hooks.h \
cache.c \
- cache.h
+ cache.h \
+ bytecode_detect.c \
+ bytecode_detect.h\
+ builtin_bytecodes.h
if !LINK_TOMMATH
libclamav_la_SOURCES += bignum.c \
diff --git a/libclamav/Makefile.in b/libclamav/Makefile.in
index 3872c0b..7e105da 100644
--- a/libclamav/Makefile.in
+++ b/libclamav/Makefile.in
@@ -115,22 +115,22 @@ LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
@ENABLE_LLVM_FALSE at am__DEPENDENCIES_2 = libclamav_nocxx.la
@ENABLE_LLVM_TRUE at am__DEPENDENCIES_2 = c++/libclamavcxx.la
am__libclamav_la_SOURCES_DIST = clamav.h matcher-ac.c matcher-ac.h \
- matcher-bm.c matcher-bm.h matcher.c matcher.h others.c \
- others.h readdb.c readdb.h cvd.c cvd.h dsig.c dsig.h \
- scanners.c scanners.h textdet.c textdet.h filetypes.c \
- filetypes.h filetypes_int.h rtf.c rtf.h blob.c blob.h mbox.c \
- mbox.h message.c message.h table.c table.h text.c text.h \
- ole2_extract.c ole2_extract.h vba_extract.c vba_extract.h \
- cltypes.h msexpand.c msexpand.h pe.c pe.h pe_icons.c \
- pe_icons.h disasm.c disasm.h disasm-common.h disasmpriv.h \
- upx.c upx.h htmlnorm.c htmlnorm.h chmunpack.c chmunpack.h \
- rebuildpe.c rebuildpe.h petite.c petite.h wwunpack.c \
- wwunpack.h unsp.c unsp.h aspack.c aspack.h packlibs.c \
- packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h line.c \
- line.h untar.c untar.h unzip.c unzip.h inflate64.c inflate64.h \
- inffixed64.h inflate64_priv.h special.c special.h binhex.c \
- binhex.h is_tar.c is_tar.h tnef.c tnef.h autoit.c autoit.h \
- unarj.c unarj.h nsis/bzlib.c nsis/bzlib_private.h \
+ matcher-bm.c matcher-bm.h matcher-md5.c matcher-md5.h \
+ matcher.c matcher.h others.c others.h readdb.c readdb.h cvd.c \
+ cvd.h dsig.c dsig.h scanners.c scanners.h textdet.c textdet.h \
+ filetypes.c filetypes.h filetypes_int.h rtf.c rtf.h blob.c \
+ blob.h mbox.c mbox.h message.c message.h table.c table.h \
+ text.c text.h ole2_extract.c ole2_extract.h vba_extract.c \
+ vba_extract.h cltypes.h msexpand.c msexpand.h pe.c pe.h \
+ pe_icons.c pe_icons.h disasm.c disasm.h disasm-common.h \
+ disasmpriv.h upx.c upx.h htmlnorm.c htmlnorm.h chmunpack.c \
+ chmunpack.h rebuildpe.c rebuildpe.h petite.c petite.h \
+ wwunpack.c wwunpack.h unsp.c unsp.h aspack.c aspack.h \
+ packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h \
+ line.c line.h untar.c untar.h unzip.c unzip.h inflate64.c \
+ inflate64.h inffixed64.h inflate64_priv.h special.c special.h \
+ binhex.c binhex.h is_tar.c is_tar.h tnef.c tnef.h autoit.c \
+ autoit.h unarj.c unarj.h nsis/bzlib.c nsis/bzlib_private.h \
nsis/nsis_bzlib.h nsis/nulsft.c nsis/nulsft.h nsis/infblock.c \
nsis/nsis_zconf.h nsis/nsis_zlib.h nsis/nsis_zutil.h pdf.c \
pdf.h spin.c spin.h yc.c yc.h elf.c elf.h execs.h sis.c sis.h \
@@ -157,16 +157,17 @@ am__libclamav_la_SOURCES_DIST = clamav.h matcher-ac.c matcher-ac.h \
clambc.h cpio.c cpio.h macho.c macho.h ishield.c ishield.h \
type_desc.h bcfeatures.h bytecode_api.c bytecode_api_decl.c \
bytecode_api.h bytecode_api_impl.h bytecode_hooks.h cache.c \
- cache.h bignum.c bignum_class.h sha1.c sha1.h
+ cache.h bytecode_detect.c bytecode_detect.h \
+ builtin_bytecodes.h bignum.c bignum_class.h sha1.c sha1.h
@LINK_TOMMATH_FALSE at am__objects_1 = libclamav_la-bignum.lo
@BUILD_SHA1_TRUE at am__objects_2 = libclamav_la-sha1.lo
am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
- libclamav_la-matcher-bm.lo libclamav_la-matcher.lo \
- libclamav_la-others.lo libclamav_la-readdb.lo \
- libclamav_la-cvd.lo libclamav_la-dsig.lo \
- libclamav_la-scanners.lo libclamav_la-textdet.lo \
- libclamav_la-filetypes.lo libclamav_la-rtf.lo \
- libclamav_la-blob.lo libclamav_la-mbox.lo \
+ libclamav_la-matcher-bm.lo libclamav_la-matcher-md5.lo \
+ libclamav_la-matcher.lo libclamav_la-others.lo \
+ libclamav_la-readdb.lo libclamav_la-cvd.lo \
+ libclamav_la-dsig.lo libclamav_la-scanners.lo \
+ libclamav_la-textdet.lo libclamav_la-filetypes.lo \
+ libclamav_la-rtf.lo libclamav_la-blob.lo libclamav_la-mbox.lo \
libclamav_la-message.lo libclamav_la-table.lo \
libclamav_la-text.lo libclamav_la-ole2_extract.lo \
libclamav_la-vba_extract.lo libclamav_la-msexpand.lo \
@@ -208,7 +209,8 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
libclamav_la-bytecode_vm.lo libclamav_la-cpio.lo \
libclamav_la-macho.lo libclamav_la-ishield.lo \
libclamav_la-bytecode_api.lo libclamav_la-bytecode_api_decl.lo \
- libclamav_la-cache.lo $(am__objects_1) $(am__objects_2)
+ libclamav_la-cache.lo libclamav_la-bytecode_detect.lo \
+ $(am__objects_1) $(am__objects_2)
libclamav_la_OBJECTS = $(am_libclamav_la_OBJECTS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
@@ -617,21 +619,22 @@ libclamav_la_LDFLAGS = @TH_SAFE@ -version-info @LIBCLAMAV_VERSION@ \
-no-undefined $(am__append_6)
include_HEADERS = clamav.h
libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
- matcher-bm.h matcher.c matcher.h others.c others.h readdb.c \
- readdb.h cvd.c cvd.h dsig.c dsig.h scanners.c scanners.h \
- textdet.c textdet.h filetypes.c filetypes.h filetypes_int.h \
- rtf.c rtf.h blob.c blob.h mbox.c mbox.h message.c message.h \
- table.c table.h text.c text.h ole2_extract.c ole2_extract.h \
- vba_extract.c vba_extract.h cltypes.h msexpand.c msexpand.h \
- pe.c pe.h pe_icons.c pe_icons.h disasm.c disasm.h \
- disasm-common.h disasmpriv.h upx.c upx.h htmlnorm.c htmlnorm.h \
- chmunpack.c chmunpack.h rebuildpe.c rebuildpe.h petite.c \
- petite.h wwunpack.c wwunpack.h unsp.c unsp.h aspack.c aspack.h \
- packlibs.c packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h \
- line.c line.h untar.c untar.h unzip.c unzip.h inflate64.c \
- inflate64.h inffixed64.h inflate64_priv.h special.c special.h \
- binhex.c binhex.h is_tar.c is_tar.h tnef.c tnef.h autoit.c \
- autoit.h unarj.c unarj.h nsis/bzlib.c nsis/bzlib_private.h \
+ matcher-bm.h matcher-md5.c matcher-md5.h matcher.c matcher.h \
+ others.c others.h readdb.c readdb.h cvd.c cvd.h dsig.c dsig.h \
+ scanners.c scanners.h textdet.c textdet.h filetypes.c \
+ filetypes.h filetypes_int.h rtf.c rtf.h blob.c blob.h mbox.c \
+ mbox.h message.c message.h table.c table.h text.c text.h \
+ ole2_extract.c ole2_extract.h vba_extract.c vba_extract.h \
+ cltypes.h msexpand.c msexpand.h pe.c pe.h pe_icons.c \
+ pe_icons.h disasm.c disasm.h disasm-common.h disasmpriv.h \
+ upx.c upx.h htmlnorm.c htmlnorm.h chmunpack.c chmunpack.h \
+ rebuildpe.c rebuildpe.h petite.c petite.h wwunpack.c \
+ wwunpack.h unsp.c unsp.h aspack.c aspack.h packlibs.c \
+ packlibs.h fsg.c fsg.h mew.c mew.h upack.c upack.h line.c \
+ line.h untar.c untar.h unzip.c unzip.h inflate64.c inflate64.h \
+ inffixed64.h inflate64_priv.h special.c special.h binhex.c \
+ binhex.h is_tar.c is_tar.h tnef.c tnef.h autoit.c autoit.h \
+ unarj.c unarj.h nsis/bzlib.c nsis/bzlib_private.h \
nsis/nsis_bzlib.h nsis/nulsft.c nsis/nulsft.h nsis/infblock.c \
nsis/nsis_zconf.h nsis/nsis_zlib.h nsis/nsis_zutil.h pdf.c \
pdf.h spin.c spin.h yc.c yc.h elf.c elf.h execs.h sis.c sis.h \
@@ -658,7 +661,8 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
clambc.h cpio.c cpio.h macho.c macho.h ishield.c ishield.h \
type_desc.h bcfeatures.h bytecode_api.c bytecode_api_decl.c \
bytecode_api.h bytecode_api_impl.h bytecode_hooks.h cache.c \
- cache.h $(am__append_7) $(am__append_8)
+ cache.h bytecode_detect.c bytecode_detect.h \
+ builtin_bytecodes.h $(am__append_7) $(am__append_8)
noinst_LTLIBRARIES = libclamav_internal_utils.la libclamav_internal_utils_nothreads.la libclamav_nocxx.la
COMMON_CLEANFILES = version.h version.h.tmp *.gcda *.gcno
@MAINTAINER_MODE_TRUE at BUILT_SOURCES = jsparse/generated/operators.h jsparse/generated/keywords.h jsparse-keywords.gperf
@@ -800,6 +804,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_api.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_api_decl.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_detect.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bytecode_vm.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-bzlib.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-cab.Plo at am__quote@
@@ -830,6 +835,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-macho.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-matcher-ac.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-matcher-bm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-matcher-md5.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-matcher.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-mbox.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamav_la-message.Plo at am__quote@
@@ -927,6 +933,14 @@ libclamav_la-matcher-bm.lo: matcher-bm.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-matcher-bm.lo `test -f 'matcher-bm.c' || echo '$(srcdir)/'`matcher-bm.c
+libclamav_la-matcher-md5.lo: matcher-md5.c
+ at am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-matcher-md5.lo -MD -MP -MF $(DEPDIR)/libclamav_la-matcher-md5.Tpo -c -o libclamav_la-matcher-md5.lo `test -f 'matcher-md5.c' || echo '$(srcdir)/'`matcher-md5.c
+ at am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-matcher-md5.Tpo $(DEPDIR)/libclamav_la-matcher-md5.Plo
+ at am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='matcher-md5.c' object='libclamav_la-matcher-md5.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-matcher-md5.lo `test -f 'matcher-md5.c' || echo '$(srcdir)/'`matcher-md5.c
+
libclamav_la-matcher.lo: matcher.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-matcher.lo -MD -MP -MF $(DEPDIR)/libclamav_la-matcher.Tpo -c -o libclamav_la-matcher.lo `test -f 'matcher.c' || echo '$(srcdir)/'`matcher.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-matcher.Tpo $(DEPDIR)/libclamav_la-matcher.Plo
@@ -1687,6 +1701,14 @@ libclamav_la-cache.lo: cache.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-cache.lo `test -f 'cache.c' || echo '$(srcdir)/'`cache.c
+libclamav_la-bytecode_detect.lo: bytecode_detect.c
+ at am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-bytecode_detect.lo -MD -MP -MF $(DEPDIR)/libclamav_la-bytecode_detect.Tpo -c -o libclamav_la-bytecode_detect.lo `test -f 'bytecode_detect.c' || echo '$(srcdir)/'`bytecode_detect.c
+ at am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-bytecode_detect.Tpo $(DEPDIR)/libclamav_la-bytecode_detect.Plo
+ at am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bytecode_detect.c' object='libclamav_la-bytecode_detect.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-bytecode_detect.lo `test -f 'bytecode_detect.c' || echo '$(srcdir)/'`bytecode_detect.c
+
libclamav_la-bignum.lo: bignum.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-bignum.lo -MD -MP -MF $(DEPDIR)/libclamav_la-bignum.Tpo -c -o libclamav_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-bignum.Tpo $(DEPDIR)/libclamav_la-bignum.Plo
diff --git a/libclamav/autoit.c b/libclamav/autoit.c
index 94cacc1..b67a516 100644
--- a/libclamav/autoit.c
+++ b/libclamav/autoit.c
@@ -38,6 +38,7 @@
#include "others.h"
#include "scanners.h"
#include "autoit.h"
+#include "fmap.h"
/* FIXME: use unicode detection and normalization from edwin */
@@ -175,116 +176,118 @@ static uint32_t getbits(struct UNP *UNP, uint32_t size) {
*********************/
-static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
+static int ea05(cli_ctx *ctx, uint8_t *base, char *tmpd) {
uint8_t b[300], comp;
- uint8_t *buf = b;
uint32_t s, m4sum=0;
int i, ret;
unsigned int files=0;
char tempfile[1024];
struct UNP UNP;
+ fmap_t *map = *ctx->fmap;
- if (cli_readn(desc, buf, 16)!=16)
+ if(!fmap_need_ptr_once(map, base, 16))
return CL_CLEAN;
for (i=0; i<16; i++)
- m4sum += buf[i];
+ m4sum += *base++;
while((ret=cli_checklimits("autoit", ctx, 0, 0, 0))==CL_CLEAN) {
- buf = b;
- if (cli_readn(desc, buf, 8)!=8)
+ if(!fmap_need_ptr_once(map, base, 8))
return CL_CLEAN;
/* MT_decrypt(buf,4,0x16fa); waste of time */
- if((uint32_t)cli_readint32((char *)buf) != 0xceb06dff) {
+ if((uint32_t)cli_readint32(base) != 0xceb06dff) {
cli_dbgmsg("autoit: no FILE magic found, extraction complete\n");
return CL_CLEAN;
}
- s = cli_readint32((char *)buf+4) ^ 0x29bc;
+ s = cli_readint32(base+4) ^ 0x29bc;
if ((int32_t)s<0)
return CL_CLEAN; /* the original code wouldn't seek back here */
+ base += 8;
if(cli_debug_flag && s<sizeof(b)) {
- if (cli_readn(desc, buf, s)!=(int)s)
+ if (!fmap_need_ptr_once(map, base, s))
return CL_CLEAN;
- buf[s]='\0';
- MT_decrypt(buf,s,s+0xa25e);
- cli_dbgmsg("autoit: magic string '%s'\n", buf);
- } else {
- lseek(desc, s, SEEK_CUR);
+ memcpy(b, base, s);
+ MT_decrypt(b,s,s+0xa25e);
+ b[s]='\0';
+ cli_dbgmsg("autoit: magic string '%s'\n", b);
}
+ base += s;
- if (cli_readn(desc, buf, 4)!=4)
+ if (!fmap_need_ptr_once(map, base, 4))
return CL_CLEAN;
- s = cli_readint32((char *)buf) ^ 0x29ac;
+ s = cli_readint32(base) ^ 0x29ac;
if ((int32_t)s<0)
return CL_CLEAN; /* the original code wouldn't seek back here */
+ base += 4;
if (cli_debug_flag && s<sizeof(b)) {
- if (cli_readn(desc, buf, s)!=(int)s)
+ if (!fmap_need_ptr_once(map, base, s))
return CL_CLEAN;
- MT_decrypt(buf,s,s+0xf25e);
- buf[s]='\0';
- cli_dbgmsg("autoit: original filename '%s'\n", buf);
- } else {
- lseek(desc, s, SEEK_CUR);
+ memcpy(b, base, s);
+ MT_decrypt(b,s,s+0xf25e);
+ b[s]='\0';
+ cli_dbgmsg("autoit: original filename '%s'\n", b);
}
+ base += s;
- if (cli_readn(desc, buf, 13)!=13)
+ if (!fmap_need_ptr_once(map, base, 13))
return CL_CLEAN;
- comp = *buf;
- UNP.csize = cli_readint32((char *)buf+1) ^ 0x45aa;
+ comp = *base;
+ UNP.csize = cli_readint32(base+1) ^ 0x45aa;
if ((int32_t)UNP.csize<0) {
cli_dbgmsg("autoit: bad file size - giving up\n");
return CL_CLEAN;
}
- lseek(desc, 16, SEEK_CUR);
-
if(!UNP.csize) {
cli_dbgmsg("autoit: skipping empty file\n");
+ base += 13 + 16;
continue;
}
cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize);
- cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x45aa);
- cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xc3d2);
+ cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32(base+5) ^ 0x45aa);
+ cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32(base+9) ^ 0xc3d2);
+
+ base += 13 + 16;
-
if(cli_checklimits("autoit", ctx, UNP.csize, 0, 0)!=CL_CLEAN) {
- lseek(desc, UNP.csize, SEEK_CUR);
+ base += UNP.csize;
continue;
}
- if (!(buf = cli_malloc(UNP.csize)))
+ if (!(UNP.inputbuf = cli_malloc(UNP.csize)))
return CL_EMEM;
- if (cli_readn(desc, buf, UNP.csize)!=(int)UNP.csize) {
+ if (!fmap_need_ptr_once(map, base, UNP.csize)) {
cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n");
- free(buf);
+ free(UNP.inputbuf);
return CL_CLEAN;
}
- MT_decrypt(buf,UNP.csize,0x22af+m4sum);
+ memcpy(UNP.inputbuf, base, UNP.csize);
+ base += UNP.csize;
+ MT_decrypt(UNP.inputbuf,UNP.csize,0x22af+m4sum);
if (comp == 1) {
cli_dbgmsg("autoit: file is compressed\n");
- if (cli_readint32((char *)buf)!=0x35304145) {
+ if (cli_readint32(UNP.inputbuf)!=0x35304145) {
cli_dbgmsg("autoit: bad magic or unsupported version\n");
- free(buf);
+ free(UNP.inputbuf);
continue;
}
- if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4))))
+ if(!(UNP.usize = be32_to_host(*(uint32_t *)(UNP.inputbuf+4))))
UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */
if(cli_checklimits("autoit", ctx, UNP.usize, 0, 0)!=CL_CLEAN) {
- free(buf);
+ free(UNP.inputbuf);
continue;
}
if (!(UNP.outputbuf = cli_malloc(UNP.usize))) {
- free(buf);
+ free(UNP.inputbuf);
return CL_EMEM;
}
cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize);
- UNP.inputbuf = buf;
UNP.cur_output = 0;
UNP.cur_input = 8;
UNP.bitmap.full = 0;
@@ -328,7 +331,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
}
}
- free(buf);
+ free(UNP.inputbuf);
/* Sometimes the autoit exe is in turn packed/lamed with a runtime compressor and similar shit.
* However, since the autoit script doesn't compress a second time very well, chances are we're
* still able to match the headers and unpack something (see sample 0811129)
@@ -340,7 +343,7 @@ static int ea05(int desc, cli_ctx *ctx, char *tmpd) {
cli_dbgmsg("autoit: decompression error - partial file may exist\n");
} else {
cli_dbgmsg("autoit: file is not compressed\n");
- UNP.outputbuf = buf;
+ UNP.outputbuf = UNP.inputbuf;
UNP.usize = UNP.csize;
}
@@ -469,9 +472,8 @@ static void LAME_decrypt (uint8_t *cypher, uint32_t size, uint16_t seed) {
autoit3 EA06 handler
*********************/
-static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
- uint8_t b[600], comp, script;
- uint8_t *buf;
+static int ea06(cli_ctx *ctx, uint8_t *base, char *tmpd) {
+ uint8_t b[600], comp, script, *buf;
uint32_t s;
int i, ret;
unsigned int files=0;
@@ -479,113 +481,119 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
const char prefixes[] = { '\0', '\0', '@', '$', '\0', '.', '"', '#' };
const char *opers[] = { ",", "=", ">", "<", "<>", ">=", "<=", "(", ")", "+", "-", "/", "*", "&", "[", "]", "==", "^", "+=", "-=", "/=", "*=", "&=" };
struct UNP UNP;
+ fmap_t *map = *ctx->fmap;
+
/* Useless due to a bug in CRC calculation - LMAO!!1 */
/* if (cli_readn(desc, buf, 24)!=24) */
/* return CL_CLEAN; */
/* LAME_decrypt(buf, 0x10, 0x99f2); */
/* buf+=0x10; */
- lseek(desc, 16, SEEK_CUR); /* for now we just skip the garbage */
+ base += 16; /* for now we just skip the garbage */
while((ret=cli_checklimits("cli_autoit", ctx, 0, 0, 0))==CL_CLEAN) {
- buf = b;
- if (cli_readn(desc, buf, 8)!=8)
+ if(!fmap_need_ptr_once(map, base, 8))
return CL_CLEAN;
/* LAME_decrypt(buf, 4, 0x18ee); waste of time */
- if(cli_readint32((char *)buf) != 0x52ca436b) {
+ if(cli_readint32(base) != 0x52ca436b) {
cli_dbgmsg("autoit: no FILE magic found, giving up\n");
return CL_CLEAN;
}
script = 0;
- s = cli_readint32((char *)buf+4) ^ 0xadbc;
+ s = cli_readint32(base+4) ^ 0xadbc;
if ((int32_t)(s*2)<0)
return CL_CLEAN; /* the original code wouldn't seek back here */
- if(s<300) {
- if (cli_readn(desc, buf, s*2)!=(int)s*2)
+ base += 8;
+ if(s < sizeof(b) / 2) {
+ if(!fmap_need_ptr_once(map, base, s*2))
return CL_CLEAN;
- LAME_decrypt(buf,s*2,s+0xb33f);
- u2a(buf,s*2);
- cli_dbgmsg("autoit: magic string '%s'\n", buf);
- if (s==19 && !memcmp(">>>AUTOIT SCRIPT<<<", buf, 19))
+ memcpy(b, base, s*2);
+ LAME_decrypt(b,s*2,s+0xb33f);
+ u2a(b,s*2);
+ cli_dbgmsg("autoit: magic string '%s'\n", b);
+ if (s==19 && !memcmp(">>>AUTOIT SCRIPT<<<", b, 19))
script = 1;
} else {
cli_dbgmsg("autoit: magic string too long to print\n");
- lseek(desc, s*2, SEEK_CUR);
}
+ base += s*2;
- if (cli_readn(desc, buf, 4)!=4)
+ if (!fmap_need_ptr_once(map, base, 4))
return CL_CLEAN;
- s = cli_readint32((char *)buf) ^ 0xf820;
+ s = cli_readint32(base) ^ 0xf820;
if ((int32_t)(s*2)<0)
return CL_CLEAN; /* the original code wouldn't seek back here */
- if(cli_debug_flag && s<300) {
- if (cli_readn(desc, buf, s*2)!=(int)s*2)
+ base += 4;
+ if(cli_debug_flag && s<sizeof(b) / 2) {
+ if(!fmap_need_ptr_once(map, base, s*2))
return CL_CLEAN;
- LAME_decrypt(buf,s*2,s+0xf479);
- buf[s*2]='\0'; buf[s*2+1]='\0';
- u2a(buf,s*2);
- cli_dbgmsg("autoit: original filename '%s'\n", buf);
- } else {
- lseek(desc, s*2, SEEK_CUR);
+ memcpy(b, base, s*2);
+ LAME_decrypt(b,s*2,s+0xf479);
+ b[s*2]='\0'; b[s*2+1]='\0';
+ u2a(b,s*2);
+ cli_dbgmsg("autoit: original filename '%s'\n", b);
}
+ base += s*2;
- if (cli_readn(desc, buf, 13)!=13)
+ if(!fmap_need_ptr_once(map, base, 13))
return CL_CLEAN;
- comp = *buf;
- UNP.csize = cli_readint32((char *)buf+1) ^ 0x87bc;
+ comp = *base;
+ UNP.csize = cli_readint32(base+1) ^ 0x87bc;
if ((int32_t)UNP.csize<0) {
cli_dbgmsg("autoit: bad file size - giving up\n");
return CL_CLEAN;
}
- lseek(desc, 16, SEEK_CUR);
-
if(!UNP.csize) {
cli_dbgmsg("autoit: skipping empty file\n");
+ base += 13 + 16;
continue;
}
cli_dbgmsg("autoit: compressed size: %x\n", UNP.csize);
- cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32((char *)buf+5) ^ 0x87bc);
- cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32((char *)buf+9) ^ 0xa685);
+ cli_dbgmsg("autoit: advertised uncompressed size %x\n", cli_readint32(base+5) ^ 0x87bc);
+ cli_dbgmsg("autoit: ref chksum: %x\n", cli_readint32(base+9) ^ 0xa685);
+
+ base += 13 + 16;
if(cli_checklimits("autoit", ctx, UNP.csize, 0, 0)!=CL_CLEAN) {
- lseek(desc, UNP.csize, SEEK_CUR);
+ base += UNP.csize;
continue;
}
files++;
- if (!(buf = cli_malloc(UNP.csize)))
+ if (!(UNP.inputbuf = cli_malloc(UNP.csize)))
return CL_EMEM;
- if (cli_readn(desc, buf, UNP.csize)!=(int)UNP.csize) {
+ if (!fmap_need_ptr_once(map, base, UNP.csize)) {
cli_dbgmsg("autoit: failed to read compressed stream. broken/truncated file?\n");
- free(buf);
+ free(UNP.inputbuf);
return CL_CLEAN;
}
- LAME_decrypt(buf,UNP.csize,0x2477 /* + m4sum (broken by design) */ );
+ memcpy(UNP.inputbuf, base, UNP.csize);
+ base += UNP.csize;
+ LAME_decrypt(UNP.inputbuf,UNP.csize,0x2477 /* + m4sum (broken by design) */ );
if (comp == 1) {
cli_dbgmsg("autoit: file is compressed\n");
- if (cli_readint32((char *)buf)!=0x36304145) {
+ if (cli_readint32(UNP.inputbuf)!=0x36304145) {
cli_dbgmsg("autoit: bad magic or unsupported version\n");
- free(buf);
+ free(UNP.inputbuf);
continue;
}
- if(!(UNP.usize = be32_to_host(*(uint32_t *)(buf+4))))
+ if(!(UNP.usize = be32_to_host(*(uint32_t *)(UNP.inputbuf+4))))
UNP.usize = UNP.csize; /* only a specifically crafted or badly corrupted sample should land here */
if(cli_checklimits("autoit", ctx, UNP.usize, 0, 0)!=CL_CLEAN) {
- free(buf);
+ free(UNP.inputbuf);
continue;
}
if (!(UNP.outputbuf = cli_malloc(UNP.usize))) {
- free(buf);
+ free(UNP.inputbuf);
return CL_EMEM;
}
cli_dbgmsg("autoit: uncompressed size again: %x\n", UNP.usize);
- UNP.inputbuf = buf;
UNP.cur_output = 0;
UNP.cur_input = 8;
UNP.bitmap.full = 0;
@@ -629,12 +637,12 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
}
}
- free(buf);
+ free(UNP.inputbuf);
if (UNP.error)
cli_dbgmsg("autoit: decompression error - partial file may exist\n");
} else {
cli_dbgmsg("autoit: file is not compressed\n");
- UNP.outputbuf = buf;
+ UNP.outputbuf = UNP.inputbuf;
UNP.usize = UNP.csize;
}
@@ -897,17 +905,17 @@ static int ea06(int desc, cli_ctx *ctx, char *tmpd) {
autoit3 wrapper
*********************/
-int cli_scanautoit(int desc, cli_ctx *ctx, off_t offset) {
- uint8_t version;
+int cli_scanautoit(cli_ctx *ctx, off_t offset) {
+ uint8_t *version;
int r;
char *tmpd;
-
- lseek(desc, offset, SEEK_SET);
- if (cli_readn(desc, &version, 1)!=1)
- return CL_EREAD;
+ fmap_t *map = *ctx->fmap;
cli_dbgmsg("in scanautoit()\n");
+ if(!(version = fmap_need_off_once(map, offset, sizeof(*version))))
+ return CL_EREAD;
+
if (!(tmpd = cli_gentemp(ctx->engine->tmpdir)))
return CL_ETMPDIR;
if (mkdir(tmpd, 0700)) {
@@ -918,13 +926,13 @@ int cli_scanautoit(int desc, cli_ctx *ctx, off_t offset) {
if (ctx->engine->keeptmp)
cli_dbgmsg("autoit: Extracting files to %s\n", tmpd);
- switch(version) {
+ switch(*version) {
case 0x35:
- r = ea05(desc, ctx, tmpd);
+ r = ea05(ctx, version + 1, tmpd);
break;
case 0x36:
#ifdef FPU_WORDS_BIGENDIAN
- r = ea06(desc, ctx, tmpd);
+ r = ea06(ctx, version + 1, tmpd);
#else
cli_dbgmsg("autoit: EA06 support not available\n");
r = CL_CLEAN;
diff --git a/libclamav/autoit.h b/libclamav/autoit.h
index 912e772..1b0256d 100644
--- a/libclamav/autoit.h
+++ b/libclamav/autoit.h
@@ -22,5 +22,5 @@
#define __AUTOIT_H
#include "others.h"
-int cli_scanautoit(int desc, cli_ctx *ctx, off_t offset);
+int cli_scanautoit(cli_ctx *ctx, off_t offset);
#endif
diff --git a/libclamav/builtin_bytecodes.h b/libclamav/builtin_bytecodes.h
new file mode 100644
index 0000000..34c43c8
--- /dev/null
+++ b/libclamav/builtin_bytecodes.h
@@ -0,0 +1,198 @@
+/*
+ * Builtin ClamAV bytecodes.
+ *
+ * Copyright (C) 2010 Sourcefire, Inc.
+ *
+ * Authors: Török Edvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef BUILTIN_BYTECODES_H
+#define BUILTIN_BYTECODES_H
+
+/* bytecode run on startup with interpreter to determine if JIT/bytecode should
+ * be disabled. It also runs a minimal self-check.
+ * There can only be one such bytecode, if there is none this is used as
+ * fallback.
+ * Usually bytecode.cvd will contain this bytecode */
+
+static const char* builtin_bc_startup = "ClamBCafheaie`fld|afefdfggifnf```aa```|biacflfafmfbfcfmb`cnbacacmbacdcicmbgfhcachcgcbchccf``bkbaap`clamcoincidencejb:1378\n"
+"\n"
+"Teddaaahdabahdacahdadahdaeahdafahdagahebjfebidebifebhfebgfebffebedebefebdfebcfebadcbgab`bb`bb`bb`bb`bb`bb`bbbfbbfbbfbbfbbfbbfbbfahahahahahahahahahebgeebbfaaaaaaaab`baabb`bb`baacb`bbadb`baacb`bbheb`baacb`bb`bb`baadb`bbadb`bb`baadb`bbadbadb`bdbadahdbkaahdbbcahdbibahdb`eahdbddahdbodahdbdaahdbnbah\n"
+"Ebjdaibcdbke|bcaefnfgfifnfefoedfcfofnfffoelfeffgeflf``bbdbke|bkaefnfgfifnfefoeffegnfcfdgifofnfaflfifdgigoelfeffgeflf``agble|baadfefbfeggfoe`gbgifnfdgoeegifnfdg``bcable|afdgefcgdgbc``afbme|b`adfefbfeggfoe`gbgifnfdgoecgdgbg``bhdbne|b`agfefdgoeefnffgifbgofnfmfefnfdg``aaboe|afdgefcgdgac``bidb`f|bdadfifcgafbflfefoebfigdgefcfofdfefoeifff``bjdb`f|aodfifcgafbflfefoejfifdgoeifff``\n"
+"G`bha`@`b`aAa`bjfBifBkeBccBdcBmeBhcBfcB`bBdfBefBdgBefBcfBdgBefBdfBlbB`bBjdBidBdeB`bBnfBefBefBdfBcgB`bB`gBefBnfBdgBifBegBmfB`bBofBbgB`bBbfBefBdgBdgBefBbg@`bidBifBccBhcBfc@`bidBifBdcBhcBfc@`bifBbeBgeBheB`bBmfBafB`gB`gBifBnfBgfB`bBdfBefBnfBifBefBdfBnb@`bhfBneBceBedBldBifBnfBegBhgB`bBifBcgB`bB`gBbgBefBfgBefBnfBdgBifBnfBgfB`bBgbBefBhgBefBcfBmfBefBmfBgbB`bBafBcfBcfBefBcgBcgBnbAjBbeBegBnfB`bB`bBgbBcgBefBdgBcgBefBbfBofBofBlfB`bBmbB`eB`bBcfBlfBafBmfBdfBoeBegBcgBefBoeBjfBifBdgB`bBofBnfBgbBnb@`bgfBneB`eBafBheB`bBifBcgB`bB`gBbgBefBfgBefBnfBdgBifBnfBgfB`bBgbBmfB`gBbgBofBdgBefBcfBdgBgbB`bBafBcfBcfBefBcgBcgBnbAjBbeBegBnfB`bBgbB`gBafBhgBcfBdgBlfB`bBmbBcfBmfB`bBlcBefBhgBefBcfBegBdgBafBbfBlfBefBncBgb@`bffBneBbeBgeBheB`bBmfBafB`gB`gBifBnfBgfB`bBdfBefBnfBifBefBdfB`bBffBofBbgB`bBegBnfBkfBnfBofBggBnfB`bBbgBefBafBcgBofBnfBnbB`eBlfBefBafBcgBefB`bBbgBefB`gBofBbgBdgB`bBdgBofB`bBhfBdgBdgB`gBjcBobBobBbfBegBgfBcgBnbBcfBlfBafBmfBafBfgBnbBnfBefBdgAj@`bed@`befBcgBdgBafBbgBdgBegB`gBjcB`bBbfBigBdgBefBcfBofBdfBefB`bBefBhgBefBcfBegBdgBifBofBnfB`bBifBnfB`bBafBegBdgBofB`bBmfBofBdfBef@`bdfBcgBdgBafBbgBdgBegB`gBjcB`bBbfBigBdgBefBcfBofBdfBefB`bBefBhgBefBcfBegBdgBifBofBnfB`bBggBifBdgBhfB`bBifBnfBdgBefBbgB`gBbgBefBdgBefBbgB`bBofBnfBlfBig@`bcfBcgBdgBafBbgBdgBegB`gBjcB`bBbfBigBdgBefBcfBofBdfBefB`bBdfBifBcgBafBbfBlfBefBdf@`bad at Ab`bad at Ac`bad at Ad`bad at Ae`bad at Af`bad at Ag`bad at Ah`bad at Ai`bad at Aj`bad at Ak`bad at Al`\n"
+"A`b`bLbahb`bab`babgeab`b`bad`ah`aa`bad`ah`aa`bie`bad`b`b`aa`b`b`aa`b`b`b`b`bad`ah`b`b`b`b`aa`b`b`bad`ah`aa`ah`b`b`b`b`aa`b`b`b`b`aa`b`b`b`b`bad`ah`aa`bad`ah`aa`b`b`aa`b`b`b`b`aa`aa`aa`aa`aa`b`b`b`b`b`b`ah`aa`bcd`b`b`aa`bcd`b`b`bcd`b`b`aa`b`b`aa`b`b`b`b`aa`bad`ah`b`b`aa`b`b`aa`bad`ah`b`b`b`b`bad`ah`b`b`b`b`bad`ah`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`b`bad`ah`b`b`b`b`bcd`b`b`b`b`b`b`bad`ah`b`b`b`b`bcd`b`b`b`b`bcd`b`b`aa`b`b`bcd`b`b`aa`b`b`bcd`b`b`aa`b`b`b`b`aa`b`b`b`b`aa`b`b`b`b`Fb`kbib\n"
+"Bb`bacabbbhdabClnadbadaddbbheabBdadahaegbadaaafeaahae at aTaaafb`aaa\n"
+"BbadagdbbheabB`adahahgbagaaaieaahahAaaTaaaiabae\n"
+"BbieajdbbheabAidbadakdbbieaj at db`balkbakAn`Addaaameab`bal at db`b`bbAadaaTaaamadac\n"
+"Bb`bankbakAo`Addaaaoeab`ban at db`baa`aaob`b`bbaaaaTbaad\n"
+"Bb`bb`abbaab`ab`bbaaabcbjdAm`@db`aTbaae\n"
+"BbadbbadbbheabBeadahbcagbbbab`bbda`abcab`bbeak`bdaAadaabfaeab`bbea at dTaabfaafal\n"
+"Bb`bbgaabcbjdB`a`@dAadbadbhadbbheabBaadahbiagbbhaaabjaeaahbiaAjaTaabjaagb`a\n"
+"Bahbkagbbbab`bbla`abkab`bbmak`blaAbdaabnaeab`bbma at dTaabnaaiah\n"
+"Bb`bboaabcbjdBaa`@dAadTbab`a\n"
+"Bb`bb`bk`blaAhdaababeab`bb`b at dTaababakaj\n"
+"Bb`bbbbabcbjdBba`@dAadTbab`a\n"
+"Bb`bbcbabcbjdBca`@dAadTbab`a\n"
+"BbadbdbdbbheabBaadahbebgbbdbaabfbeaahbebAjaTaabfbanam\n"
+"BbadbgbdbbheabBbadahbhbgbbgbaabibeaahbhbAfaTaabibanb`a\n"
+"Bb`bbjbk`bdaB`adaabkbeab`bbjb at dTaabkbb`aao\n"
+"Bb`bblbabcbjdBba`@dAadTbab`a\n"
+"Bb`bbmbabcbidBda`@d at daabnbnab`bbmbAadTaabnbbdabaa\n"
+"Baabobnab`bbmbAbdTaabobbcabba\n"
+"Baab`ceab`bbmbAbdTaab`cbgabha\n"
+"Baabaceab`bbmbAadTaabacbfabha\n"
+"Baabbceab`bbmb at dTaabbcbeabha\n"
+"Bb`bbccabbafBea`@dTbabha\n"
+"Bb`bbdcabbafBfa`@dTbabha\n"
+"Bb`bbecabbafBga`@dTbabha\n"
+"Bahbfcgbadaabgceaahbfc at aTaabgcbjabia\n"
+"BbcdbhcdbbheabAddb`bbicgbbhcaabjceab`bbic at db`b`bbEamjnmd`Taabjcbhbbja\n"
+"BbcdbkcdbbheabAfdb`bblcgbbkcbcdbmcdbbheabAedb`bbncgbbmcaabociab`bblcbncb`b`bbEbmjnmd`Taabocbhbbka\n"
+"Bb`bb`dab`bbdaabadeab`bbncb`db`b`bbEcmjnmd`Taabadblabhb\n"
+"Bb`bbbdgbbkcb`bbcdab`bcdaabddeab`bbbdbcdb`b`bbEdmjnmd`Taabddbmabhb\n"
+"BbadbeddbbheabAndahbfdgbbedb`bbgd`abfdaabhdlbb`bbid`abhdaabjdeab`bbgdbidb`b`bbEemjnmd`Taabjdbnabhb\n"
+"BbadbkddbbheabBaadahbldgbbkdb`bbmd`abldb`bbndh`bmdBhadbadboddbbheabB`adahb`egbbodb`bbae`ab`eb`bbbeh`baeBdadbadbcedbbheabBcadahbdegbbceb`bbee`abdeb`bbfeh`beeB`adb`bbgegbbmcb`bbheh`bgeAhdb`bbiegbbkcb`bbjel`bbebndb`bbkel`bjebheb`bblel`bkebieb`bbmel`blebfeb`bbneh`bgdBladbadboedbbheabAodahb`fgbboeb`bbaf`ab`fb`bbbfh`bafBhadbcdbcfdbbheabAddb`bbdfgbbcfb`bbefl`bdfbneb`bbffl`befbbfbadbgfdbbheabBeadahbhfgbbgfb`bbif`abhfb`bbjfh`bifBhadbcdbkfdbbheabAcdb`bblfgbbkfb`bbmfl`bjfblfbcdbnfdbbheab at db`bbofgbbnfaab`geab`bbmebofTaab`gb`bboa\n"
+"Bb`bbagabaagbmeTcab`bEfmjnmd\n"
+"BbcdbbgdbbheabAadb`bbcggbbbgaabdgeab`bbffbcgTaabdgbbbbab\n"
+"Bb`bbegabaagbffTcab`bEgmjnmd\n"
+"BbcdbfgdbbheabAbdb`bbgggbbfgaabhgeab`bbmfbggTaabhgbdbbcb\n"
+"Bb`bbigabaagbmfTcab`bEhmjnmd\n"
+"Bb`bbjgabbaaHonnkm``odHm``oonnkdaabkgeab`bbjgHhgfedcbadTaabkgbfbbeb\n"
+"Bb`bblgabaagbjgTcab`bEimjnmd\n"
+"Bb`bbmgababcaDm``odaabngeab`bbmgDo``mdb`b`bbHnejkjgjmd`Taabngbhbbgb\n"
+"Bb`bbogabaagbmgTcab`bF`amjnmd\n"
+"Bb`bb`hbb`b`hTcab`bb`hE\n"
+;
+/* source-code for builtin_bc_startup: */
+#if 0
+const uint16_t __clambc_kind = BC_STARTUP;
+int entrypoint()
+{
+ // Whole platform specific bugs can be disabled with check_platform,
+ // see clamscan --debug for meaning of bits.
+ // For example:
+ //disable_jit_if("Pax mprotect on, with RWX", 0,
+ // check_platform(0x0affffff, 0xffffffff, 0x19));
+
+ struct cli_environment env;
+ get_environment(&env, sizeof(env));
+ if (env.has_jit_compiled) {
+ /* CPU checks */
+ switch (env.arch) {
+ case arch_i386:
+ disable_jit_if("i[34]86 detected, JIT needs pentium or better",0,
+ !memcmp(env.cpu,"i386",4) ||
+ !memcmp(env.cpu,"i486",4));
+ break;
+ default:
+ break;
+ }
+
+ /* RWX checks */
+ if (!(env.os_features & (1 << feature_map_rwx))) {
+ disable_jit_if("RWX mapping denied.", 0, 1);
+ if (env.os_category == os_linux) {
+ if (env.os_features & (1 << feature_selinux))
+ /* all SELinux versions deny RWX mapping when policy says so */
+ disable_jit_if("^SELinux is preventing 'execmem' access.\n"
+ "Run 'setsebool -P clamd_use_jit on'.", 0, 1);
+ else if (env.os_features & (1 << feature_pax))
+ /* recent versions of PaX deny RWX mapping */
+ disable_jit_if("^PaX is preventing 'mprotect' access.\n"
+ "Run 'paxctl -cm <executable>'", 0, 1);
+ else
+ /* RWX mapping got denied but apparently not due to SELinux/PaX */
+ disable_jit_if("^RWX mapping denied for unknown reason."
+ "Please report to http://bugs.clamav.net\n", 0, 1);
+ }
+ } else {
+ if ((env.os_category == os_linux || env.os == llvm_os_Linux) &&
+ (env.os_features & (1 << feature_pax_mprotect))) {
+ /* older versions of PaX allow RWX mapping but silently degrade it to RW
+ * mapping and kill the program if it tries to execute. */
+ disable_jit_if("^PaX is preventing 'mprotect' access.\n"
+ "Run 'paxctl -cm <executable>'", 0, 1);
+ }
+ }
+ }
+ int s = disable_bytecode_if("",0,0);
+ switch (s) {
+ case 0:
+ debug("startup: bytecode execution in auto mode");
+ break;
+ case 1:
+ debug("startup: bytecode execution with interpreter only");
+ break;
+ case 2:
+ debug("startup: bytecode disabled");
+ break;
+ }
+
+ /* check that the OS information is consistent */
+ /* JIT == C++ code compiled */
+ if (env.has_jit_compiled && !env.cpp_version) {
+ return 0xdead1;
+ }
+ if (env.dconf_level < env.functionality_level) {
+ return 0xdead2;
+ }
+ if (env.functionality_level != engine_functionality_level()) {
+ return 0xdead3;
+ }
+ if (env.dconf_level != engine_dconf_level()) {
+ return 0xdead4;
+ }
+ if (env.big_endian != __is_bigendian()) {
+ return 0xdead5;
+ }
+
+ uint32_t a = (env.os_category << 24) | (env.arch << 20) |
+ (env.compiler << 16) | (env.functionality_level << 8) |
+ (env.dconf_level);
+ uint32_t b = (env.big_endian << 28) | (env.sizeof_ptr << 24) |
+ env.cpp_version;
+ uint32_t c = (env.os_features << 24) | env.c_version;
+ if (a != env.platform_id_a) {
+ debug_print_uint(a);
+ return 0xdead6;
+ }
+ if (b != env.platform_id_b) {
+ debug_print_uint(b);
+ return 0xdead7;
+ }
+ if (c != env.platform_id_c) {
+ debug_print_uint(c);
+ return 0xdead8;
+ }
+ c = test1(0xf00dbeef, 0xbeeff00d);
+ if (c != 0x12345678) {
+ debug_print_uint(c);
+ return 0xdead9;
+ }
+ c = test2(0xf00d);
+ if (c != 0xd00f) {
+ debug_print_uint(c);
+ return 0xdead10;
+ }
+
+ /* magic number to tell libclamav that selftest succeeded */
+ return 0xda7aba5e;
+}
+
+
+#endif
+#endif
diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c
index 5c32955..1d31544 100644
--- a/libclamav/bytecode.c
+++ b/libclamav/bytecode.c
@@ -32,10 +32,12 @@
#include "pe.h"
#include "bytecode.h"
#include "bytecode_priv.h"
+#include "bytecode_detect.h"
#include "readdb.h"
#include "scanners.h"
#include "bytecode_api.h"
#include "bytecode_api_impl.h"
+#include "builtin_bytecodes.h"
#include <string.h>
/* dummy values */
@@ -147,10 +149,10 @@ static int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
snprintf(fullname, 1024, "%s"PATHSEP"javascript", ctx->jsnormdir);
fd = open(fullname, O_RDONLY|O_BINARY);
if(fd >= 0) {
- ret = cli_scandesc(fd, cctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, cctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
if (ret == CL_CLEAN) {
lseek(fd, 0, SEEK_SET);
- ret = cli_scandesc(fd, cctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, cctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
}
close(fd);
}
@@ -213,7 +215,6 @@ static int cli_bytecode_context_reset(struct cli_bc_ctx *ctx)
int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
{
- cli_ctx *cctx = (cli_ctx*)ctx->ctx;
cli_bytecode_context_reset(ctx);
memset(ctx, 0, sizeof(*ctx));
return CL_SUCCESS;
@@ -221,6 +222,9 @@ int cli_bytecode_context_clear(struct cli_bc_ctx *ctx)
static unsigned typesize(const struct cli_bc *bc, uint16_t type)
{
+ struct cli_bc_type *ty;
+ unsigned j;
+
type &= 0x7fff;
if (!type)
return 0;
@@ -232,7 +236,25 @@ static unsigned typesize(const struct cli_bc *bc, uint16_t type)
return 4;
if (type <= 64)
return 8;
- return bc->types[type-65].size;
+ ty = &bc->types[type-65];
+ if (ty->size)
+ return ty->size;
+ switch (ty->kind) {
+ case 2:
+ case 3:
+ for (j=0;j<ty->numElements;j++)
+ ty->size += typesize(bc, ty->containedTypes[j]);
+ break;
+ case 4:
+ ty->size = ty->numElements * typesize(bc, ty->containedTypes[0]);
+ break;
+ default:
+ break;
+ }
+ if (!ty->size && ty->kind != DFunctionType) {
+ cli_warnmsg("type %d size is 0\n", type-65);
+ }
+ return ty->size;
}
static unsigned typealign(const struct cli_bc *bc, uint16_t type)
@@ -264,6 +286,10 @@ int cli_bytecode_context_setfuncid(struct cli_bc_ctx *ctx, const struct cli_bc *
return CL_EMEM;
}
ctx->opsizes = cli_malloc(sizeof(*ctx->opsizes)*func->numArgs);
+ if (!ctx->opsizes) {
+ cli_errmsg("bytecode: error allocating memory for opsizes\n");
+ return CL_EMEM;
+ }
for (i=0;i<func->numArgs;i++) {
unsigned al = typealign(bc, func->types[i]);
s = (s+al-1)&~(al-1);
@@ -742,7 +768,8 @@ static int parseTypes(struct cli_bc *bc, unsigned char *buffer)
return CL_EMALFDB;
}
if (t == 5) {
- ty->size = ty->align = sizeof(void*);
+ /* for interpreter, pointers 64-bit there */
+ ty->size = ty->align = 8;
} else {
ty->size = ty->numElements*typesize(bc, ty->containedTypes[0]);
ty->align = typealign(bc, ty->containedTypes[0]);
@@ -1055,10 +1082,14 @@ static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *bu
return CL_EMALFDB;
}
all_locals = func->numArgs + func->numLocals;
- func->types = cli_calloc(all_locals, sizeof(*func->types));
- if (!func->types) {
- cli_errmsg("Out of memory allocating function arguments\n");
- return CL_EMEM;
+ if (!all_locals) {
+ func->types = NULL;
+ } else {
+ func->types = cli_calloc(all_locals, sizeof(*func->types));
+ if (!func->types) {
+ cli_errmsg("Out of memory allocating function arguments\n");
+ return CL_EMEM;
+ }
}
for (i=0;i<all_locals;i++) {
func->types[i] = readNumber(buffer, &offset, len, &ok);
@@ -1188,10 +1219,14 @@ static int parseBB(struct cli_bc *bc, unsigned func, unsigned bb, unsigned char
if (ok) {
inst.u.ops.numOps = numOp;
inst.u.ops.opsizes=NULL;
- inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops));
- if (!inst.u.ops.ops) {
- cli_errmsg("Out of memory allocating operands\n");
- return CL_EMEM;
+ if (!numOp) {
+ inst.u.ops.ops = NULL;
+ } else {
+ inst.u.ops.ops = cli_calloc(numOp, sizeof(*inst.u.ops.ops));
+ if (!inst.u.ops.ops) {
+ cli_errmsg("Out of memory allocating operands\n");
+ return CL_EMEM;
+ }
}
if (inst.opcode == OP_BC_CALL_DIRECT)
inst.u.ops.funcid = readFuncID(bc, buffer, &offset, len, &ok);
@@ -1520,6 +1555,11 @@ int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, stru
cli_errmsg("bytecode has to be prepared either for interpreter or JIT!\n");
return CL_EARG;
}
+ if (bc->state == bc_disabled) {
+ cli_dbgmsg("bytecode triggered but running bytecodes is disabled\n");
+ return CL_SUCCESS;
+ }
+ ctx->env = &bcs->env;
context_safe(ctx);
if (bc->state == bc_interp) {
memset(&func, 0, sizeof(func));
@@ -1608,6 +1648,7 @@ void cli_bytecode_destroy(struct cli_bc *bc)
cli_bitset_free(bc->uses_apis);
free(bc->lsig);
free(bc->globalBytes);
+ memset(bc, 0, sizeof(*bc));
}
#define MAP(val) do { operand_t o = val; \
@@ -1659,6 +1700,39 @@ static inline int get_geptypesize(const struct cli_bc *bc, uint16_t tid)
return typesize(bc, ty->containedTypes[0]);
}
+static int calc_gepz(struct cli_bc *bc, struct cli_bc_func *func, uint16_t tid, operand_t op)
+{
+ unsigned off = 0, i;
+ uint32_t *gepoff;
+ const struct cli_bc_type *ty;
+ if (tid >= bc->num_types + 65) {
+ cli_errmsg("bytecode: typeid out of range %u >= %u\n", tid, bc->num_types);
+ return -1;
+ }
+ if (tid <= 65) {
+ cli_errmsg("bytecode: invalid type for gep (%u)\n", tid);
+ return -1;
+ }
+ ty = &bc->types[tid - 65];
+ if (ty->kind != DPointerType || ty->containedTypes[0] < 65) {
+ cli_errmsg("bytecode: invalid gep type, must be pointer to nonint: %u\n", tid);
+ return -1;
+ }
+ ty = &bc->types[ty->containedTypes[0] - 65];
+ if (ty->kind != DStructType && ty->kind != DPackedStructType)
+ return 0;
+ gepoff = (uint32_t*)&func->constants[op - func->numValues];
+ if (*gepoff >= ty->numElements) {
+ cli_errmsg("bytecode: gep offset out of range: %d >= %d\n",(uint32_t)*gepoff, ty->numElements);
+ return -1;
+ }
+ for (i=0;i<*gepoff;i++) {
+ off += typesize(bc, ty->containedTypes[i]);
+ }
+ *gepoff = off;
+ return 1;
+}
+
static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
{
unsigned i, j, k;
@@ -1755,6 +1829,7 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
map[j] = bcfunc->numBytes;
/* printf("%d -> %d, %u\n", j, map[j], typesize(bc, ty)); */
bcfunc->numBytes += typesize(bc, ty);
+ /* TODO: don't allow size 0, it is always a bug! */
}
bcfunc->numBytes = (bcfunc->numBytes + 7)&~7;
for (j=0;j<bcfunc->numConstants;j++) {
@@ -1872,11 +1947,13 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
else
inst->interp_op = 5*(inst->interp_op/5)+3;
MAP(inst->u.three[1]);
+ if (calc_gepz(bc, bcfunc, inst->u.three[0], inst->u.three[2]) == -1)
+ return CL_EBYTECODE;
MAP(inst->u.three[2]);
break;
- case OP_BC_GEPN:
- /*TODO */
- break;
+/* case OP_BC_GEPN:
+ *TODO
+ break;*/
case OP_BC_MEMSET:
case OP_BC_MEMCPY:
case OP_BC_MEMMOVE:
@@ -1903,7 +1980,7 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
MAPPTR(inst->u.unaryop);
break;
default:
- cli_dbgmsg("Unhandled opcode: %d\n", inst->opcode);
+ cli_warnmsg("Bytecode: unhandled opcode: %d\n", inst->opcode);
return CL_EBYTECODE;
}
}
@@ -1914,41 +1991,407 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
return CL_SUCCESS;
}
-int cli_bytecode_prepare(struct cli_all_bc *bcs, unsigned dconfmask)
+static int add_selfcheck(struct cli_all_bc *bcs)
+{
+ struct cli_bc_func *func;
+ struct cli_bc_inst *inst;
+ struct cli_bc *bc;
+
+ bcs->all_bcs = cli_realloc2(bcs->all_bcs, sizeof(*bcs->all_bcs)*(bcs->count+1));
+ if (!bcs->all_bcs) {
+ cli_errmsg("cli_loadcbc: Can't allocate memory for bytecode entry\n");
+ return CL_EMEM;
+ }
+ bc = &bcs->all_bcs[bcs->count++];
+ memset(bc, 0, sizeof(*bc));
+
+ bc->trusted = 1;
+ bc->num_globals = 1;
+ bc->globals = cli_calloc(1, sizeof(*bc->globals));
+ if (!bc->globals) {
+ cli_errmsg("Failed to allocate memory for globals\n");
+ return CL_EMEM;
+ }
+ bc->globals[0] = cli_calloc(1, sizeof(*bc->globals[0]));
+ if (!bc->globals[0]) {
+ cli_errmsg("Failed to allocate memory for globals\n");
+ return CL_EMEM;
+ }
+ bc->globaltys = cli_calloc(1, sizeof(*bc->globaltys));
+ if (!bc->globaltys) {
+ cli_errmsg("Failed to allocate memory for globaltypes\n");
+ return CL_EMEM;
+ }
+ bc->globaltys[0] = 32;
+ *bc->globals[0] = 0;
+ bc->id = ~0;
+ bc->kind = 0;
+ bc->num_types = 5;
+ bc->num_func = 1;
+ bc->funcs = cli_calloc(1, sizeof(*bc->funcs));
+ if (!bc->funcs) {
+ cli_errmsg("Failed to allocate memory for func\n");
+ return CL_EMEM;
+ }
+ func = bc->funcs;
+ func->numInsts = 2;
+ func->numLocals = 1;
+ func->numValues = 1;
+ func->numConstants = 1;
+ func->numBB = 1;
+ func->returnType = 32;
+ func->types = cli_calloc(1, sizeof(*func->types));
+ if (!func->types) {
+ cli_errmsg("Failed to allocate memory for types\n");
+ return CL_EMEM;
+ }
+ func->types[0] = 32;
+ func->BB = cli_calloc(1, sizeof(*func->BB));
+ if (!func->BB) {
+ cli_errmsg("Failed to allocate memory for BB\n");
+ return CL_EMEM;
+ }
+ func->allinsts = cli_calloc(2, sizeof(*func->allinsts));
+ if (!func->allinsts) {
+ cli_errmsg("Failed to allocate memory for insts\n");
+ return CL_EMEM;
+ }
+ func->BB->numInsts = 2;
+ func->BB->insts = func->allinsts;
+ func->constants = cli_calloc(1, sizeof(*func->constants));
+ if (!func->constants) {
+ cli_errmsg("Failed to allocate memory for constants\n");
+ return CL_EMEM;
+ }
+ func->constants[0] = 0xf00d;
+ inst = func->allinsts;
+
+ inst->opcode = OP_BC_CALL_API;
+ inst->u.ops.numOps = 1;
+ inst->u.ops.opsizes = NULL;
+ inst->u.ops.ops = cli_calloc(1, sizeof(*inst->u.ops.ops));
+ if (!inst->u.ops.ops) {
+ cli_errmsg("Failed to allocate memory for instructions\n");
+ return CL_EMEM;
+ }
+ inst->u.ops.ops[0] = 1;
+ inst->u.ops.funcid = 18; /* test2 */
+ inst->dest = 0;
+ inst->type = 32;
+ inst->interp_op = inst->opcode* 5 + 3;
+
+ inst = &func->allinsts[1];
+ inst->opcode = OP_BC_RET;
+ inst->type = 32;
+ inst->u.unaryop = 0;
+ inst->interp_op = inst->opcode* 5;
+
+ bc->state = bc_loaded;
+ return 0;
+}
+
+static int run_selfcheck(struct cli_all_bc *bcs)
{
- unsigned i, interp = 0;
+ struct cli_bc_ctx *ctx;
+ struct cli_bc *bc = &bcs->all_bcs[bcs->count-1];
int rc;
- if (cli_bytecode_prepare_jit(bcs) == CL_SUCCESS) {
- cli_dbgmsg("Bytecode: %u bytecode prepared with JIT\n", bcs->count);
+ if (bc->state != bc_jit && bc->state != bc_interp) {
+ cli_errmsg("Failed to prepare selfcheck bytecode\n");
+ return CL_EBYTECODE;
+ }
+ ctx = cli_bytecode_context_alloc();
+ if (!ctx) {
+ cli_errmsg("Failed to allocate bytecode context\n");
+ return CL_EMEM;
+ }
+ cli_bytecode_context_setfuncid(ctx, bc, 0);
+
+ cli_dbgmsg("bytecode self test running\n");
+ rc = cli_bytecode_run(bcs, bc, ctx);
+ cli_bytecode_context_destroy(ctx);
+ if (rc != CL_SUCCESS) {
+ cli_errmsg("bytecode self test failed: %s\n",
+ cl_strerror(rc));
+ } else {
+ cli_dbgmsg("bytecode self test succeeded\n");
+ }
+ return rc;
+}
+
+static int selfcheck(int jit, struct cli_bcengine *engine)
+{
+ struct cli_all_bc bcs;
+ int rc;
+
+ memset(&bcs, 0, sizeof(bcs));
+ bcs.all_bcs = NULL;
+ bcs.count = 0;
+ bcs.engine = engine;
+ rc = add_selfcheck(&bcs);
+ if (rc == CL_SUCCESS) {
+ if (jit) {
+ if (!bcs.engine) {
+ cli_dbgmsg("bytecode: JIT disabled\n");
+ rc = CL_BREAK;/* no JIT - not fatal */
+ } else {
+ rc = cli_bytecode_prepare_jit(&bcs);
+ }
+ } else {
+ rc = cli_bytecode_prepare_interpreter(bcs.all_bcs);
+ }
+ if (rc == CL_SUCCESS)
+ rc = run_selfcheck(&bcs);
+ if (rc == CL_BREAK)
+ rc = CL_SUCCESS;
+ }
+ cli_bytecode_destroy(bcs.all_bcs);
+ free(bcs.all_bcs);
+ cli_bytecode_done_jit(&bcs, 1);
+ if (rc != CL_SUCCESS) {
+ cli_errmsg("Bytecode: failed to run selfcheck in %s mode: %s\n",
+ jit ? "JIT" : "interpreter", cl_strerror(rc));
+ }
+ return rc;
+}
+
+static int set_mode(struct cl_engine *engine, enum bytecode_mode mode)
+{
+ if (engine->bytecode_mode == mode)
+ return 0;
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_OFF) {
+ cli_errmsg("bytecode: already turned off, can't turn it on again!\n");
+ return -1;
+ }
+ cli_dbgmsg("Bytecode: mode changed to %d\n", mode);
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST) {
+ if (mode == CL_BYTECODE_MODE_OFF || have_clamjit) {
+ cli_errmsg("bytecode: in test mode but JIT/bytecode is about to be disabled: %d\n", mode);
+ engine->bytecode_mode = mode;
+ return -1;
+ }
+ return 0;
+ }
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_JIT) {
+ cli_errmsg("bytecode: in JIT mode but JIT is about to be disabled: %d\n", mode);
+ engine->bytecode_mode = mode;
+ return -1;
+ }
+ engine->bytecode_mode = mode;
+ return 0;
+}
+
+/* runs the first bytecode of the specified kind, or the builtin one if no
+ * bytecode of that kind is loaded */
+static int run_builtin_or_loaded(struct cli_all_bc *bcs, uint8_t kind, const char* builtin_cbc, struct cli_bc_ctx *ctx, const char *desc)
+{
+ unsigned i, builtin = 0, rc = 0;
+ struct cli_bc *bc = NULL;
+
+ for (i=0;i<bcs->count;i++) {
+ bc = &bcs->all_bcs[i];
+ if (bc->kind == kind)
+ break;
+ }
+ if (i == bcs->count)
+ bc = NULL;
+ if (!bc) {
+ /* no loaded bytecode found, load the builtin one! */
+ struct cli_dbio dbio;
+ bc = cli_calloc(1, sizeof(*bc));
+ if (!bc) {
+ cli_errmsg("Out of memory allocating bytecode\n");
+ return CL_EMEM;
+ }
+ builtin = 1;
+
+ memset(&dbio, 0, sizeof(dbio));
+ dbio.usebuf = 1;
+ dbio.bufpt = dbio.buf = (char*)builtin_cbc;
+ dbio.bufsize = strlen(builtin_cbc)+1;
+ if (!dbio.bufsize || dbio.bufpt[dbio.bufsize-2] != '\n') {
+ cli_errmsg("Invalid builtin bytecode: missing terminator\n");
+ free(bc);
+ return CL_EMALFDB;
+ }
+
+ rc = cli_bytecode_load(bc, NULL, &dbio, 1);
+ if (rc) {
+ cli_errmsg("Failed to load builtin %s bytecode\n", desc);
+ free(bc);
+ return rc;
+ }
+ }
+ rc = cli_bytecode_prepare_interpreter(bc);
+ if (rc) {
+ cli_errmsg("Failed to prepare %s %s bytecode for interpreter: %s\n",
+ builtin ? "builtin" : "loaded", desc, cl_strerror(rc));
+ }
+ if (bc->state != bc_interp) {
+ cli_errmsg("Failed to prepare %s %s bytecode for interpreter\n",
+ builtin ? "builtin" : "loaded", desc);
+ rc = CL_EMALFDB;
+ }
+ if (!rc) {
+ cli_bytecode_context_setfuncid(ctx, bc, 0);
+ cli_dbgmsg("Bytecode: %s running (%s)\n", desc,
+ builtin ? "builtin" : "loaded");
+ rc = cli_bytecode_run(bcs, bc, ctx);
+ }
+ if (rc) {
+ cli_errmsg("Failed to execute %s %s bytecode: %s\n",builtin ? "builtin":"loaded",
+ desc, cl_strerror(rc));
+ }
+ if (builtin) {
+ cli_bytecode_destroy(bc);
+ free(bc);
+ }
+ return rc;
+}
+
+int cli_bytecode_prepare2(struct cl_engine *engine, struct cli_all_bc *bcs, unsigned dconfmask)
+{
+ unsigned i, interp = 0, jitok = 0, jitcount=0;
+ int rc;
+ struct cli_bc_ctx *ctx;
+
+ cli_detect_environment(&bcs->env);
+ switch (bcs->env.arch) {
+ case arch_i386:
+ case arch_x86_64:
+ if (!(dconfmask & BYTECODE_JIT_X86)) {
+ cli_dbgmsg("Bytecode: disabled on X86 via DCONF\n");
+ if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ }
+ break;
+ case arch_ppc32:
+ case arch_ppc64:
+ if (!(dconfmask & BYTECODE_JIT_PPC)) {
+ cli_dbgmsg("Bytecode: disabled on PPC via DCONF\n");
+ if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ }
+ break;
+ case arch_arm:
+ if (!(dconfmask & BYTECODE_JIT_ARM)) {
+ cli_dbgmsg("Bytecode: disabled on ARM via DCONF\n");
+ if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ }
+ break;
+ default:
+ cli_dbgmsg("Bytecode: JIT not supported on this architecture, falling back\n");
+ if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ break;
+ }
+ cli_dbgmsg("Bytecode: mode is %d\n", engine->bytecode_mode);
+
+ ctx = cli_bytecode_context_alloc();
+ if (!ctx) {
+ cli_errmsg("Bytecode: failed to allocate bytecode context\n");
+ return CL_EMEM;
+ }
+ rc = run_builtin_or_loaded(bcs, BC_STARTUP, builtin_bc_startup, ctx, "BC_STARTUP");
+ if (rc != CL_SUCCESS) {
+ cli_warnmsg("Bytecode: BC_STARTUP failed to run, disabling ALL bytecodes! Please report to http://bugs.clamav.net\n");
+ ctx->bytecode_disable_status = 2;
+ } else {
+ cli_dbgmsg("Bytecode: disable status is %d\n", ctx->bytecode_disable_status);
+ rc = cli_bytecode_context_getresult_int(ctx);
+ /* check magic number, don't use 0 here because it is too easy for a
+ * buggy bytecode to return 0 */
+ if (rc != 0xda7aba5e) {
+ cli_warnmsg("Bytecode: selftest failed with code %08x. Please report to http://bugs.clamav.net\n",
+ rc);
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_TEST)
+ return CL_EBYTECODE_TESTFAIL;
+ }
+ }
+ switch (ctx->bytecode_disable_status) {
+ case 1:
+ if (set_mode(engine, CL_BYTECODE_MODE_INTERPRETER) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ break;
+ case 2:
+ if (set_mode(engine, CL_BYTECODE_MODE_OFF) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ break;
+ default:
+ break;
+ }
+ cli_bytecode_context_destroy(ctx);
+
+
+ if (engine->bytecode_mode != CL_BYTECODE_MODE_INTERPRETER &&
+ engine->bytecode_mode != CL_BYTECODE_MODE_OFF) {
+ selfcheck(1, bcs->engine);
+ rc = cli_bytecode_prepare_jit(bcs);
+ if (rc == CL_SUCCESS) {
+ jitok = 1;
+ cli_dbgmsg("Bytecode: %u bytecode prepared with JIT\n", bcs->count);
+ if (engine->bytecode_mode != CL_BYTECODE_MODE_TEST)
+ return CL_SUCCESS;
+ }
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_JIT) {
+ cli_errmsg("Bytecode: JIT required, but not all bytecodes could be prepared with JIT\n");
+ return CL_EMALFDB;
+ }
+ } else {
+ cli_bytecode_done_jit(bcs, 0);
+ }
+
+ if (!(dconfmask & BYTECODE_INTERPRETER)) {
+ cli_dbgmsg("Bytecode: needs interpreter, but interpreter is disabled\n");
+ if (set_mode(engine, CL_BYTECODE_MODE_OFF) == -1)
+ return CL_EBYTECODE_TESTFAIL;
+ }
+
+ if (engine->bytecode_mode == CL_BYTECODE_MODE_OFF) {
+ for (i=0;i<bcs->count;i++)
+ bcs->all_bcs[i].state = bc_disabled;
+ cli_dbgmsg("Bytecode: ALL bytecodes disabled\n");
return CL_SUCCESS;
}
+
for (i=0;i<bcs->count;i++) {
struct cli_bc *bc = &bcs->all_bcs[i];
- if (bc->state == bc_interp || bc->state == bc_jit)
+ if (bc->state == bc_jit) {
+ jitcount++;
continue;
- if (!(dconfmask & BYTECODE_INTERPRETER)) {
- cli_warnmsg("Bytecode needs interpreter, but interpreter is disabled\n");
+ }
+ if (bc->state == bc_interp) {
+ interp++;
continue;
}
rc = cli_bytecode_prepare_interpreter(bc);
- interp++;
- if (rc != CL_SUCCESS)
+ if (rc != CL_SUCCESS) {
+ bc->state = bc_disabled;
+ cli_warnmsg("Bytecode: %d failed to prepare for interpreter mode\n", bc->id);
return rc;
+ }
+ interp++;
}
cli_dbgmsg("Bytecode: %u bytecode prepared with JIT, "
- "%u prepared with interpreter\n", bcs->count-interp, interp);
+ "%u prepared with interpreter, %u failed\n", jitcount, interp,
+ bcs->count - jitcount - interp);
return CL_SUCCESS;
}
-int cli_bytecode_init(struct cli_all_bc *allbc, unsigned dconfmask)
+int cli_bytecode_init(struct cli_all_bc *allbc)
{
+ int ret;
memset(allbc, 0, sizeof(*allbc));
- return cli_bytecode_init_jit(allbc, dconfmask);
+ ret = cli_bytecode_init_jit(allbc, 0/*XXX*/);
+ cli_dbgmsg("Bytecode initialized in %s mode\n",
+ allbc->engine ? "JIT" : "interpreter");
+ allbc->inited = 1;
+ return ret;
}
int cli_bytecode_done(struct cli_all_bc *allbc)
{
- return cli_bytecode_done_jit(allbc);
+ return cli_bytecode_done_jit(allbc, 0);
}
int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map)
@@ -1959,11 +2402,15 @@ int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map)
return 0;
}
-int cli_bytecode_runlsig(cli_ctx *cctx, const struct cli_all_bc *bcs, unsigned bc_idx, const char **virname, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map)
+int cli_bytecode_runlsig(cli_ctx *cctx, struct cli_target_info *tinfo,
+ const struct cli_all_bc *bcs, unsigned bc_idx,
+ const char **virname, const uint32_t* lsigcnt,
+ const uint32_t *lsigsuboff, fmap_t *map)
{
int ret;
struct cli_bc_ctx ctx;
const struct cli_bc *bc = &bcs->all_bcs[bc_idx-1];
+ struct cli_pe_hook_data pehookdata;
if (bc->hook_lsig_id) {
cli_dbgmsg("hook lsig id %d matched (bc %d)\n", bc->hook_lsig_id, bc->id);
@@ -1971,6 +2418,9 @@ int cli_bytecode_runlsig(cli_ctx *cctx, const struct cli_all_bc *bcs, unsigned b
* executed, so that it has all the info for the hook */
if (cctx->hook_lsig_matches)
cli_bitset_set(cctx->hook_lsig_matches, bc->hook_lsig_id-1);
+ /* save match counts */
+ memcpy(&ctx.lsigcnt, lsigcnt, 64*4);
+ memcpy(&ctx.lsigoff, lsigsuboff, 64*4);
return CL_SUCCESS;
}
memset(&ctx, 0, sizeof(ctx));
@@ -1979,6 +2429,16 @@ int cli_bytecode_runlsig(cli_ctx *cctx, const struct cli_all_bc *bcs, unsigned b
ctx.hooks.match_offsets = lsigsuboff;
cli_bytecode_context_setctx(&ctx, cctx);
cli_bytecode_context_setfile(&ctx, map);
+ if (tinfo && tinfo->status == 1) {
+ ctx.sections = tinfo->exeinfo.section;
+ memset(&pehookdata, 0, sizeof(pehookdata));
+ pehookdata.offset = tinfo->exeinfo.offset;
+ pehookdata.ep = tinfo->exeinfo.ep;
+ pehookdata.nsections = tinfo->exeinfo.nsections;
+ pehookdata.hdr_size = tinfo->exeinfo.hdr_size;
+ ctx.hooks.pedata = &pehookdata;
+ ctx.resaddr = tinfo->exeinfo.res_addr;
+ }
cli_dbgmsg("Running bytecode for logical signature match\n");
ret = cli_bytecode_run(bcs, bc, &ctx);
@@ -2009,6 +2469,9 @@ int cli_bytecode_runhook(cli_ctx *cctx, const struct cl_engine *engine, struct c
cli_bytecode_context_setfile(ctx, map);
cli_dbgmsg("Bytecode executing hook id %u (%u hooks)\n", id, hooks_cnt);
+ /* restore match counts */
+ ctx->hooks.match_counts = ctx->lsigcnt;
+ ctx->hooks.match_offsets = ctx->lsigoff;
for (i=0;i < hooks_cnt;i++) {
const struct cli_bc *bc = &engine->bcs.all_bcs[hooks[i]];
if (bc->lsig) {
@@ -2104,7 +2567,8 @@ void cli_bytecode_describe(const struct cli_bc *bc)
printf("Bytecode format functionality level: %u\n", bc->metadata.formatlevel);
printf("Bytecode metadata:\n\tcompiler version: %s\n",
bc->metadata.compiler ? bc->metadata.compiler : "N/A");
- printf("\tcompiled on: %s",
+ printf("\tcompiled on: (%d) %s",
+ (uint32_t)stamp,
cli_ctime(&stamp, buf, sizeof(buf)));
printf("\tcompiled by: %s\n", bc->metadata.sigmaker ? bc->metadata.sigmaker : "N/A");
/*TODO: parse and display arch name, also take it into account when
@@ -2115,6 +2579,9 @@ void cli_bytecode_describe(const struct cli_bc *bc)
case BC_GENERIC:
puts("generic, not loadable by clamscan/clamd");
break;
+ case BC_STARTUP:
+ puts("run on startup (unique)");
+ break;
case BC_LOGICAL:
puts("logical only");
break;
diff --git a/libclamav/bytecode.h b/libclamav/bytecode.h
index 31ef0df..cc307b7 100644
--- a/libclamav/bytecode.h
+++ b/libclamav/bytecode.h
@@ -25,6 +25,7 @@
#include "clambc.h"
#include <stdio.h>
#include "fmap.h"
+#include "bytecode_detect.h"
struct cli_dbio;
struct cli_bc_ctx;
@@ -41,7 +42,8 @@ enum bc_state {
bc_skip,
bc_loaded,
bc_jit,
- bc_interp
+ bc_interp,
+ bc_disabled
};
struct cli_bc {
@@ -56,12 +58,12 @@ struct cli_bc {
uint16_t *globaltys;
size_t num_globals;
enum bc_state state;
- uint16_t start_tid;
struct bitset_tag *uses_apis;
char *lsig;
char *vnameprefix;
char **vnames;
unsigned vnames_cnt;
+ uint16_t start_tid;
struct cli_bc_dbgnode *dbgnodes;
unsigned dbgnode_cnt;
unsigned hook_lsig_id;
@@ -74,10 +76,13 @@ struct cli_all_bc {
struct cli_bc *all_bcs;
unsigned count;
struct cli_bcengine *engine;
+ struct cli_environment env;
+ int inited;
};
struct cli_pe_hook_data;
struct cli_exe_section;
+struct pdf_obj;
struct cli_bc_ctx *cli_bytecode_context_alloc(void);
/* FIXME: we can't include others.h because others.h includes us...*/
void cli_bytecode_context_setctx(struct cli_bc_ctx *ctx, void *cctx);
@@ -86,6 +91,7 @@ int cli_bytecode_context_setparam_int(struct cli_bc_ctx *ctx, unsigned i, uint64
int cli_bytecode_context_setparam_ptr(struct cli_bc_ctx *ctx, unsigned i, void *data, unsigned datalen);
int cli_bytecode_context_setfile(struct cli_bc_ctx *ctx, fmap_t *map);
int cli_bytecode_context_setpe(struct cli_bc_ctx *ctx, const struct cli_pe_hook_data *data, const struct cli_exe_section *sections);
+int cli_bytecode_context_setpdf(struct cli_bc_ctx *ctx, unsigned phase, unsigned nobjs, struct pdf_obj *objs, uint32_t *pdf_flags, uint32_t pdfsize, uint32_t pdfstartoff);
int cli_bytecode_context_clear(struct cli_bc_ctx *ctx);
/* returns file descriptor, sets tempfile. Caller takes ownership, and is
* responsible for freeing/unlinking */
@@ -100,9 +106,9 @@ extern int have_clamjit;
#ifdef __cplusplus
}
#endif
-int cli_bytecode_init(struct cli_all_bc *allbc, unsigned dconfmask);
+int cli_bytecode_init(struct cli_all_bc *allbc);
int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio, int security);
-int cli_bytecode_prepare(struct cli_all_bc *allbc, unsigned dconfmask);
+int cli_bytecode_prepare2(struct cl_engine *engine, struct cli_all_bc *allbc, unsigned dconfmask);
int cli_bytecode_run(const struct cli_all_bc *bcs, const struct cli_bc *bc, struct cli_bc_ctx *ctx);
void cli_bytecode_destroy(struct cli_bc *bc);
int cli_bytecode_done(struct cli_all_bc *allbc);
@@ -111,7 +117,8 @@ void cli_bytecode_describe(const struct cli_bc *bc);
/* Hooks */
struct cli_exe_info;
struct cli_ctx_tag;
-int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, const struct cli_all_bc *bcs, unsigned bc_idx, const char **virname, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
+struct cli_target_info;
+int cli_bytecode_runlsig(struct cli_ctx_tag *ctx, struct cli_target_info *info, const struct cli_all_bc *bcs, unsigned bc_idx, const char **virname, const uint32_t* lsigcnt, const uint32_t *lsigsuboff, fmap_t *map);
int cli_bytecode_runhook(struct cli_ctx_tag *cctx, const struct cl_engine *engine, struct cli_bc_ctx *ctx, unsigned id, fmap_t *map, const char **virname);
#ifdef __cplusplus
diff --git a/libclamav/bytecode_api.c b/libclamav/bytecode_api.c
index ce72493..154f0ba 100644
--- a/libclamav/bytecode_api.c
+++ b/libclamav/bytecode_api.c
@@ -42,6 +42,7 @@
#include "bytecode_api_impl.h"
#include "others.h"
#include "pe.h"
+#include "pdf.h"
#include "disasm.h"
#include "scanners.h"
#include "jsparse/js-norm.h"
@@ -989,7 +990,7 @@ int32_t cli_bcapi_memstr(struct cli_bc_ctx *ctx, const uint8_t* h, int32_t hs,
const uint8_t *s;
if (!h || !n || hs < 0 || ns < 0)
return -1;
- s = cli_memstr(h, hs, n, ns);
+ s = (const uint8_t*) cli_memstr((const char*)h, hs, (const char*)n, ns);
if (!s)
return -1;
return s - h;
@@ -997,12 +998,12 @@ int32_t cli_bcapi_memstr(struct cli_bc_ctx *ctx, const uint8_t* h, int32_t hs,
int32_t cli_bcapi_hex2ui(struct cli_bc_ctx *ctx, uint32_t ah, uint32_t bh)
{
- uint8_t result = 0;
+ char result = 0;
unsigned char in[2];
in[0] = ah;
in[1] = bh;
- if (cli_hex2str_to(in, &result, 2) == -1)
+ if (cli_hex2str_to((const char*)in, &result, 2) == -1)
return -1;
return result;
}
@@ -1215,3 +1216,228 @@ int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx , int32_t extracted_file)
cli_dbgmsg("bytecode api: input switched to extracted file\n");
return 0;
}
+
+uint32_t cli_bcapi_get_environment(struct cli_bc_ctx *ctx , struct cli_environment* env, uint32_t len)
+{
+ if (len > sizeof(*env)) {
+ cli_dbgmsg("cli_bcapi_get_environment len %u > %lu\n", len, sizeof(*env));
+ return -1;
+ }
+ memcpy(env, ctx->env, len);
+ return 0;
+}
+
+uint32_t cli_bcapi_disable_bytecode_if(struct cli_bc_ctx *ctx , const int8_t* reason, uint32_t len, uint32_t cond)
+{
+ if (ctx->bc->kind != BC_STARTUP) {
+ cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_bytecode_if\n");
+ return -1;
+ }
+ if (!cond)
+ return ctx->bytecode_disable_status;
+ if (*reason == '^')
+ cli_warnmsg("Bytecode: disabling completely because %s\n", reason+1);
+ else
+ cli_dbgmsg("Bytecode: disabling completely because %s\n", reason);
+ ctx->bytecode_disable_status = 2;
+ return ctx->bytecode_disable_status;
+}
+
+uint32_t cli_bcapi_disable_jit_if(struct cli_bc_ctx *ctx , const int8_t* reason, uint32_t len, uint32_t cond)
+{
+ if (ctx->bc->kind != BC_STARTUP) {
+ cli_dbgmsg("Bytecode must be BC_STARTUP to call disable_jit_if\n");
+ return -1;
+ }
+ if (!cond)
+ return ctx->bytecode_disable_status;
+ if (*reason == '^')
+ cli_warnmsg("Bytecode: disabling JIT because %s\n", reason+1);
+ else
+ cli_dbgmsg("Bytecode: disabling JIT because %s\n", reason);
+ if (ctx->bytecode_disable_status != 2) /* no reenabling */
+ ctx->bytecode_disable_status = 1;
+ return ctx->bytecode_disable_status;
+}
+
+int32_t cli_bcapi_version_compare(struct cli_bc_ctx *ctx , const uint8_t* lhs, uint32_t lhs_len,
+ const uint8_t* rhs, uint32_t rhs_len)
+{
+ unsigned i = 0, j = 0;
+ unsigned long li=0, ri=0;
+ do {
+ while (i < lhs_len && j < rhs_len && lhs[i] == rhs[j] &&
+ !isdigit(lhs[i]) && !isdigit(rhs[j])) {
+ i++; j++;
+ }
+ if (i == lhs_len && j == rhs_len)
+ return 0;
+ if (i == lhs_len)
+ return -1;
+ if (j == rhs_len)
+ return 1;
+ if (!isdigit(lhs[i]) || !isdigit(rhs[j]))
+ return lhs[i] < rhs[j] ? -1 : 1;
+ while (isdigit(lhs[i]) && i < lhs_len)
+ li = 10*li + (lhs[i] - '0');
+ while (isdigit(rhs[j]) && j < rhs_len)
+ ri = 10*ri + (rhs[j] - '0');
+ if (li < ri)
+ return -1;
+ if (li > ri)
+ return 1;
+ } while (1);
+}
+
+static int check_bits(uint32_t query, uint32_t value, uint8_t shift, uint8_t mask)
+{
+ uint8_t q = (query >> shift)&mask;
+ uint8_t v = (value >> shift)&mask;
+ /* q == mask -> ANY */
+ if (q == v || q == mask)
+ return 1;
+ return 0;
+}
+
+uint32_t cli_bcapi_check_platform(struct cli_bc_ctx *ctx , uint32_t a, uint32_t b , uint32_t c)
+{
+ unsigned ret =
+ check_bits(a, ctx->env->platform_id_a, 24, 0xff) &&
+ check_bits(a, ctx->env->platform_id_a, 20, 0xf) &&
+ check_bits(a, ctx->env->platform_id_a, 16, 0xf) &&
+ check_bits(a, ctx->env->platform_id_a, 8, 0xff) &&
+ check_bits(a, ctx->env->platform_id_a, 0, 0xff) &&
+ check_bits(b, ctx->env->platform_id_b, 28, 0xf) &&
+ check_bits(b, ctx->env->platform_id_b, 24, 0xf) &&
+ check_bits(b, ctx->env->platform_id_b, 16, 0xff) &&
+ check_bits(b, ctx->env->platform_id_b, 8, 0xff) &&
+ check_bits(b, ctx->env->platform_id_b, 0, 0xff) &&
+ check_bits(c, ctx->env->platform_id_c, 24, 0xff) &&
+ check_bits(c, ctx->env->platform_id_c, 16, 0xff) &&
+ check_bits(c, ctx->env->platform_id_c, 8, 0xff) &&
+ check_bits(c, ctx->env->platform_id_c, 0, 0xff);
+ if (ret) {
+ cli_dbgmsg("check_platform(0x%08x,0x%08x,0x%08x) = match\n",a,b,c);
+ }
+ return ret;
+}
+
+int cli_bytecode_context_setpdf(struct cli_bc_ctx *ctx, unsigned phase,
+ unsigned nobjs,
+ struct pdf_obj *objs, uint32_t *pdf_flags,
+ uint32_t pdfsize, uint32_t pdfstartoff)
+{
+ ctx->pdf_nobjs = nobjs;
+ ctx->pdf_objs = objs;
+ ctx->pdf_flags = pdf_flags;
+ ctx->pdf_size = pdfsize;
+ ctx->pdf_startoff = pdfstartoff;
+ ctx->pdf_phase = phase;
+ return 0;
+}
+
+int32_t cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx *ctx)
+{
+ if (!ctx->pdf_phase)
+ return -1;
+ return ctx->pdf_nobjs;
+}
+
+int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx)
+{
+ if (!ctx->pdf_phase)
+ return -1;
+ return *ctx->pdf_flags;
+}
+
+int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t flags)
+{
+ if (!ctx->pdf_phase)
+ return -1;
+ cli_dbgmsg("cli_pdf: bytecode set_flags %08x -> %08x\n",
+ *ctx->pdf_flags,
+ flags);
+ *ctx->pdf_flags = flags;
+ return 0;
+}
+
+int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx , uint32_t objid)
+{
+ unsigned i;
+ if (!ctx->pdf_phase)
+ return -1;
+ for (i=0;i<ctx->pdf_nobjs;i++) {
+ if (ctx->pdf_objs[i].id == objid)
+ return i;
+ }
+ return -1;
+}
+
+uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t objidx)
+{
+ if (!ctx->pdf_phase ||
+ objidx >= ctx->pdf_nobjs ||
+ ctx->pdf_phase == PDF_PHASE_POSTDUMP /* map is obj itself, no access to pdf anymore */
+ )
+ return 0;
+ if (objidx + 1 == ctx->pdf_nobjs)
+ return ctx->pdf_size - ctx->pdf_objs[objidx].start;
+ return ctx->pdf_objs[objidx+1].start - ctx->pdf_objs[objidx].start - 4;
+}
+
+uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t objidx, uint32_t amount)
+{
+ uint32_t size = cli_bcapi_pdf_getobjsize(ctx, objidx);
+ if (amount > size)
+ return NULL;
+ return fmap_need_off(ctx->fmap, ctx->pdf_objs[objidx].start, amount);
+}
+
+int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t objidx)
+{
+ if (!ctx->pdf_phase ||
+ objidx >= ctx->pdf_nobjs)
+ return -1;
+ return ctx->pdf_objs[objidx].id;
+}
+
+int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t objidx)
+{
+ if (!ctx->pdf_phase ||
+ objidx >= ctx->pdf_nobjs)
+ return -1;
+ return ctx->pdf_objs[objidx].flags;
+}
+
+int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t objidx, int32_t flags)
+{
+ if (!ctx->pdf_phase ||
+ objidx >= ctx->pdf_nobjs)
+ return -1;
+ cli_dbgmsg("cli_pdf: bytecode setobjflags %08x -> %08x\n",
+ ctx->pdf_objs[objidx].flags,
+ flags);
+ ctx->pdf_objs[objidx].flags = flags;
+ return 0;
+}
+
+int32_t cli_bcapi_pdf_get_offset(struct cli_bc_ctx *ctx , int32_t objidx)
+{
+ if (!ctx->pdf_phase ||
+ objidx >= ctx->pdf_nobjs)
+ return -1;
+ return ctx->pdf_startoff + ctx->pdf_objs[objidx].start;
+}
+
+int32_t cli_bcapi_pdf_get_phase(struct cli_bc_ctx *ctx)
+{
+ return ctx->pdf_phase;
+}
+
+int32_t cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx *ctx)
+{
+ if (ctx->pdf_phase != PDF_PHASE_POSTDUMP)
+ return -1;
+ return ctx->pdf_dumpedid;
+}
+
diff --git a/libclamav/bytecode_api.h b/libclamav/bytecode_api.h
index d4a6c31..27f44d2 100644
--- a/libclamav/bytecode_api.h
+++ b/libclamav/bytecode_api.h
@@ -33,6 +33,7 @@
#include "bytecode_execs.h"
#include "bytecode_pe.h"
#include "bytecode_disasm.h"
+#include "bytecode_detect.h"
#endif
#ifndef __CLAMBC__
@@ -44,11 +45,14 @@ struct DISASM_RESULT;
enum BytecodeKind {
/** generic bytecode, not tied a specific hook */
BC_GENERIC=0,
+ BC_STARTUP=1,
_BC_START_HOOKS=256,
/** triggered by a logical signature */
BC_LOGICAL=256,
/** a PE unpacker */
BC_PE_UNPACKER,
+ /* PDF hook */
+ BC_PDF,
_BC_LAST_HOOK
};
@@ -57,7 +61,63 @@ static const unsigned PE_INVALID_RVA = 0xFFFFFFFF ;
/** LibClamAV functionality level constants */
enum FunctionalityLevels {
FUNC_LEVEL_096 = 51,
- FUNC_LEVEL_096_dev
+ FUNC_LEVEL_096_dev,
+ FUNC_LEVEL_096_1,
+ FUNC_LEVEL_096_1_dev,
+ FUNC_LEVEL_096_2
+};
+
+enum pdf_phase {
+ PDF_PHASE_NONE /* not a PDF */,
+ PDF_PHASE_PARSED, /* after parsing a PDF, object flags can be set etc. */
+ PDF_PHASE_POSTDUMP, /* after an obj was dumped and scanned */
+ PDF_PHASE_END /* after the pdf scan finished */
+};
+
+enum pdf_flag {
+ BAD_PDF_VERSION=0,
+ BAD_PDF_HEADERPOS,
+ BAD_PDF_TRAILER,
+ BAD_PDF_TOOMANYOBJS,
+ BAD_STREAM_FILTERS,
+ BAD_FLATE,
+ BAD_FLATESTART,
+ BAD_STREAMSTART,
+ BAD_ASCIIDECODE,
+ BAD_INDOBJ,
+ UNTERMINATED_OBJ_DICT,
+ ESCAPED_COMMON_PDFNAME,
+ HEX_JAVASCRIPT,
+ UNKNOWN_FILTER,
+ MANY_FILTERS,
+ HAS_OPENACTION,
+ BAD_STREAMLEN,
+ ENCRYPTED_PDF,
+ LINEARIZED_PDF /* not bad, just as flag */
+};
+
+enum pdf_objflags {
+ OBJ_STREAM=0,
+ OBJ_DICT,
+ OBJ_EMBEDDED_FILE,
+ OBJ_FILTER_AH,
+ OBJ_FILTER_A85,
+ OBJ_FILTER_FLATE,
+ OBJ_FILTER_LZW,
+ OBJ_FILTER_RL,
+ OBJ_FILTER_FAX,
+ OBJ_FILTER_JBIG2,
+ OBJ_FILTER_DCT,
+ OBJ_FILTER_JPX,
+ OBJ_FILTER_CRYPT,
+ OBJ_FILTER_UNKNOWN,
+ OBJ_JAVASCRIPT,
+ OBJ_OPENACTION,
+ OBJ_HASFILTERS,
+ OBJ_SIGNED,
+ OBJ_IMAGE,
+ OBJ_TRUNCATED,
+ OBJ_FORCEDUMP
};
#ifdef __CLAMBC__
@@ -84,7 +144,6 @@ extern const uint32_t __clambc_filesize[1];
/** Kind of the bytecode */
const uint16_t __clambc_kind;
/* ---------------- END GLOBALS --------------------------------------------- */
-
/* ---------------- BEGIN 0.96 APIs (don't touch) --------------------------- */
/** Test api.
@param a 0xf00dbeef
@@ -651,5 +710,136 @@ int32_t extract_set_container(uint32_t container);
int32_t input_switch(int32_t extracted_file);
/* ---------------- END 0.96.1 APIs ------------------------------------- */
+/* ---------------- BEGIN 0.96.2 APIs ----------------------------------- */
+
+uint32_t get_environment(struct cli_environment *env, uint32_t len);
+/** Disables the bytecode completely if condition is true.
+ Can only be called from the BC_STARTUP bytecode.
+ @param reason - why the bytecode had to be disabled
+ @param len - length of reason
+ @param cond - condition
+ @return 0 - auto mode
+ 1 - JIT disabled
+ 2 - fully disabled
+ */
+uint32_t disable_bytecode_if(const int8_t *reason, uint32_t len, uint32_t cond);
+
+/** Disables the JIT completely if condition is true.
+ Can only be called from the BC_STARTUP bytecode.
+ @param reason - why the JIT had to be disabled
+ @param len - length of reason
+ @param cond - condition
+ @return 0 - auto mode
+ 1 - JIT disabled
+ 2 - fully disabled
+ */
+uint32_t disable_jit_if(const int8_t* reason, uint32_t len, uint32_t cond);
+
+/** Compares two version numbers.
+ * @param[in] lhs - left hand side of comparison
+ @param lhs_len - length of \p lhs
+ @param[in] rhs - right hand side of comparison
+ @param rhs_len - length of \p rhs
+ @return -1 - lhs < rhs
+ 0 - lhs == rhs
+ 1 - lhs > rhs */
+int32_t version_compare(const uint8_t* lhs, uint32_t lhs_len,
+ const uint8_t* rhs, uint32_t rhs_len);
+
+/** Disables the JIT if the platform id matches.
+ * 0xff can be used instead of a field to mark ANY.
+ * @param a - os_category << 24 | arch << 20 | compiler << 16 | flevel << 8 | dconf
+ @param b - big_endian << 28 | sizeof_ptr << 24 | cpp_version
+ @param c - os_features << 24 | c_version
+ @return 0 - no match
+ 1 - match */
+uint32_t check_platform(uint32_t a, uint32_t b, uint32_t c);
+
+/** Return number of pdf objects
+ * @return -1 - if not called from PDF hook
+ >=0 - number of PDF objects
+*/
+int32_t pdf_get_obj_num(void);
+
+/** Return the flags for the entire PDF (as set so far).
+ * @return -1 - if not called from PDF hook
+ >=0 - pdf flags */
+int32_t pdf_get_flags(void);
+
+/** Sets the flags for the entire PDF.
+ * It is recommended that you retrieve old flags, and just add new ones.
+ * @param flags - flags to set */
+int32_t pdf_set_flags(int32_t flags);
+
+/** Lookup pdf object with specified id.
+ * @param id - pdf id (objnumber << 8 | generationid)
+ @return -1 - if object id doesn't exist
+ >=0 - object index
+ */
+int32_t pdf_lookupobj(uint32_t id);
+
+/** Return the size of the specified PDF obj.
+ * @param objnum - object index (from 0), not object id!
+ * @return 0 - if not called from PDF hook, or invalid objnum
+ >=0 - size of object */
+uint32_t pdf_getobjsize(int32_t objidx);
+
+/** Return the undecoded object.
+ Meant only for reading, write modifies the fmap buffer, so avoid!
+ @param objidx - object index (from 0), not object id!
+ @param amount - size returned by pdf_getobjsize (or smaller)
+ @return NULL - invalid objidx/amount
+ pointer - pointer to original object */
+uint8_t *pdf_getobj(int32_t objidx, uint32_t amount);
+
+/* Return the object id for the specified object index.
+ @param objidx - object index (from 0)
+ @return -1 - object index invalid
+ >=0 - object id (obj id << 8 | generation id)
+*/
+int32_t pdf_getobjid(int32_t objidx);
+
+/* Return the object flags for the specified object index.
+ @param objidx - object index (from 0)
+ @return -1 - object index invalid
+ >=0 - object flags
+*/
+int32_t pdf_getobjflags(int32_t objidx);
+
+/* Sets the object flags for the specified object index.
+ This can be used to force dumping of a certain obj, by setting the
+ OBJ_FORCEDUMP flag for example.
+ @param objidx - object index (from 0)
+ @return -1 - object index invalid
+ >=0 - flags set
+*/
+int32_t pdf_setobjflags(int32_t objidx, int32_t flags);
+
+/* Return the object's offset in the PDF.
+ @param objidx - object index (from 0)
+ @return -1 - object index invalid
+ >=0 - offset
+*/
+int32_t pdf_get_offset(int32_t objidx);
+
+/** Return an 'enum pdf_phase'.
+ * Identifies at which phase this bytecode was called */
+int32_t pdf_get_phase(void);
+
+/** Return the currently dumped obj id.
+ Valid only in PDF_PHASE_POSTDUMP */
+int32_t pdf_get_dumpedobjid(void);
+
+/** Attempts to match current executable's icon against the specified icon
+ * groups.
+ * @param[in] group1 - same as GROUP1 in LDB signatures
+ * @param group1_len - length of \p group1
+ * @param[in] group2 - same as GROUP2 in LDB signatures
+ * @param group2_len - length of \p group2
+ */
+
+int32_t matchicon(const uint8_t* group1, int32_t group1_len,
+ const uint8_t* group2, int32_t group2_len);
+/* ---------------- END 0.96.2 APIs ----------------------------------- */
#endif
#endif
diff --git a/libclamav/bytecode_api_decl.c b/libclamav/bytecode_api_decl.c
index 68fe24a..3db106f 100644
--- a/libclamav/bytecode_api_decl.c
+++ b/libclamav/bytecode_api_decl.c
@@ -104,6 +104,24 @@ uint32_t cli_bcapi_engine_scan_options(struct cli_bc_ctx *ctx );
uint32_t cli_bcapi_engine_db_options(struct cli_bc_ctx *ctx );
int32_t cli_bcapi_extract_set_container(struct cli_bc_ctx *ctx , uint32_t);
int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx , int32_t);
+uint32_t cli_bcapi_get_environment(struct cli_bc_ctx *ctx , struct cli_environment*, uint32_t);
+uint32_t cli_bcapi_disable_bytecode_if(struct cli_bc_ctx *ctx , const int8_t*, uint32_t, uint32_t);
+uint32_t cli_bcapi_disable_jit_if(struct cli_bc_ctx *ctx , const int8_t*, uint32_t, uint32_t);
+int32_t cli_bcapi_version_compare(struct cli_bc_ctx *ctx , const uint8_t*, uint32_t, const uint8_t*, uint32_t);
+uint32_t cli_bcapi_check_platform(struct cli_bc_ctx *ctx , uint32_t, uint32_t, uint32_t);
+int32_t cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx , uint32_t);
+uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t);
+uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t);
+int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t, int32_t);
+int32_t cli_bcapi_pdf_get_offset(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_get_phase(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t*, int32_t, const uint8_t*, int32_t);
const struct cli_apiglobal cli_globals[] = {
/* Bytecode globals BEGIN */
@@ -128,25 +146,29 @@ static uint16_t cli_tmp4[]={16, 8, 8, 32, 32, 32, 32, 32, 32, 32, 32, 32, 16, 16
static uint16_t cli_tmp5[]={32, 16, 16, 32, 32, 32, 16, 16};
static uint16_t cli_tmp6[]={32};
static uint16_t cli_tmp7[]={32};
-static uint16_t cli_tmp8[]={32, 32};
+static uint16_t cli_tmp8[]={32, 65, 32, 65, 32};
static uint16_t cli_tmp9[]={32};
-static uint16_t cli_tmp10[]={32, 65, 32, 32};
-static uint16_t cli_tmp11[]={65, 32, 32};
-static uint16_t cli_tmp12[]={32, 32, 32};
-static uint16_t cli_tmp13[]={32, 65, 32};
-static uint16_t cli_tmp14[]={32, 65, 32, 65, 32};
-static uint16_t cli_tmp15[]={32, 32, 32, 32};
-static uint16_t cli_tmp16[]={32, 65, 32, 32, 32, 32};
-static uint16_t cli_tmp17[]={32, 87, 32};
-static uint16_t cli_tmp18[]={88};
-static uint16_t cli_tmp19[]={32, 32, 32, 32, 32, 32, 32, 32, 32};
-static uint16_t cli_tmp20[]={65, 32};
+static uint16_t cli_tmp10[]={32, 32};
+static uint16_t cli_tmp11[]={32, 32, 32};
+static uint16_t cli_tmp12[]={65, 32, 32};
+static uint16_t cli_tmp13[]={32, 32, 32, 32};
+static uint16_t cli_tmp14[]={32, 65, 32, 32};
+static uint16_t cli_tmp15[]={32, 85, 32};
+static uint16_t cli_tmp16[]={86};
+static uint16_t cli_tmp17[]={32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 8, 8, 8, 8, 8, 8, 8, 8, 8};
+static uint16_t cli_tmp18[]={8};
+static uint16_t cli_tmp19[]={32, 65, 32};
+static uint16_t cli_tmp20[]={32, 65, 32, 32, 32, 32};
static uint16_t cli_tmp21[]={32, 91, 32};
static uint16_t cli_tmp22[]={92};
-static uint16_t cli_tmp23[]={16, 8, 8, 8, 94, 93};
-static uint16_t cli_tmp24[]={8};
-static uint16_t cli_tmp25[]={95};
-static uint16_t cli_tmp26[]={8};
+static uint16_t cli_tmp23[]={32, 32, 32, 32, 32, 32, 32, 32, 32};
+static uint16_t cli_tmp24[]={65, 32};
+static uint16_t cli_tmp25[]={32, 95, 32};
+static uint16_t cli_tmp26[]={96};
+static uint16_t cli_tmp27[]={16, 8, 8, 8, 98, 97};
+static uint16_t cli_tmp28[]={8};
+static uint16_t cli_tmp29[]={99};
+static uint16_t cli_tmp30[]={8};
const struct cli_bc_type cli_apicall_types[]={
{DStructType, cli_tmp0, 13, 0, 0},
@@ -157,101 +179,123 @@ const struct cli_bc_type cli_apicall_types[]={
{DStructType, cli_tmp5, 8, 0, 0},
{DArrayType, cli_tmp6, 1, 0, 0},
{DArrayType, cli_tmp7, 64, 0, 0},
- {DFunctionType, cli_tmp8, 2, 0, 0},
+ {DFunctionType, cli_tmp8, 5, 0, 0},
{DFunctionType, cli_tmp9, 1, 0, 0},
- {DFunctionType, cli_tmp10, 4, 0, 0},
+ {DFunctionType, cli_tmp10, 2, 0, 0},
{DFunctionType, cli_tmp11, 3, 0, 0},
{DFunctionType, cli_tmp12, 3, 0, 0},
- {DFunctionType, cli_tmp13, 3, 0, 0},
- {DFunctionType, cli_tmp14, 5, 0, 0},
- {DFunctionType, cli_tmp15, 4, 0, 0},
- {DFunctionType, cli_tmp16, 6, 0, 0},
- {DFunctionType, cli_tmp17, 3, 0, 0},
- {DPointerType, cli_tmp18, 1, 0, 0},
- {DStructType, cli_tmp19, 9, 0, 0},
- {DFunctionType, cli_tmp20, 2, 0, 0},
+ {DFunctionType, cli_tmp13, 4, 0, 0},
+ {DFunctionType, cli_tmp14, 4, 0, 0},
+ {DFunctionType, cli_tmp15, 3, 0, 0},
+ {DPointerType, cli_tmp16, 1, 0, 0},
+ {DStructType, cli_tmp17, 23, 0, 0},
+ {DArrayType, cli_tmp18, 65, 0, 0},
+ {DFunctionType, cli_tmp19, 3, 0, 0},
+ {DFunctionType, cli_tmp20, 6, 0, 0},
{DFunctionType, cli_tmp21, 3, 0, 0},
{DPointerType, cli_tmp22, 1, 0, 0},
- {DStructType, cli_tmp23, 6, 0, 0},
- {DArrayType, cli_tmp24, 29, 0, 0},
- {DArrayType, cli_tmp25, 3, 0, 0},
- {DArrayType, cli_tmp26, 10, 0, 0}
+ {DStructType, cli_tmp23, 9, 0, 0},
+ {DFunctionType, cli_tmp24, 2, 0, 0},
+ {DFunctionType, cli_tmp25, 3, 0, 0},
+ {DPointerType, cli_tmp26, 1, 0, 0},
+ {DStructType, cli_tmp27, 6, 0, 0},
+ {DArrayType, cli_tmp28, 29, 0, 0},
+ {DArrayType, cli_tmp29, 3, 0, 0},
+ {DArrayType, cli_tmp30, 10, 0, 0}
};
const unsigned cli_apicall_maxtypes=sizeof(cli_apicall_types)/sizeof(cli_apicall_types[0]);
const struct cli_apicall cli_apicalls[]={
/* Bytecode APIcalls BEGIN */
- {"test1", 12, 0, 0},
- {"read", 13, 0, 1},
- {"write", 13, 1, 1},
- {"seek", 12, 1, 0},
- {"setvirusname", 13, 2, 1},
- {"debug_print_str", 13, 3, 1},
- {"debug_print_uint", 8, 0, 2},
- {"disasm_x86", 21, 4, 1},
- {"trace_directory", 13, 5, 1},
- {"trace_scope", 13, 6, 1},
- {"trace_source", 13, 7, 1},
- {"trace_op", 13, 8, 1},
- {"trace_value", 13, 9, 1},
- {"trace_ptr", 13, 10, 1},
- {"pe_rawaddr", 8, 1, 2},
- {"file_find", 13, 11, 1},
- {"file_byteat", 8, 2, 2},
- {"malloc", 20, 0, 3},
- {"test2", 8, 3, 2},
- {"get_pe_section", 17, 12, 1},
- {"fill_buffer", 16, 0, 4},
- {"extract_new", 8, 4, 2},
- {"read_number", 8, 5, 2},
+ {"test1", 11, 0, 0},
+ {"read", 19, 0, 1},
+ {"write", 19, 1, 1},
+ {"seek", 11, 1, 0},
+ {"setvirusname", 19, 2, 1},
+ {"debug_print_str", 19, 3, 1},
+ {"debug_print_uint", 10, 0, 2},
+ {"disasm_x86", 25, 4, 1},
+ {"trace_directory", 19, 5, 1},
+ {"trace_scope", 19, 6, 1},
+ {"trace_source", 19, 7, 1},
+ {"trace_op", 19, 8, 1},
+ {"trace_value", 19, 9, 1},
+ {"trace_ptr", 19, 10, 1},
+ {"pe_rawaddr", 10, 1, 2},
+ {"file_find", 19, 11, 1},
+ {"file_byteat", 10, 2, 2},
+ {"malloc", 24, 0, 3},
+ {"test2", 10, 3, 2},
+ {"get_pe_section", 21, 12, 1},
+ {"fill_buffer", 20, 0, 4},
+ {"extract_new", 10, 4, 2},
+ {"read_number", 10, 5, 2},
{"hashset_new", 9, 0, 5},
- {"hashset_add", 12, 2, 0},
- {"hashset_remove", 12, 3, 0},
- {"hashset_contains", 12, 4, 0},
- {"hashset_done", 8, 6, 2},
- {"hashset_empty", 8, 7, 2},
- {"buffer_pipe_new", 8, 8, 2},
- {"buffer_pipe_new_fromfile", 8, 9, 2},
- {"buffer_pipe_read_avail", 8, 10, 2},
- {"buffer_pipe_read_get", 11, 0, 6},
- {"buffer_pipe_read_stopped", 12, 5, 0},
- {"buffer_pipe_write_avail", 8, 11, 2},
- {"buffer_pipe_write_get", 11, 1, 6},
- {"buffer_pipe_write_stopped", 12, 6, 0},
- {"buffer_pipe_done", 8, 12, 2},
- {"inflate_init", 15, 0, 7},
- {"inflate_process", 8, 13, 2},
- {"inflate_done", 8, 14, 2},
- {"bytecode_rt_error", 8, 15, 2},
- {"jsnorm_init", 8, 16, 2},
- {"jsnorm_process", 8, 17, 2},
- {"jsnorm_done", 8, 18, 2},
- {"ilog2", 12, 7, 0},
- {"ipow", 15, 1, 7},
- {"iexp", 15, 2, 7},
- {"isin", 15, 3, 7},
- {"icos", 15, 4, 7},
- {"memstr", 14, 0, 8},
- {"hex2ui", 12, 8, 0},
- {"atoi", 13, 13, 1},
- {"debug_print_str_start", 13, 14, 1},
- {"debug_print_str_nonl", 13, 15, 1},
- {"entropy_buffer", 13, 16, 1},
- {"map_new", 12, 9, 0},
- {"map_addkey", 10, 0, 9},
- {"map_setvalue", 10, 1, 9},
- {"map_remove", 10, 2, 9},
- {"map_find", 10, 3, 9},
- {"map_getvaluesize", 8, 19, 2},
- {"map_getvalue", 11, 2, 6},
- {"map_done", 8, 20, 2},
- {"file_find_limit", 10, 4, 9},
+ {"hashset_add", 11, 2, 0},
+ {"hashset_remove", 11, 3, 0},
+ {"hashset_contains", 11, 4, 0},
+ {"hashset_done", 10, 6, 2},
+ {"hashset_empty", 10, 7, 2},
+ {"buffer_pipe_new", 10, 8, 2},
+ {"buffer_pipe_new_fromfile", 10, 9, 2},
+ {"buffer_pipe_read_avail", 10, 10, 2},
+ {"buffer_pipe_read_get", 12, 0, 6},
+ {"buffer_pipe_read_stopped", 11, 5, 0},
+ {"buffer_pipe_write_avail", 10, 11, 2},
+ {"buffer_pipe_write_get", 12, 1, 6},
+ {"buffer_pipe_write_stopped", 11, 6, 0},
+ {"buffer_pipe_done", 10, 12, 2},
+ {"inflate_init", 13, 0, 7},
+ {"inflate_process", 10, 13, 2},
+ {"inflate_done", 10, 14, 2},
+ {"bytecode_rt_error", 10, 15, 2},
+ {"jsnorm_init", 10, 16, 2},
+ {"jsnorm_process", 10, 17, 2},
+ {"jsnorm_done", 10, 18, 2},
+ {"ilog2", 11, 7, 0},
+ {"ipow", 13, 1, 7},
+ {"iexp", 13, 2, 7},
+ {"isin", 13, 3, 7},
+ {"icos", 13, 4, 7},
+ {"memstr", 8, 0, 8},
+ {"hex2ui", 11, 8, 0},
+ {"atoi", 19, 13, 1},
+ {"debug_print_str_start", 19, 14, 1},
+ {"debug_print_str_nonl", 19, 15, 1},
+ {"entropy_buffer", 19, 16, 1},
+ {"map_new", 11, 9, 0},
+ {"map_addkey", 14, 0, 9},
+ {"map_setvalue", 14, 1, 9},
+ {"map_remove", 14, 2, 9},
+ {"map_find", 14, 3, 9},
+ {"map_getvaluesize", 10, 19, 2},
+ {"map_getvalue", 12, 2, 6},
+ {"map_done", 10, 20, 2},
+ {"file_find_limit", 14, 4, 9},
{"engine_functionality_level", 9, 1, 5},
{"engine_dconf_level", 9, 2, 5},
{"engine_scan_options", 9, 3, 5},
{"engine_db_options", 9, 4, 5},
- {"extract_set_container", 8, 21, 2},
- {"input_switch", 8, 22, 2}
+ {"extract_set_container", 10, 21, 2},
+ {"input_switch", 10, 22, 2},
+ {"get_environment", 15, 17, 1},
+ {"disable_bytecode_if", 14, 5, 9},
+ {"disable_jit_if", 14, 6, 9},
+ {"version_compare", 8, 1, 8},
+ {"check_platform", 13, 5, 7},
+ {"pdf_get_obj_num", 9, 5, 5},
+ {"pdf_get_flags", 9, 6, 5},
+ {"pdf_set_flags", 10, 23, 2},
+ {"pdf_lookupobj", 10, 24, 2},
+ {"pdf_getobjsize", 10, 25, 2},
+ {"pdf_getobj", 12, 3, 6},
+ {"pdf_getobjid", 10, 26, 2},
+ {"pdf_getobjflags", 10, 27, 2},
+ {"pdf_setobjflags", 11, 10, 0},
+ {"pdf_get_offset", 10, 28, 2},
+ {"pdf_get_phase", 9, 7, 5},
+ {"pdf_get_dumpedobjid", 9, 8, 5},
+ {"matchicon", 8, 2, 8}
/* Bytecode APIcalls END */
};
const cli_apicall_int2 cli_apicalls0[] = {
@@ -264,7 +308,8 @@ const cli_apicall_int2 cli_apicalls0[] = {
(cli_apicall_int2)cli_bcapi_buffer_pipe_write_stopped,
(cli_apicall_int2)cli_bcapi_ilog2,
(cli_apicall_int2)cli_bcapi_hex2ui,
- (cli_apicall_int2)cli_bcapi_map_new
+ (cli_apicall_int2)cli_bcapi_map_new,
+ (cli_apicall_int2)cli_bcapi_pdf_setobjflags
};
const cli_apicall_pointer cli_apicalls1[] = {
(cli_apicall_pointer)cli_bcapi_read,
@@ -283,7 +328,8 @@ const cli_apicall_pointer cli_apicalls1[] = {
(cli_apicall_pointer)cli_bcapi_atoi,
(cli_apicall_pointer)cli_bcapi_debug_print_str_start,
(cli_apicall_pointer)cli_bcapi_debug_print_str_nonl,
- (cli_apicall_pointer)cli_bcapi_entropy_buffer
+ (cli_apicall_pointer)cli_bcapi_entropy_buffer,
+ (cli_apicall_pointer)cli_bcapi_get_environment
};
const cli_apicall_int1 cli_apicalls2[] = {
(cli_apicall_int1)cli_bcapi_debug_print_uint,
@@ -308,7 +354,13 @@ const cli_apicall_int1 cli_apicalls2[] = {
(cli_apicall_int1)cli_bcapi_map_getvaluesize,
(cli_apicall_int1)cli_bcapi_map_done,
(cli_apicall_int1)cli_bcapi_extract_set_container,
- (cli_apicall_int1)cli_bcapi_input_switch
+ (cli_apicall_int1)cli_bcapi_input_switch,
+ (cli_apicall_int1)cli_bcapi_pdf_set_flags,
+ (cli_apicall_int1)cli_bcapi_pdf_lookupobj,
+ (cli_apicall_int1)cli_bcapi_pdf_getobjsize,
+ (cli_apicall_int1)cli_bcapi_pdf_getobjid,
+ (cli_apicall_int1)cli_bcapi_pdf_getobjflags,
+ (cli_apicall_int1)cli_bcapi_pdf_get_offset
};
const cli_apicall_malloclike cli_apicalls3[] = {
(cli_apicall_malloclike)cli_bcapi_malloc
@@ -321,28 +373,38 @@ const cli_apicall_allocobj cli_apicalls5[] = {
(cli_apicall_allocobj)cli_bcapi_engine_functionality_level,
(cli_apicall_allocobj)cli_bcapi_engine_dconf_level,
(cli_apicall_allocobj)cli_bcapi_engine_scan_options,
- (cli_apicall_allocobj)cli_bcapi_engine_db_options
+ (cli_apicall_allocobj)cli_bcapi_engine_db_options,
+ (cli_apicall_allocobj)cli_bcapi_pdf_get_obj_num,
+ (cli_apicall_allocobj)cli_bcapi_pdf_get_flags,
+ (cli_apicall_allocobj)cli_bcapi_pdf_get_phase,
+ (cli_apicall_allocobj)cli_bcapi_pdf_get_dumpedobjid
};
const cli_apicall_bufget cli_apicalls6[] = {
(cli_apicall_bufget)cli_bcapi_buffer_pipe_read_get,
(cli_apicall_bufget)cli_bcapi_buffer_pipe_write_get,
- (cli_apicall_bufget)cli_bcapi_map_getvalue
+ (cli_apicall_bufget)cli_bcapi_map_getvalue,
+ (cli_apicall_bufget)cli_bcapi_pdf_getobj
};
const cli_apicall_int3 cli_apicalls7[] = {
(cli_apicall_int3)cli_bcapi_inflate_init,
(cli_apicall_int3)cli_bcapi_ipow,
(cli_apicall_int3)cli_bcapi_iexp,
(cli_apicall_int3)cli_bcapi_isin,
- (cli_apicall_int3)cli_bcapi_icos
+ (cli_apicall_int3)cli_bcapi_icos,
+ (cli_apicall_int3)cli_bcapi_check_platform
};
const cli_apicall_2bufs cli_apicalls8[] = {
- (cli_apicall_2bufs)cli_bcapi_memstr
+ (cli_apicall_2bufs)cli_bcapi_memstr,
+ (cli_apicall_2bufs)cli_bcapi_version_compare,
+ (cli_apicall_2bufs)cli_bcapi_matchicon
};
const cli_apicall_ptrbufid cli_apicalls9[] = {
(cli_apicall_ptrbufid)cli_bcapi_map_addkey,
(cli_apicall_ptrbufid)cli_bcapi_map_setvalue,
(cli_apicall_ptrbufid)cli_bcapi_map_remove,
(cli_apicall_ptrbufid)cli_bcapi_map_find,
- (cli_apicall_ptrbufid)cli_bcapi_file_find_limit
+ (cli_apicall_ptrbufid)cli_bcapi_file_find_limit,
+ (cli_apicall_ptrbufid)cli_bcapi_disable_bytecode_if,
+ (cli_apicall_ptrbufid)cli_bcapi_disable_jit_if
};
const unsigned cli_apicall_maxapi = sizeof(cli_apicalls)/sizeof(cli_apicalls[0]);
diff --git a/libclamav/bytecode_api_impl.h b/libclamav/bytecode_api_impl.h
index dd852c7..c6be9c8 100644
--- a/libclamav/bytecode_api_impl.h
+++ b/libclamav/bytecode_api_impl.h
@@ -30,6 +30,7 @@
#define BYTECODE_API_IMPL_H
struct cli_bc_bctx;
+struct cli_environment;
uint32_t cli_bcapi_test1(struct cli_bc_ctx *ctx , uint32_t, uint32_t);
int32_t cli_bcapi_read(struct cli_bc_ctx *ctx , uint8_t*, int32_t);
int32_t cli_bcapi_write(struct cli_bc_ctx *ctx , uint8_t*, int32_t);
@@ -101,5 +102,23 @@ uint32_t cli_bcapi_engine_scan_options(struct cli_bc_ctx *ctx );
uint32_t cli_bcapi_engine_db_options(struct cli_bc_ctx *ctx );
int32_t cli_bcapi_extract_set_container(struct cli_bc_ctx *ctx , uint32_t);
int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx , int32_t);
+uint32_t cli_bcapi_get_environment(struct cli_bc_ctx *ctx , struct cli_environment*, uint32_t);
+uint32_t cli_bcapi_disable_bytecode_if(struct cli_bc_ctx *ctx , const int8_t*, uint32_t, uint32_t);
+uint32_t cli_bcapi_disable_jit_if(struct cli_bc_ctx *ctx , const int8_t*, uint32_t, uint32_t);
+int32_t cli_bcapi_version_compare(struct cli_bc_ctx *ctx , const uint8_t*, uint32_t, const uint8_t*, uint32_t);
+uint32_t cli_bcapi_check_platform(struct cli_bc_ctx *ctx , uint32_t, uint32_t, uint32_t);
+int32_t cli_bcapi_pdf_get_obj_num(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_get_flags(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_set_flags(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_lookupobj(struct cli_bc_ctx *ctx , uint32_t);
+uint32_t cli_bcapi_pdf_getobjsize(struct cli_bc_ctx *ctx , int32_t);
+uint8_t* cli_bcapi_pdf_getobj(struct cli_bc_ctx *ctx , int32_t, uint32_t);
+int32_t cli_bcapi_pdf_getobjid(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_getobjflags(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_setobjflags(struct cli_bc_ctx *ctx , int32_t, int32_t);
+int32_t cli_bcapi_pdf_get_offset(struct cli_bc_ctx *ctx , int32_t);
+int32_t cli_bcapi_pdf_get_phase(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_pdf_get_dumpedobjid(struct cli_bc_ctx *ctx );
+int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t*, int32_t, const uint8_t*, int32_t);
#endif
diff --git a/libclamav/bytecode_detect.c b/libclamav/bytecode_detect.c
new file mode 100644
index 0000000..6311314
--- /dev/null
+++ b/libclamav/bytecode_detect.c
@@ -0,0 +1,320 @@
+/*
+ * Detect environment for bytecode.
+ *
+ * Copyright (C) 2009-2010 Sourcefire, Inc.
+ *
+ * Authors: Török Edvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+#include "target.h"
+#include "cltypes.h"
+
+#include "bytecode_detect.h"
+#include "others.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HAVE_UNAME_SYSCALL
+#include <sys/utsname.h>
+#endif
+
+#define CHECK_ARCH(a) if (!strcmp(TARGET_ARCH_TYPE, #a)) env->arch = arch_##a
+
+extern int have_clamjit;
+
+static void cli_print_environment(struct cli_environment *env)
+{
+ uint32_t id_a = env->platform_id_a;
+ uint32_t id_b = env->platform_id_b;
+ uint32_t id_c = env->platform_id_c;
+ /* the bytecode instruction that exactly identifies this platform */
+ /* the space separated groups can be a concrete value, or 0xff for ANY */
+ cli_dbgmsg("environment detected:\n");
+ cli_dbgmsg("check_platform(0x%08x, 0x%08x, 0x%08x)\n",
+ id_a, id_b, id_c);
+ cli_dbgmsg("check_platform(0x%02x %01x %01x %02x %02x,"
+ "0x%01x %01x %02x %02x %02x,"
+ "0x%02x %02x %02x %02x)\n",
+ env->os_category, env->arch, env->compiler,
+ env->functionality_level,
+ env->dconf_level,
+ env->big_endian,
+ env->sizeof_ptr,
+ (env->cpp_version >> 16)&0xff,
+ (env->cpp_version >> 8)&0xff,
+ env->cpp_version&0xff,
+ env->os_features,
+ (env->c_version >> 16)&0xff,
+ (env->c_version >> 8)&0xff,
+ env->c_version&0xff);
+ cli_dbgmsg("check_platform( OS CPU COM FL DCONF,BE PTR CXX VV.VV.VV, FLG CC VV.VV.VV)\n");
+ cli_dbgmsg("Engine version: %s\n", env->engine_version);
+ cli_dbgmsg("Host triple: %s\n", env->triple);
+ cli_dbgmsg("Host CPU: %s\n", env->cpu);
+ cli_dbgmsg("OS: %s\n", env->sysname);
+ cli_dbgmsg("OS release: %s\n", env->release);
+ cli_dbgmsg("OS version: %s\n", env->version);
+ cli_dbgmsg("OS hardware: %s\n", env->machine);
+ cli_dbgmsg("OS LLVM category: %d\n", env->os);
+ cli_dbgmsg("Has JIT compiled: %d\n", env->has_jit_compiled);
+ cli_dbgmsg("------------------------------------------------------\n");
+}
+
+#ifdef __linux__
+
+static int detect_PaX(void)
+{
+ char line[128];
+ int pax = 0;
+ FILE *f = fopen("/proc/self/status", "r");
+ if (!f)
+ return 0;
+ while (fgets(line, sizeof(line), f)) {
+ if (!memcmp(line, "PaX:", 4)) {
+ pax = 1;
+ if (!strchr(line,'m'))
+ pax = 2;
+ break;
+ }
+ }
+ fclose(f);
+ return pax;
+}
+
+static int detect_SELinux(void)
+{
+ char line[128];
+ int selinux = 0;
+ int enforce = 0;
+ FILE *f = fopen("/proc/filesystems", "r");
+ if (!f) {
+ f = fopen("/selinux/enforce", "r");
+ if (!f && errno == EACCES)
+ return 2;
+ if (fscanf(f, "%d", &enforce) == 1)
+ selinux = 2;
+ fclose(f);
+ return selinux;
+ }
+ while (fgets(line, sizeof(line), f)) {
+ if (strstr(line, "selinuxfs\n")) {
+ selinux = 1;
+ break;
+ }
+ }
+ fclose(f);
+ if (!selinux)
+ return 0;
+
+ f = fopen("/selinux/enforce", "r");
+ if (f && fscanf(f, "%d", &enforce) == 1) {
+ if (enforce == 1)
+ selinux = 2;
+ if (enforce == -1)
+ selinux = 0;
+ }
+ fclose(f);
+ return selinux;
+}
+
+static void detect_os_features(uint8_t *os_features)
+{
+ int features = 0;
+ switch (detect_PaX()) {
+ case 2:
+ features |= 1 << feature_pax_mprotect;
+ /* fall through */
+ case 1:
+ features |= 1 << feature_pax;
+ break;
+ default:
+ break;
+ }
+ switch (detect_SELinux()) {
+ case 2:
+ features |= 1 << feature_selinux_enforcing;
+ /* fall through */
+ case 1:
+ features |= 1 << feature_selinux;
+ break;
+ default:
+ break;
+ }
+
+ *os_features = features;
+}
+#else
+static void detect_os_features(uint8_t *os_features)
+{
+ *os_features = 0;
+}
+#endif
+
+/* OS features :
+ * Linux: PaX << 2| SELinux << 1| mmap-RWX
+ * Other: mmap-RWX */
+
+void cli_detect_environment(struct cli_environment *env)
+{
+ memset(env, 0, sizeof(*env));
+#if WORDS_BIGENDIAN == 0
+ env->big_endian = 0;
+#else
+ env->big_endian = 1;
+#endif
+ env->sizeof_ptr = sizeof(void*);
+
+ /* -- Detect arch -- */
+ CHECK_ARCH(i386);
+ else CHECK_ARCH(x86_64);
+ else if (!strcmp(TARGET_ARCH_TYPE,"ppc")) env->arch = arch_ppc32;/* llvm will fix ppc64 */
+ else CHECK_ARCH(arm);
+ else CHECK_ARCH(sparc);
+ else CHECK_ARCH(sparc64);
+ else CHECK_ARCH(mips);
+ else CHECK_ARCH(mips64);
+ else CHECK_ARCH(alpha);
+ else CHECK_ARCH(hppa1);
+ else CHECK_ARCH(hppa2);
+ else CHECK_ARCH(m68k);
+ else env->arch = arch_unknown;
+
+ /* -- Detect OS -- */
+#ifdef C_AIX
+ env->os_category = os_aix;
+#elif defined(C_BEOS)
+ env->os_category = os_beos;
+ /* DARWIN must come before BSD since it defines both */
+#elif defined(C_DARWIN)
+ env->os_category = os_darwin;
+#elif defined(C_BSD)
+ env->os_category = os_bsd;
+#elif defined(C_GNU_HURD)
+ env->os_category = os_gnu_hurd;
+#elif defined(C_HPUX)
+ env->os_category = os_hpux;
+#elif defined(C_INTERIX)
+ env->os_category = os_interix;
+#elif defined(C_IRIX)
+ env->os_category = os_irix;
+#elif defined(C_KFREEBSD_GNU)
+ env->os_category = os_kfreebsd_gnu;
+#elif defined(C_LINUX)
+ env->os_category = os_linux;
+#elif defined(C_OS2)
+ env->os_category = os_os2;
+#elif defined(C_OSF)
+ env->os_category = os_osf;
+#elif defined(C_QNX6)
+ env->os_category = os_qnx6;
+#elif defined(C_SOLARIS)
+ env->os_category = os_solaris;
+#elif defined(_WIN64)
+ env->os_category = os_win64;
+#elif defined(_WIN32)
+ env->os_category = os_win32;
+#else
+ env->os_category = os_generic;
+#endif
+
+ env->os = llvm_os_UnknownOS;
+ /* -- Detect compiler -- */
+
+ /* check GNUC last, because some other compilers might define it */
+#ifdef __INTEL_COMPILER
+ env->compiler = compiler_intel;
+ env->c_version = __INTEL_COMPILER;
+#elif defined(_MSC_VER)
+ env->compiler = compiler_msc;
+ env->c_version = _MSC_VER;
+#elif defined(__SUNPRO_C)
+ env->compiler = compiler_sun;
+ env->c_version = __SUNPRO_C;
+#elif defined(__GNUC__)
+
+#ifdef __clang__
+ env->compiler = compiler_clang;
+#elif defined(__llvm__)
+ env->compiler = compiler_llvm;
+#else
+ env->compiler = compiler_gnuc;
+#endif
+ env->c_version =
+ MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+
+#else
+ env->compiler = compiler_other;
+ env->c_version = 0;
+#endif
+ env->cpp_version = 0;
+
+ env->has_jit_compiled = have_clamjit;
+
+ /* engine */
+ env->functionality_level = cl_retflevel();
+ env->dconf_level = CL_FLEVEL_DCONF;
+
+ INIT_STRFIELD(env->engine_version, cl_retver());
+#ifdef HAVE_UNAME_SYSCALL
+ {
+ struct utsname name;
+ if (uname(&name) == 0) {
+ INIT_STRFIELD(env->sysname, name.sysname);
+ INIT_STRFIELD(env->release, name.release);
+ INIT_STRFIELD(env->version, name.version);
+ INIT_STRFIELD(env->machine, name.machine);
+ }
+ }
+#endif
+#ifdef _WIN32
+ {
+ OSVERSIONINFOEX info;
+ info.dwOSVersionInfoSize = sizeof(info);
+ if (GetVersionEx((OSVERSIONINFO *)&info) != 0 && info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ if (info.wProductType == VER_NT_WORKSTATION)
+ INIT_STRFIELD(env->sysname, "Microsoft Windows");
+ else
+ INIT_STRFIELD(env->sysname, "Microsoft Windows Server");
+ snprintf((char*)env->release, sizeof(env->release), "%d.%d SP%d.%d",
+ info.dwMajorVersion, info.dwMinorVersion,
+ info.wServicePackMajor, info.wServicePackMinor);
+ snprintf((char*)env->version, sizeof(env->version),"Build %d",
+ info.dwBuildNumber);
+ }
+ }
+
+#endif
+ if (!env->sysname[0]) {
+ INIT_STRFIELD(env->sysname, TARGET_OS_TYPE);
+ }
+
+ detect_os_features(&env->os_features);
+
+ cli_detect_env_jit(env);
+
+ env->platform_id_a = (env->os_category << 24) | (env->arch << 20) |
+ (env->compiler << 16) | (env->functionality_level << 8) |
+ (env->dconf_level);
+ env->platform_id_b = (env->big_endian << 28) | (env->sizeof_ptr << 24) |
+ env->cpp_version;
+ env->platform_id_c = (env->os_features << 24) | env->c_version;
+ cli_print_environment(env);
+}
diff --git a/libclamav/bytecode_detect.h b/libclamav/bytecode_detect.h
new file mode 100644
index 0000000..f864aab
--- /dev/null
+++ b/libclamav/bytecode_detect.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009 Sourcefire, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef BYTECODE_DETECT_H
+#define BYTECODE_DETECT_H
+/* mostly from m4/acinclude.m4 */
+enum arch_list {
+ arch_unknown=0,
+ arch_i386,
+ arch_x86_64,
+ arch_ppc32,
+ arch_ppc64,
+ arch_arm,
+ arch_sparc,
+ arch_sparc64,
+ arch_mips,
+ arch_mips64,
+ arch_alpha,
+ arch_hppa1,
+ arch_hppa2,
+ arch_m68k,
+ arch_ANY = 0xf
+};
+
+/* from ClamAV's configure.in */
+enum os_kind_conf {
+ os_unknown=0,
+ os_aix,
+ os_beos,
+ os_bsd,
+ os_darwin,
+ os_gnu_hurd,
+ os_hpux,
+ os_interix,
+ os_irix,
+ os_kfreebsd_gnu,
+ os_linux,
+ os_os2,
+ os_osf,
+ os_qnx6,
+ os_solaris,
+ os_win32,
+ os_win64,
+ os_ANY = 0xff
+};
+
+enum os_kind_llvm {
+ llvm_os_UnknownOS=0,
+ llvm_os_AuroraUX,
+ llvm_os_Cygwin,
+ llvm_os_Darwin,
+ llvm_os_DragonFly,
+ llvm_os_FreeBSD,
+ llvm_os_Linux,
+ llvm_os_Lv2,
+ llvm_os_MinGW32,
+ llvm_os_MinGW64,
+ llvm_os_NetBSD,
+ llvm_os_OpenBSD,
+ llvm_os_Psp,
+ llvm_os_Solaris,
+ llvm_os_Win32,
+ llvm_os_Haiku,
+ llvm_os_ANY = 0xff
+};
+
+/* the ones from clamconf */
+enum compiler_list {
+ compiler_unknown = 0,
+ compiler_gnuc,
+ compiler_llvm,
+ compiler_clang,
+ compiler_intel,
+ compiler_msc,
+ compiler_sun,
+ compiler_other,
+ compiler_ANY = 0xf
+};
+
+enum endian_list {
+ endian_little=0,
+ endian_big=1,
+ endian_ANY=0xf
+};
+
+enum os_feature_bits {
+ feature_map_rwx = 0,
+ feature_selinux = 1,
+ feature_selinux_enforcing = 2,
+ feature_pax = 3,
+ feature_pax_mprotect = 4
+};
+
+struct cli_environment {
+ uint32_t platform_id_a;
+ uint32_t platform_id_b;
+ uint32_t platform_id_c;
+ uint32_t c_version;
+ uint32_t cpp_version; /* LLVM only */
+ /* engine */
+ uint32_t functionality_level;
+ uint32_t dconf_level;
+ int8_t engine_version[65];
+ /* detailed runtime info */
+ int8_t triple[65];/* LLVM only */
+ int8_t cpu[65];/* LLVM only */
+ /* uname */
+ int8_t sysname[65];
+ int8_t release[65];
+ int8_t version[65];
+ int8_t machine[65];
+ /* build time */
+ uint8_t big_endian;
+ uint8_t sizeof_ptr;
+ uint8_t arch;
+ uint8_t os_category;/* from configure */
+ uint8_t os;/* from LLVM if available */
+ uint8_t compiler;
+ uint8_t has_jit_compiled;
+ uint8_t os_features;
+ uint8_t reserved0;
+};
+
+#ifndef __CLAMBC__
+#define MAKE_VERSION(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | d)
+#define INIT_STRFIELD(field, value) do {\
+ strncpy((char*)(field), (value), sizeof(field)-1);\
+ (field)[sizeof(field)-1]=0;\
+} while (0)
+#endif
+
+void cli_detect_env_jit(struct cli_environment *env);
+void cli_detect_environment(struct cli_environment *env);
+#endif
diff --git a/libclamav/bytecode_nojit.c b/libclamav/bytecode_nojit.c
index 62588cb..ec961a9 100644
--- a/libclamav/bytecode_nojit.c
+++ b/libclamav/bytecode_nojit.c
@@ -53,7 +53,7 @@ int cli_bytecode_init_jit(struct cli_all_bc *allbc, unsigned dconfmask)
return CL_SUCCESS;
}
-int cli_bytecode_done_jit(struct cli_all_bc *allbc)
+int cli_bytecode_done_jit(struct cli_all_bc *allbc, int partial)
{
return CL_SUCCESS;
}
@@ -78,3 +78,7 @@ void cli_printcxxver()
{
/* Empty */
}
+void cli_detect_env_jit(struct cli_environment *env)
+{
+ /* Empty */
+}
diff --git a/libclamav/bytecode_priv.h b/libclamav/bytecode_priv.h
index b61ea2d..8ac8d9d 100644
--- a/libclamav/bytecode_priv.h
+++ b/libclamav/bytecode_priv.h
@@ -39,8 +39,8 @@ typedef uint16_t funcid_t;
struct cli_bc_callop {
operand_t* ops;
uint16_t* opsizes;
- uint8_t numOps;
funcid_t funcid;
+ uint8_t numOps;
};
struct branch {
@@ -59,8 +59,8 @@ typedef uint8_t interp_op_t;
struct cli_bc_inst {
enum bc_opcode opcode;
uint16_t type;
- interp_op_t interp_op;/* opcode for interpreter */
operand_t dest;
+ interp_op_t interp_op;/* opcode for interpreter */
union {
operand_t unaryop;
struct cli_bc_cast cast;
@@ -96,8 +96,8 @@ struct cli_bc_func {
struct cli_bc_dbgnode_element {
unsigned nodeid;
- char *string;
unsigned len;
+ char *string;
uint64_t constant;
};
@@ -139,6 +139,8 @@ struct bc_jsnorm {
struct cli_bc_ctx {
uint8_t timeout;/* must be first byte in struct! */
+ uint16_t funcid;
+ unsigned numParams;
/* id and params of toplevel function called */
const struct cli_bc *bc;
const struct cli_bc_func *func;
@@ -147,47 +149,58 @@ struct cli_bc_ctx {
uint16_t *opsizes;
char *values;
operand_t *operands;
- uint16_t funcid;
- unsigned numParams;
uint32_t file_size;
+ int outfd;
off_t off;
fmap_t *fmap;
fmap_t *save_map;
const char *virname;
struct cli_bc_hooks hooks;
+ struct cli_exe_info exeinfo;
+ uint32_t lsigcnt[64];
+ uint32_t lsigoff[64];
+ uint32_t pdf_nobjs;
+ struct pdf_obj *pdf_objs;
+ uint32_t* pdf_flags;
+ uint32_t pdf_size;
+ uint32_t pdf_startoff;
+ unsigned pdf_phase;
+ int32_t pdf_dumpedid;
const struct cli_exe_section *sections;
- int outfd;
+ uint32_t resaddr;
char *tempfile;
void *ctx;
unsigned written;
unsigned filewritten;
unsigned found;
+ unsigned ninflates;
bc_dbg_callback_trace trace;
bc_dbg_callback_trace_op trace_op;
bc_dbg_callback_trace_val trace_val;
bc_dbg_callback_trace_ptr trace_ptr;
- unsigned trace_level;
const char *directory;
const char *file;
const char *scope;
+ unsigned trace_level;
uint32_t scopeid;
unsigned line;
unsigned col;
mpool_t *mpool;
struct bc_inflate* inflates;
- unsigned ninflates;
struct bc_buffer *buffers;
unsigned nbuffers;
- struct cli_hashset *hashsets;
unsigned nhashsets;
- struct bc_jsnorm* jsnorms;
unsigned njsnorms;
- char *jsnormdir;
unsigned jsnormwritten;
+ struct cli_hashset *hashsets;
+ struct bc_jsnorm* jsnorms;
+ char *jsnormdir;
struct cli_map *maps;
unsigned nmaps;
unsigned containertype;
unsigned extracted_file_input;
+ const struct cli_environment *env;
+ unsigned bytecode_disable_status;
};
struct cli_all_bc;
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst);
@@ -199,7 +212,7 @@ extern "C" {
int cli_vm_execute_jit(const struct cli_all_bc *bcs, struct cli_bc_ctx *ctx, const struct cli_bc_func *func);
int cli_bytecode_prepare_jit(struct cli_all_bc *bc);
int cli_bytecode_init_jit(struct cli_all_bc *bc, unsigned dconfmask);
-int cli_bytecode_done_jit(struct cli_all_bc *bc);
+int cli_bytecode_done_jit(struct cli_all_bc *bc, int partial);
#ifdef __cplusplus
}
diff --git a/libclamav/bytecode_vm.c b/libclamav/bytecode_vm.c
index c60b6a4..33c16cd 100644
--- a/libclamav/bytecode_vm.c
+++ b/libclamav/bytecode_vm.c
@@ -199,8 +199,8 @@ struct stack_entry {
struct stack_entry *prev;
const struct cli_bc_func *func;
operand_t ret;
- struct cli_bc_bb *bb;
unsigned bb_inst;
+ struct cli_bc_bb *bb;
char *values;
};
@@ -526,6 +526,7 @@ static inline int64_t ptr_register_glob_fixedid(struct ptr_infos *infos,
sinfos = cli_realloc(infos->glob_infos, sizeof(*sinfos)*n);
if (!sinfos)
return 0;
+ memset(sinfos + infos->nglobs, 0, (n - infos->nglobs)*sizeof(*sinfos));
infos->glob_infos = sinfos;
infos->nglobs = n;
}
diff --git a/libclamav/c++/GenList.pl b/libclamav/c++/GenList.pl
new file mode 100755
index 0000000..42966c3
--- /dev/null
+++ b/libclamav/c++/GenList.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+my $path = $ARGV[0];
+`(cd $path/tools/llvm-config; make ENABLE_OPTIMIZED=0 llvm-config-perobjincl)`;
+
+my %compdeps;
+my @codegencomponents = ('x86codegen','powerpccodegen','armcodegen');
+my @allnonsys = ('support','jit','fullcodegen', at codegencomponents);
+my @allcomponents= ('system', at allnonsys);
+my $allJIT="jit core lib/Support/SourceMgr.o lib/Analysis/PointerTracking.o lib/Transforms/Scalar/DCE.o lib/Analysis/IPA/CallGraph.o";
+for my $component (@allcomponents) {
+ $/ = " ";
+ $component =~ s/^fullcodegen/codegen interpreter jit target/;
+ if ($component =~ "^jit") {
+ open DEPS, "$path/tools/llvm-config/llvm-config-perobjincl --libnames $allJIT|";
+ } else {
+ open DEPS, "$path/tools/llvm-config/llvm-config-perobjincl --libnames $component|";
+ }
+ $component =~ s/^codegen.+/fullcodegen/;
+ while (<DEPS>) {
+ chomp;
+ s/[\n\r]//;
+ next if (!/\.o$/);
+ s/Support\/reg(.*).o/Support\/reg$1.c/;
+ s/\.o$/.cpp/;
+ $compdeps{$component}{$_}=1;
+ }
+ close DEPS or die "llvm-config failed";
+}
+
+# System is always linked in, so remove it from all else
+foreach my $systemcomp (keys %{$compdeps{'system'}}) {
+ foreach my $component (@allnonsys) {
+ delete $compdeps{$component}{$systemcomp} if defined $compdeps{$component}{$systemcomp};
+ }
+}
+
+# Eliminate components from codegen that are in JIT already.
+# and compute common codegen components.
+my %intersection = ();
+my %count = ();
+
+foreach my $codegen (@codegencomponents) {
+ my %newdeps;
+ for my $depobj (keys %{$compdeps{$codegen}}) {
+ next if $compdeps{'jit'}{$depobj};
+ $newdeps{$depobj}=1;
+ $count{$depobj}++;
+ }
+ $compdeps{$codegen} = \%newdeps;
+}
+foreach my $element (keys %count) {
+ $intersection{$element}=1 if $count{$element} > 1;
+}
+
+foreach my $codegen (@codegencomponents) {
+ foreach my $element (keys %intersection) {
+ delete $compdeps{$codegen}{$element};
+ }
+ # Move the system and support objs required (even if not common) to codegen,
+ # since these were already built for tblgen.
+ foreach my $element (keys %{$compdeps{'system'}}) {
+ next unless defined $compdeps{$codegen}{$element};
+ delete $compdeps{$codegen}{$element};
+ $intersection{$element}=1;
+ }
+ foreach my $element (keys %{$compdeps{'support'}}) {
+ next unless defined $compdeps{$codegen}{$element};
+ delete $compdeps{$codegen}{$element};
+ $intersection{$element}=1;
+ }
+}
+
+ at allcomponents=(@allcomponents,'codegen');
+$compdeps{'codegen'}=\%intersection;
+foreach my $comp (keys %{$compdeps{'codegen'}}) {
+ delete $compdeps{'fullcodegen'}{$comp};
+}
+foreach my $comp (keys %{$compdeps{'jit'}}) {
+ delete $compdeps{'fullcodegen'}{$comp};
+}
+foreach my $comp (keys %{$compdeps{'support'}}) {
+ $compdeps{'support_nodups'}{$comp}=1;
+}
+
+foreach my $comp (keys %{$compdeps{'jit'}}) {
+ next unless defined $compdeps{'support_nodups'}{$comp};
+ delete $compdeps{'support_nodups'}{$comp};
+}
+ at allcomponents=(@allcomponents,'codegen','support_nodups');
+
+foreach my $comp (@allcomponents) {
+ print "libllvm$comp"."_la_SOURCES=";
+ foreach my $dep (sort keys %{$compdeps{$comp}}) {
+ print "\\\n\tllvm/$dep";
+ }
+ print "\n\n";
+}
+
diff --git a/libclamav/c++/Makefile.am b/libclamav/c++/Makefile.am
index 91f91e5..9f7c8a4 100644
--- a/libclamav/c++/Makefile.am
+++ b/libclamav/c++/Makefile.am
@@ -47,7 +47,8 @@ libclamavcxx_la_CXXFLAGS = $(LLVM_CXXFLAGS)
libclamavcxx_la_SOURCES = bytecode2llvm.cpp\
ClamBCRTChecks.cpp\
ClamBCModule.h\
- ClamBCDiagnostics.h
+ ClamBCDiagnostics.h\
+ detect.cpp
if BUILD_X86
libclamavcxx_la_LIBADD+=libllvmx86codegen.la
libclamavcxx_la_DEPENDENCIES+=libllvmx86codegen.la
diff --git a/libclamav/c++/Makefile.in b/libclamav/c++/Makefile.in
index 8900575..f7000f4 100644
--- a/libclamav/c++/Makefile.in
+++ b/libclamav/c++/Makefile.in
@@ -108,7 +108,7 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
am_libclamavcxx_la_OBJECTS = libclamavcxx_la-bytecode2llvm.lo \
- libclamavcxx_la-ClamBCRTChecks.lo
+ libclamavcxx_la-ClamBCRTChecks.lo libclamavcxx_la-detect.lo
libclamavcxx_la_OBJECTS = $(am_libclamavcxx_la_OBJECTS)
AM_V_lt = $(am__v_lt_$(V))
am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
@@ -981,7 +981,8 @@ libclamavcxx_la_CXXFLAGS = $(LLVM_CXXFLAGS)
libclamavcxx_la_SOURCES = bytecode2llvm.cpp\
ClamBCRTChecks.cpp\
ClamBCModule.h\
- ClamBCDiagnostics.h
+ ClamBCDiagnostics.h\
+ detect.cpp
LLVM_CXXFLAGS = -Woverloaded-virtual -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings
unittest_CXXFLAGS = @NO_VARIADIC_MACROS@ @NO_MISSING_FIELD_INITIALIZERS@
@@ -2085,6 +2086,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/count-count.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamavcxx_la-ClamBCRTChecks.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamavcxx_la-bytecode2llvm.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libclamavcxx_la-detect.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgoogletest_la-TestMain.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgoogletest_la-gtest-death-test.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/libgoogletest_la-gtest-filepath.Plo at am__quote@
@@ -2502,6 +2504,14 @@ libclamavcxx_la-ClamBCRTChecks.lo: ClamBCRTChecks.cpp
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -c -o libclamavcxx_la-ClamBCRTChecks.lo `test -f 'ClamBCRTChecks.cpp' || echo '$(srcdir)/'`ClamBCRTChecks.cpp
+libclamavcxx_la-detect.lo: detect.cpp
+ at am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -MT libclamavcxx_la-detect.lo -MD -MP -MF $(DEPDIR)/libclamavcxx_la-detect.Tpo -c -o libclamavcxx_la-detect.lo `test -f 'detect.cpp' || echo '$(srcdir)/'`detect.cpp
+ at am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamavcxx_la-detect.Tpo $(DEPDIR)/libclamavcxx_la-detect.Plo
+ at am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='detect.cpp' object='libclamavcxx_la-detect.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -c -o libclamavcxx_la-detect.lo `test -f 'detect.cpp' || echo '$(srcdir)/'`detect.cpp
+
libgoogletest_la-gtest-death-test.lo: llvm/utils/unittest/googletest/gtest-death-test.cc
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgoogletest_la_CPPFLAGS) $(CPPFLAGS) $(libgoogletest_la_CXXFLAGS) $(CXXFLAGS) -MT libgoogletest_la-gtest-death-test.lo -MD -MP -MF $(DEPDIR)/libgoogletest_la-gtest-death-test.Tpo -c -o libgoogletest_la-gtest-death-test.lo `test -f 'llvm/utils/unittest/googletest/gtest-death-test.cc' || echo '$(srcdir)/'`llvm/utils/unittest/googletest/gtest-death-test.cc
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgoogletest_la-gtest-death-test.Tpo $(DEPDIR)/libgoogletest_la-gtest-death-test.Plo
diff --git a/libclamav/c++/TODO.CLAMAV b/libclamav/c++/TODO.CLAMAV
new file mode 100644
index 0000000..dc02bc5
--- /dev/null
+++ b/libclamav/c++/TODO.CLAMAV
@@ -0,0 +1,15 @@
+Convert to clamav's build system -> impl. cross-compilation support (tblgen)
+
+Right now static linking of libclamav doesn't work with llvm parts for a number
+of reasons:
+1. llvm is not built with libtool, and it builds .a files (or .so files)
+2. if I link with .a files, that works for a .so (LLVM's .a files are PIC), but
+ the created libclamav.a will miss the .a files, so I'd need to install the llvm
+ .a files together with clamav's
+3. libtool solves this by putting individual .o files into the target libtool .a
+archive, but since I link against non-libtool archives it doesn't know how to do
+that
+4. if I link against a .so then obviously it is not static linking
+
+If llvm would be converted to clamav's buildsystem then static linking of
+libclamav would work.
diff --git a/libclamav/c++/bytecode2llvm.cpp b/libclamav/c++/bytecode2llvm.cpp
index 22b5413..0fbbc24 100644
--- a/libclamav/c++/bytecode2llvm.cpp
+++ b/libclamav/c++/bytecode2llvm.cpp
@@ -1800,7 +1800,7 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
for (unsigned i=0;i<bcs->count;i++) {
const struct cli_bc *bc = &bcs->all_bcs[i];
- if (bc->state == bc_skip)
+ if (bc->state == bc_skip || bc->state == bc_interp)
continue;
LLVMCodegen Codegen(bc, M, &CF, bcs->engine->compiledFunctions, EE,
OurFPM, apiFuncs, apiMap);
@@ -1821,7 +1821,7 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
}
delete [] apiFuncs;
}
- return -1;
+ return CL_SUCCESS;
} catch (std::bad_alloc &badalloc) {
errs() << MODULE << badalloc.what() << "\n";
return CL_EMEM;
@@ -1872,63 +1872,6 @@ int bytecode_init(void)
int cli_bytecode_init_jit(struct cli_all_bc *bcs, unsigned dconfmask)
{
LLVMApiScopedLock scopedLock;
- bcs->engine = NULL;
- Triple triple(sys::getHostTriple());
- if (cli_debug_flag)
- errs() << "host triple is: " << sys::getHostTriple() << "\n";
- enum Triple::ArchType arch = triple.getArch();
- switch (arch) {
- case Triple::arm:
- if (!(dconfmask & BYTECODE_JIT_ARM)) {
- if (cli_debug_flag)
- errs() << "host triple is: " << sys::getHostTriple() << "\n";
- return 0;
- }
- break;
- case Triple::ppc:
- case Triple::ppc64:
- if (!(dconfmask & BYTECODE_JIT_PPC)) {
- if (cli_debug_flag)
- errs() << "JIT disabled for ppc\n";
- return 0;
- }
- break;
- case Triple::x86:
- case Triple::x86_64:
- if (!(dconfmask & BYTECODE_JIT_X86)) {
- if (cli_debug_flag)
- errs() << "JIT disabled for x86\n";
- return 0;
- }
- break;
- default:
- errs() << "Not supported architecture for " << triple.str() << "\n";
- return CL_EBYTECODE;
- }
-
- std::string cpu = sys::getHostCPUName();
- if (cli_debug_flag)
- errs() << "host cpu is: " << cpu << "\n";
- if (!cpu.compare("i386") ||
- !cpu.compare("i486")) {
- bcs->engine = 0;
- DEBUG(errs() << "i[34]86 detected, falling back to interpreter (JIT needs pentium or better\n");
- /* i386 and i486 has to fallback to interpreter */
- return 0;
- }
- std::string ErrMsg;
- sys::MemoryBlock B = sys::Memory::AllocateRWX(4096, NULL, &ErrMsg);
- if (B.base() == 0) {
- errs() << MODULE << ErrMsg << "\n";
-#ifdef __linux__
- errs() << MODULE << "SELinux is preventing 'execmem' access. Run 'setsebool -P clamd_use_jit on' to allow access\n";
-#endif
- errs() << MODULE << "falling back to interpreter mode\n";
- return 0;
- } else {
- sys::Memory::ReleaseRWX(B);
- }
-
bcs->engine = new(std::nothrow) cli_bcengine;
if (!bcs->engine)
return CL_EMEM;
@@ -1937,7 +1880,7 @@ int cli_bytecode_init_jit(struct cli_all_bc *bcs, unsigned dconfmask)
return 0;
}
-int cli_bytecode_done_jit(struct cli_all_bc *bcs)
+int cli_bytecode_done_jit(struct cli_all_bc *bcs, int partial)
{
LLVMApiScopedLock scopedLock;
if (bcs->engine) {
@@ -1945,10 +1888,14 @@ int cli_bytecode_done_jit(struct cli_all_bc *bcs)
if (bcs->engine->Listener)
bcs->engine->EE->UnregisterJITEventListener(bcs->engine->Listener);
delete bcs->engine->EE;
+ bcs->engine->EE = 0;
}
delete bcs->engine->Listener;
- delete bcs->engine;
- bcs->engine = 0;
+ bcs->engine->Listener = 0;
+ if (!partial) {
+ delete bcs->engine;
+ bcs->engine = 0;
+ }
}
return 0;
}
diff --git a/libclamav/c++/configure b/libclamav/c++/configure
index c953b8e..dc60c55 100755
--- a/libclamav/c++/configure
+++ b/libclamav/c++/configure
@@ -14504,7 +14504,7 @@ else
enable_optimized=default
fi
- if test "x$enable_optimized" == "xno"; then
+ if test "x$enable_optimized" = "xno"; then
DEBUG_BUILD_TRUE=
DEBUG_BUILD_FALSE='#'
else
diff --git a/libclamav/c++/configure.ac b/libclamav/c++/configure.ac
index f58a967..b557e2f 100644
--- a/libclamav/c++/configure.ac
+++ b/libclamav/c++/configure.ac
@@ -54,7 +54,7 @@ AC_ARG_ENABLE([llvm],AC_HELP_STRING([-enable-llvm],
AC_ARG_ENABLE(optimized, AC_HELP_STRING([-enable-optimized],
[Compile with optimizations enabled (default is YES)]),
enable_optimized=$enableval, enable_optimized=default)
-AM_CONDITIONAL(DEBUG_BUILD,[test "x$enable_optimized" == "xno"])
+AM_CONDITIONAL(DEBUG_BUILD,[test "x$enable_optimized" = "xno"])
dnl Set configure args for subdir
if test "$enable_optimized" = "default"; then
diff --git a/libclamav/c++/detect.cpp b/libclamav/c++/detect.cpp
new file mode 100644
index 0000000..92a6fd6
--- /dev/null
+++ b/libclamav/c++/detect.cpp
@@ -0,0 +1,151 @@
+/*
+ * JIT detection for ClamAV bytecode.
+ *
+ * Copyright (C) 2010 Sourcefire, Inc.
+ *
+ * Authors: Török Edvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/DataTypes.h"
+#include "llvm/System/Memory.h"
+#include "llvm/Config/config.h"
+
+extern "C" {
+#include "bytecode_detect.h"
+}
+
+using namespace llvm;
+
+static void warn_assumptions(const char *msg, int a, int b)
+{
+ errs() << "LibClamAV Warning: libclamav and llvm make inconsistent "
+ << "assumptions about " << msg << ": " <<
+ a << " and " << b << "."
+ << "Please report to http://bugs.clamav.net\n";
+}
+
+#define CASE_OS(theos, compat) case Triple::theos:\
+ env->os = llvm_os_##theos;\
+ if (env->os_category != compat)\
+ warn_assumptions("Operating System", env->os_category, Triple::theos);\
+ break
+
+void cli_detect_env_jit(struct cli_environment *env)
+{
+ std::string host_triple = sys::getHostTriple();
+ INIT_STRFIELD(env->triple, host_triple.c_str());
+
+ std::string cpu = sys::getHostCPUName();
+ INIT_STRFIELD(env->cpu, cpu.c_str());
+
+ if (env->big_endian != (int)sys::isBigEndianHost()) {
+ warn_assumptions("host endianness", env->big_endian, sys::isBigEndianHost());
+ env->big_endian = sys::isBigEndianHost();
+ }
+
+#ifdef __GNUC__
+ env->cpp_version = MAKE_VERSION(0, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
+#elif defined (__INTEL_COMPILER)
+ env->cpp_version = __INTEL_COMPILER;
+#elif defined (_MSC_VER)
+ env->cpp_version = _MSC_VER;
+#endif
+
+ Triple triple(host_triple);
+
+ // CPU architecture
+ enum Triple::ArchType arch = triple.getArch();
+ enum arch_list earch;
+ bool conflicts = false;
+ switch (arch) {
+ case Triple::arm:
+ earch = arch_arm;
+ if (env->arch != earch) conflicts = true;
+ break;
+ case Triple::ppc:
+ earch = arch_ppc32;
+ if (env->arch != earch &&
+ env->arch != arch_ppc64) conflicts = true;
+ break;
+ case Triple::ppc64:
+ earch = arch_ppc64;
+ // ppc64 is fixed up by llvm
+ if (env->arch != arch_ppc32 &&
+ env->arch != arch_ppc64) conflicts = true;
+ break;
+ case Triple::x86:
+ earch = arch_i386;
+ if (env->arch != earch) {
+ /* bb #2153 */
+ if (env->os_category != os_darwin || env->arch != arch_x86_64)
+ conflicts = true;
+ }
+ break;
+ case Triple::x86_64:
+ earch = arch_x86_64;
+ if (env->arch != earch) {
+ /* bb #2153 */
+ if (env->os_category != os_darwin || env->arch != arch_i386)
+ conflicts = true;
+ }
+ break;
+ default:
+ earch = arch_unknown;
+ break;
+ }
+ if (conflicts)
+ warn_assumptions("CPU architecture", env->arch, earch);
+ if (earch != arch_unknown)
+ env->arch = earch;
+
+ // OS
+ Triple::OSType os = triple.getOS();
+ switch (os) {
+ case Triple::UnknownOS:
+ env->os = llvm_os_UnknownOS;
+ break;
+ CASE_OS(AuroraUX, os_solaris);
+ CASE_OS(Cygwin, os_win32);
+ CASE_OS(Darwin, os_darwin);
+ CASE_OS(DragonFly, os_bsd);
+ CASE_OS(FreeBSD, os_bsd);
+ CASE_OS(Linux, os_linux);
+ CASE_OS(Lv2, os_unknown);
+ CASE_OS(MinGW32, os_win32);
+ CASE_OS(MinGW64, os_win64);
+ CASE_OS(NetBSD, os_bsd);
+ CASE_OS(OpenBSD, os_bsd);
+ CASE_OS(Psp, os_unknown);
+ CASE_OS(Solaris, os_solaris);
+ CASE_OS(Win32, os_win32);
+ CASE_OS(Haiku, os_unknown);
+ }
+
+ // mmap RWX
+ std::string ErrMsg;
+ sys::MemoryBlock B = sys::Memory::AllocateRWX(4096, NULL, &ErrMsg);
+ if (B.base() == 0) {
+ errs() << "LibClamAV Warning: RWX mapping denied: " << ErrMsg << "\n";
+ } else {
+ env->os_features |= 1 << feature_map_rwx;
+ sys::Memory::ReleaseRWX(B);
+ }
+}
+
diff --git a/libclamav/c++/llvm/include/llvm/ADT/EquivalenceClasses.h b/libclamav/c++/llvm/include/llvm/ADT/EquivalenceClasses.h
index f5f3d49..fa4af67 100644
--- a/libclamav/c++/llvm/include/llvm/ADT/EquivalenceClasses.h
+++ b/libclamav/c++/llvm/include/llvm/ADT/EquivalenceClasses.h
@@ -190,7 +190,7 @@ public:
/// insert - Insert a new value into the union/find set, ignoring the request
/// if the value already exists.
iterator insert(const ElemTy &Data) {
- return TheMapping.insert(Data).first;
+ return TheMapping.insert(ECValue(Data)).first;
}
/// findLeader - Given a value in the set, return a member iterator for the
diff --git a/libclamav/c++/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/libclamav/c++/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 0e54ca4..48d2a1c 100644
--- a/libclamav/c++/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/libclamav/c++/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -2399,7 +2399,7 @@ std::pair<unsigned, const TargetRegisterClass*> TargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint,
EVT VT) const {
if (Constraint[0] != '{')
- return std::pair<unsigned, const TargetRegisterClass*>(0, 0);
+ return std::make_pair(0, static_cast<TargetRegisterClass*>(0));
assert(*(Constraint.end()-1) == '}' && "Not a brace enclosed constraint?");
// Remove the braces from around the name.
@@ -2431,7 +2431,7 @@ getRegForInlineAsmConstraint(const std::string &Constraint,
}
}
- return std::pair<unsigned, const TargetRegisterClass*>(0, 0);
+ return std::make_pair(0, static_cast<TargetRegisterClass*>(0));
}
//===----------------------------------------------------------------------===//
diff --git a/libclamav/c++/llvm/lib/CodeGen/Spiller.cpp b/libclamav/c++/llvm/lib/CodeGen/Spiller.cpp
index 7ba4403..c06279d 100644
--- a/libclamav/c++/llvm/lib/CodeGen/Spiller.cpp
+++ b/libclamav/c++/llvm/lib/CodeGen/Spiller.cpp
@@ -439,8 +439,8 @@ private:
// reg.
MachineBasicBlock *useMBB = useInst->getParent();
MachineBasicBlock::iterator useItr(useInst);
- tii->copyRegToReg(*useMBB, next(useItr), li->reg, newVReg, trc, trc);
- MachineInstr *copyMI = next(useItr);
+ tii->copyRegToReg(*useMBB, llvm::next(useItr), li->reg, newVReg, trc, trc);
+ MachineInstr *copyMI = llvm::next(useItr);
copyMI->addRegisterKilled(newVReg, tri);
SlotIndex copyIdx = lis->InsertMachineInstrInMaps(copyMI);
diff --git a/libclamav/c++/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/libclamav/c++/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
index f920dca..d226f06 100644
--- a/libclamav/c++/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
+++ b/libclamav/c++/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
@@ -2817,7 +2817,7 @@ Value *LSRInstance::Expand(const LSRFixup &LF,
}
if (IDom == Inst->getParent() &&
(!BetterPos || DT.dominates(BetterPos, Inst)))
- BetterPos = next(BasicBlock::iterator(Inst));
+ BetterPos = llvm::next(BasicBlock::iterator(Inst));
}
if (!AllDominate)
break;
diff --git a/libclamav/c++/llvm/lib/Transforms/Utils/LowerInvoke.cpp b/libclamav/c++/llvm/lib/Transforms/Utils/LowerInvoke.cpp
index 766c4d9..ebed676 100644
--- a/libclamav/c++/llvm/lib/Transforms/Utils/LowerInvoke.cpp
+++ b/libclamav/c++/llvm/lib/Transforms/Utils/LowerInvoke.cpp
@@ -146,14 +146,14 @@ bool LowerInvoke::doInitialization(Module &M) {
// VisualStudio defines setjmp as _setjmp via #include <csetjmp> / <setjmp.h>,
// so it looks like Intrinsic::_setjmp
-#if defined(_MSC_VER) && defined(setjmp)
+#if defined(_MSC_VER) && _MSC_VER < 1600 && defined(setjmp)
#define setjmp_undefined_for_visual_studio
#undef setjmp
#endif
SetJmpFn = Intrinsic::getDeclaration(&M, Intrinsic::setjmp);
-#if defined(_MSC_VER) && defined(setjmp_undefined_for_visual_studio)
+#if defined(_MSC_VER) && _MSC_VER < 1600 && defined(setjmp_undefined_for_visual_studio)
// let's return it to _setjmp state in case anyone ever needs it after this
// point under VisualStudio
#define setjmp _setjmp
diff --git a/libclamav/c++/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/libclamav/c++/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
index 4f5a70b..d62b160 100644
--- a/libclamav/c++/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
+++ b/libclamav/c++/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp
@@ -861,7 +861,7 @@ void PromoteMem2Reg::PromoteSingleBlockAlloca(AllocaInst *AI, AllocaInfo &Info,
// Find the nearest store that has a lower than this load.
StoresByIndexTy::iterator I =
std::lower_bound(StoresByIndex.begin(), StoresByIndex.end(),
- std::pair<unsigned, StoreInst*>(LoadIdx, 0),
+ std::pair<unsigned, StoreInst*>(LoadIdx, static_cast<StoreInst*>(0)),
StoreIndexSearchPredicate());
// If there is no store before this load, then we can't promote this load.
diff --git a/libclamav/c++/merge.sh b/libclamav/c++/merge.sh
new file mode 100755
index 0000000..475a94c
--- /dev/null
+++ b/libclamav/c++/merge.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Merge upstream LLVM from git-svn mirror
+set -e
+rm -f .git/info/grafts
+touch .git/info/grafts
+echo "Creating grafts for llvm-upstream"
+
+REPONAME=llvm
+REFPFX=refs/tags/merge-$REPONAME-
+UPSTREAM=$REPONAME-upstream/release
+git for-each-ref $REFPFX* --format='%(refname)' | while read tag_ref
+do
+ tag_svn_ref=`echo $tag_ref|sed -e s\|$REFPFX\|\|`
+ upstream_ref=`git log $UPSTREAM -1 --grep=trunk@$tag_svn_ref --format=format:%H`
+ local_ref=`git rev-parse $tag_ref`
+ local_parent_ref=`git rev-parse $tag_ref^`
+ git branch --contains $local_ref | grep '*' >/dev/null ||
+ { echo "branch has been rebased, tag is on branch: `git branch --contains $local_ref`"; exit 1;}
+ echo "$local_ref $local_parent_ref $upstream_ref" >>.git/info/grafts
+done
+echo "Merging llvm-upstream"
+MERGEREV=`git log $UPSTREAM -1 |grep /release_27@|sed -s 's/.*@\([0-9]*\).*/\1/'`
+echo "$MERGEREV"
+git merge -s subtree --squash llvm-upstream/release
+
+echo "Run strip-llvm.sh from libclamav/c++"
+echo "Then fix conflicts if needed: git mergetool"
+echo "Then commit the result and tag it: git commit && git tag merge-llvm-$MERGEREV"
+echo "Then remove the grafts: rm .git/info/grafts"
+# && git commit || {
+# echo "Merge failed: resolve conflicts and run: git tag merge-llvm-$MERGEREV && rm .git/info/grafts"; exit 1;}
+# git tag merge-llvm-$MERGEREV
+# rm .git/info/grafts
diff --git a/libclamav/c++/strip-llvm.sh b/libclamav/c++/strip-llvm.sh
new file mode 100755
index 0000000..44bb1fe
--- /dev/null
+++ b/libclamav/c++/strip-llvm.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Remove directories we don't use
+
+for i in llvm/bindings/ llvm/examples/ llvm/projects/ llvm/runtime/\
+ llvm/website llvm/win32 llvm/Xcode llvm/lib/Archive\
+ llvm/lib/CompilerDriver/ llvm/lib/Debugger/ llvm/lib/Linker/\
+ llvm/lib/Target/Alpha/ llvm/lib/Target/Blackfin/ llvm/lib/Target/CBackend/\
+ llvm/lib/Target/CellSPU/ llvm/lib/Target/CppBackend/ llvm/lib/Target/Mips\
+ llvm/lib/Target/MSIL llvm/lib/Target/MSP430/ llvm/lib/Target/PIC16\
+ llvm/lib/Target/Sparc/ llvm/lib/Target/SystemZ llvm/lib/Target/XCore\
+ llvm/lib/Target/MBlaze/ llvm/lib/Target/PIC16/ llvm/lib/Target/MSP430\
+ llvm/test/Archive/ llvm/test/Bindings/ llvm/test/Bitcode/ llvm/test/DebugInfo/\
+ llvm/test/FrontendAda/ llvm/test/FrontendC llvm/test/FrontendC++/\
+ llvm/test/FrontendFortran/ llvm/test/FrontendObjC\
+ llvm/test/FrontendObjC++ llvm/test/Linker/ llvm/test/LLVMC\
+ llvm/test/MC llvm/test/Transforms llvm/test/Transforms/InstCombine\
+ llvm/test/BugPoint llvm/test/CodeGen/CPP llvm/test/CodeGen/Mips\
+ llvm/test/CodeGen/Alpha llvm/test/CodeGen/PIC16 llvm/test/CodeGen/SPARC\
+ llvm/test/CodeGen/XCore llvm/test/CodeGen/MSP430 llvm/test/CodeGen/MBlaze\
+ llvm/test/CodeGen/CellSPU llvm/test/CodeGen/CBackend\
+ llvm/test/CodeGen/SystemZ llvm/test/CodeGen/Blackfin llvm/test/TableGen\
+ llvm/test/Analysis llvm/test/Assembler llvm/test/Other\
+ llvm/tools/bugpoint llvm/tools/gold llvm/tools/llvm-ar\
+ llvm/tools/llvm-bcanalyzer llvm/tools/llvm-db\
+ llvm/tools/llvm-extract llvm/tools/llvm-ld llvm/tools/llvm-link llvm/tools/llvm-mc\
+ llvm/tools/llvm-nm llvm/tools/llvm-prof llvm/tools/llvm-ranlib\
+ llvm/tools/llvm-stub llvm/tools/lto llvm/tools/opt llvm/lib/MC/MCParser\
+ llvm/tools/llvm-dis/Makefile llvm/tools/edis/ llvm/tools/llvm-shlib\
+ llvm/docs
+ do
+ git rm -rf $i; git rm -f $i;
+done
+# config.status needs these
+mkdir -p llvm/docs/doxygen
+touch llvm/docs/doxygen.cfg.in
+git add llvm/docs/doxygen.cfg.in
diff --git a/libclamav/clamav.h b/libclamav/clamav.h
index e083e4b..6890c76 100644
--- a/libclamav/clamav.h
+++ b/libclamav/clamav.h
@@ -66,7 +66,11 @@ typedef enum {
CL_EMAXSIZE,
CL_EMAXFILES,
CL_EFORMAT,
- CL_EBYTECODE
+ CL_EBYTECODE,/* may be reported in testmode */
+ CL_EBYTECODE_TESTFAIL, /* may be reported in testmode */
+
+ /* no error codes below this line please */
+ CL_ELAST_ERROR
} cl_error_t;
/* db options */
@@ -143,8 +147,9 @@ enum cl_engine_field {
CL_ENGINE_AC_MAXDEPTH, /* uint32_t */
CL_ENGINE_TMPDIR, /* (char *) */
CL_ENGINE_KEEPTMP, /* uint32_t */
- CL_ENGINE_BYTECODE_SECURITY, /* uint32_t */
- CL_ENGINE_BYTECODE_TIMEOUT /* uint32_t */
+ CL_ENGINE_BYTECODE_SECURITY, /* uint32_t */
+ CL_ENGINE_BYTECODE_TIMEOUT, /* uint32_t */
+ CL_ENGINE_BYTECODE_MODE /* uint32_t */
};
enum bytecode_security {
@@ -153,6 +158,15 @@ enum bytecode_security {
CL_BYTECODE_TRUST_NOTHING /* paranoid setting */
};
+enum bytecode_mode {
+ CL_BYTECODE_MODE_AUTO=0, /* JIT if possible, fallback to interpreter */
+ CL_BYTECODE_MODE_JIT, /* force JIT */
+ CL_BYTECODE_MODE_INTERPRETER, /* force interpreter */
+ CL_BYTECODE_MODE_TEST, /* both JIT and interpreter, compare results,
+ all failures are fatal */
+ CL_BYTECODE_MODE_OFF /* for query only, not settable */
+};
+
extern int cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field field, long long num);
extern long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field field, int *err);
@@ -174,6 +188,53 @@ extern int cl_engine_addref(struct cl_engine *engine);
extern int cl_engine_free(struct cl_engine *engine);
+/* CALLBACKS - WARNING: unstable API - WIP */
+
+
+typedef cl_error_t (*clcb_pre_scan)(int fd, void *context);
+/* PRE-SCAN
+Input:
+fd = File descriptor which is about to be scanned
+context = Opaque application provided data
+
+Output:
+CL_CLEAN = File is scanned
+CL_BREAK = Whitelisted by callback - file is skipped and marked as clean
+CL_VIRUS = Blacklisted by callback - file is skipped and marked as infected
+*/
+extern void cl_engine_set_clcb_pre_scan(struct cl_engine *engine, clcb_pre_scan callback);
+
+
+typedef cl_error_t (*clcb_post_scan)(int fd, int result, const char *virname, void *context);
+/* POST-SCAN
+Input:
+fd = File descriptor which is was scanned
+result = The scan result for the file
+virname = Virus name if infected
+context = Opaque application provided data
+
+Output:
+CL_CLEAN = Scan result is not overridden
+CL_BREAK = Whitelisted by callback - scan result is set to CL_CLEAN
+CL_VIRUS = Blacklisted by callback - scan result is set to CL_VIRUS
+*/
+extern void cl_engine_set_clcb_post_scan(struct cl_engine *engine, clcb_post_scan callback);
+
+
+typedef int (*clcb_sigload)(const char *type, const char *name, void *context);
+/* SIGNATURE LOAD
+Input:
+type = The signature type (e.g. "db", "ndb", "mdb", etc.)
+name = The virus name
+context = Opaque application provided data
+
+Output:
+0 = Load the current signature
+Non 0 = Skip the current signature
+*/
+extern void cl_engine_set_clcb_sigload(struct cl_engine *engine, clcb_sigload callback, void *context);
+
+
struct cl_stat {
char *dir;
struct stat *stattab;
@@ -195,6 +256,7 @@ struct cl_cvd { /* field no. */
/* file scanning */
extern int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
+extern int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context);
extern int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
diff --git a/libclamav/cvd.c b/libclamav/cvd.c
index 42ab23b..30dac75 100644
--- a/libclamav/cvd.c
+++ b/libclamav/cvd.c
@@ -307,7 +307,7 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
else
off = ftell(dbio->fs);
- if((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && CLI_DBEXT(name))) {
+ if((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && (CLI_DBEXT(name) || cli_strbcasestr(name, ".ign") || cli_strbcasestr(name, ".ign2")))) {
ret = cli_load(name, engine, signo, options, dbio);
if(ret) {
cli_errmsg("cli_tgzload: Can't load %s\n", name);
diff --git a/libclamav/elf.c b/libclamav/elf.c
index e54ac4f..92e9bdd 100644
--- a/libclamav/elf.c
+++ b/libclamav/elf.c
@@ -66,8 +66,8 @@ static uint32_t cli_rawaddr(uint32_t vaddr, struct elf_program_hdr32 *ph, uint16
int cli_scanelf(cli_ctx *ctx)
{
struct elf_file_hdr32 file_hdr;
- struct elf_section_hdr32 *section_hdr;
- struct elf_program_hdr32 *program_hdr;
+ struct elf_section_hdr32 *section_hdr = NULL;
+ struct elf_program_hdr32 *program_hdr = NULL;
uint16_t shnum, phnum, shentsize, phentsize;
uint32_t entry, fentry, shoff, phoff, i;
uint8_t conv = 0, err;
@@ -237,14 +237,15 @@ int cli_scanelf(cli_ctx *ctx)
phoff = EC32(file_hdr.e_phoff, conv);
cli_dbgmsg("ELF: Program header table offset: %d\n", phoff);
- program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize);
- if(!program_hdr) {
- cli_errmsg("ELF: Can't allocate memory for program headers\n");
- return CL_EMEM;
+ if(phnum) {
+ program_hdr = (struct elf_program_hdr32 *) cli_calloc(phnum, phentsize);
+ if(!program_hdr) {
+ cli_errmsg("ELF: Can't allocate memory for program headers\n");
+ return CL_EMEM;
+ }
+ cli_dbgmsg("------------------------------------\n");
}
- cli_dbgmsg("------------------------------------\n");
-
for(i = 0; i < phnum; i++) {
err = 0;
if(format == 1) {
@@ -333,14 +334,15 @@ int cli_scanelf(cli_ctx *ctx)
shoff = EC32(file_hdr.e_shoff, conv);
cli_dbgmsg("ELF: Section header table offset: %d\n", shoff);
- section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
- if(!section_hdr) {
- cli_errmsg("ELF: Can't allocate memory for section headers\n");
- return CL_EMEM;
+ if(shnum) {
+ section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
+ if(!section_hdr) {
+ cli_errmsg("ELF: Can't allocate memory for section headers\n");
+ return CL_EMEM;
+ }
+ cli_dbgmsg("------------------------------------\n");
}
- cli_dbgmsg("------------------------------------\n");
-
for(i = 0; i < shnum; i++) {
err = 0;
if(format == 1) {
@@ -458,8 +460,8 @@ int cli_scanelf(cli_ctx *ctx)
int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
{
struct elf_file_hdr32 file_hdr;
- struct elf_section_hdr32 *section_hdr;
- struct elf_program_hdr32 *program_hdr;
+ struct elf_section_hdr32 *section_hdr = NULL;
+ struct elf_program_hdr32 *program_hdr = NULL;
uint16_t shnum, phnum, shentsize, phentsize, i;
uint32_t entry, fentry = 0, shoff, phoff;
uint8_t conv = 0, err;
@@ -602,12 +604,14 @@ int cli_elfheader(fmap_t *map, struct cli_exe_info *elfinfo)
return -1;
}
- section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
- if(!section_hdr) {
- cli_errmsg("ELF: Can't allocate memory for section headers\n");
- free(elfinfo->section);
- elfinfo->section = NULL;
- return -1;
+ if(shnum) {
+ section_hdr = (struct elf_section_hdr32 *) cli_calloc(shnum, shentsize);
+ if(!section_hdr) {
+ cli_errmsg("ELF: Can't allocate memory for section headers\n");
+ free(elfinfo->section);
+ elfinfo->section = NULL;
+ return -1;
+ }
}
for(i = 0; i < shnum; i++) {
diff --git a/libclamav/execs.h b/libclamav/execs.h
index e73791f..34a1f0c 100644
--- a/libclamav/execs.h
+++ b/libclamav/execs.h
@@ -52,6 +52,10 @@ struct cli_exe_info {
uint16_t nsections;
/** Hashset for versioninfo matching */
struct cli_hashset *vinfo;
+ /** Resrources RVA - PE ONLY */
+ uint32_t res_addr;
+ /** Address size - PE ONLY */
+ uint32_t hdr_size;
};
#endif
diff --git a/libclamav/filetypes_int.h b/libclamav/filetypes_int.h
index d8c2cf2..55b4391 100644
--- a/libclamav/filetypes_int.h
+++ b/libclamav/filetypes_int.h
@@ -130,8 +130,8 @@ static const char *ftypes_int[] = {
"0:0:5349502d48495420285349502f48:SIP log:CL_TYPE_ANY:CL_TYPE_IGNORED",
"1:0:3c2540204c414e4755414745203d:HTML data:CL_TYPE_ANY:CL_TYPE_HTML",
"0:0:7b5c727466:RTF:CL_TYPE_ANY:CL_TYPE_RTF:30",
- "1:*:255044462d??2e:PDF:CL_TYPE_ANY:CL_TYPE_PDF:30",
- "1:*:257064662d??2e:PDF:CL_TYPE_ANY:CL_TYPE_PDF:30",
+ "1:0,1024:255044462d??2e:PDF:CL_TYPE_ANY:CL_TYPE_PDF:30",
+ "1:0,1024:257064662d??2e:PDF:CL_TYPE_ANY:CL_TYPE_PDF:30",
"0:257:7573746172:TAR-POSIX:CL_TYPE_ANY:CL_TYPE_POSIX_TAR",
"0:0:5b616c69617365735d:mirc ini:CL_TYPE_ANY:CL_TYPE_SCRIPT",
"1:0,1024:0a(46|66)726f6d3a20{-1024}0a(4d|6d)(49|69)(4d|6d)(45|65)2d(56|76)657273696f6e3a20:Mail file:CL_TYPE_ANY:CL_TYPE_MAIL",
diff --git a/libclamav/fmap.c b/libclamav/fmap.c
index 19437eb..61aeb6e 100644
--- a/libclamav/fmap.c
+++ b/libclamav/fmap.c
@@ -30,7 +30,7 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#if HAVE_MMAP
+#ifdef ANONYMOUS_MAP
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
@@ -67,7 +67,7 @@ static inline unsigned int fmap_which_page(fmap_t *m, size_t at);
#define UNPAGE_THRSHLD_HI 8*1024*1024
#define READAHEAD_PAGES 8
-#if defined(HAVE_MMAP) && defined(C_LINUX) && defined(CL_THREAD_SAFE)
+#if defined(ANONYMOUS_MAP) && defined(C_LINUX) && defined(CL_THREAD_SAFE)
/*
WORKAROUND
Relieve some stress on mmap_sem.
@@ -124,7 +124,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
hdrsz = fmap_align_to(sizeof(fmap_t) + (pages-1) * sizeof(uint32_t), pgsz); /* fmap_t includes 1 bitmap slot, hence (pages-1) */
mapsz = pages * pgsz + hdrsz;
fmap_lock;
-#if HAVE_MMAP
+#ifdef ANONYMOUS_MAP
if ((m = (fmap_t *)mmap(NULL, mapsz, PROT_READ | PROT_WRITE, MAP_PRIVATE|/*FIXME: MAP_POPULATE is ~8% faster but more memory intensive */ANONYMOUS_MAP, -1, 0)) == MAP_FAILED) {
m = NULL;
} else {
@@ -133,9 +133,9 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
madvise((void *)m, mapsz, MADV_RANDOM|MADV_DONTFORK);
#endif /* madvise */
}
-#else /* ! HAVE_MMAP */
+#else /* ! ANONYMOUS_MAP */
m = (fmap_t *)cli_malloc(mapsz);
-#endif /* HAVE_MMAP */
+#endif /* ANONYMOUS_MAP */
if(!m) {
cli_warnmsg("fmap: map allocation failed\n");
fmap_unlock;
@@ -159,7 +159,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty) {
static void fmap_aging(fmap_t *m) {
-#if HAVE_MMAP
+#ifdef ANONYMOUS_MAP
if(m->dumb) return;
if(m->paged * m->pgsz > UNPAGE_THRSHLD_HI) { /* we alloc'd too much */
unsigned int i, avail = 0, freeme[2048], maxavail = MIN(sizeof(freeme)/sizeof(*freeme), m->paged - UNPAGE_THRSHLD_LO / m->pgsz) - 1;
@@ -411,7 +411,7 @@ void fmap_unneed_ptr(fmap_t *m, void *ptr, size_t len) {
}
void funmap(fmap_t *m) {
-#if HAVE_MMAP
+#ifdef ANONYMOUS_MAP
if(!m->dumb) {
size_t len = m->pages * m->pgsz + m->hdrsz;
fmap_lock;
diff --git a/libclamav/hashtab.c b/libclamav/hashtab.c
index bb01f50..8ecaee5 100644
--- a/libclamav/hashtab.c
+++ b/libclamav/hashtab.c
@@ -329,6 +329,7 @@ const struct cli_element* cli_hashtab_insert(struct cli_hashtable *s, const char
}
else if(element->key == DELETED_KEY) {
deleted_element = element;
+ element->key = NULL;
}
else if(len == element->len && strncmp(key, element->key, len)==0) {
PROFILE_DATA_UPDATE(s, tries);
diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map
index e0cbc3c..e0e470b 100644
--- a/libclamav/libclamav.map
+++ b/libclamav/libclamav.map
@@ -11,6 +11,9 @@ CLAMAV_PUBLIC {
cl_engine_get_num;
cl_engine_set_str;
cl_engine_get_str;
+ cl_engine_set_clcb_pre_scan;
+ cl_engine_set_clcb_post_scan;
+ cl_engine_set_clcb_sigload;
cl_engine_settings_copy;
cl_engine_settings_apply;
cl_engine_settings_free;
@@ -94,6 +97,7 @@ CLAMAV_PRIVATE {
regex_list_add_pattern;
cli_build_regex_list;
regex_list_match;
+ cli_hashset_destroy;
phishing_init;
init_domainlist;
init_whitelist;
@@ -123,6 +127,9 @@ CLAMAV_PRIVATE {
cli_bm_free;
cli_initroots;
cli_scanbuff;
+ cli_fmap_scandesc;
+ cli_scandesc_stats;
+ cli_scanfile_stats;
html_screnc_decode;
mpool_create;
mpool_calloc;
@@ -150,7 +157,7 @@ CLAMAV_PRIVATE {
have_rar;
have_clamjit;
cli_bytecode_load;
- cli_bytecode_prepare;
+ cli_bytecode_prepare2;
cli_bytecode_run;
cli_bytecode_destroy;
cli_bytecode_context_alloc;
@@ -172,6 +179,7 @@ CLAMAV_PRIVATE {
cli_bytecode_printversion;
cli_bytecode_describe;
cli_printcxxver;
+ cli_detect_environment;
local:
*;
};
diff --git a/libclamav/matcher-ac.c b/libclamav/matcher-ac.c
index 3e69da3..b660257 100644
--- a/libclamav/matcher-ac.c
+++ b/libclamav/matcher-ac.c
@@ -974,35 +974,25 @@ int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs,
return CL_SUCCESS;
}
-int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, fmap_t *map)
+int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, const struct cli_target_info *info)
{
int ret;
unsigned int i;
struct cli_ac_patt *patt;
- struct cli_target_info info;
- if(map) {
- memset(&info, 0, sizeof(info));
- info.fsize = map->len;
- }
-
- info.exeinfo.vinfo = &data->vinfo;
+ /* info.exeinfo.vinfo = &data->vinfo; */
for(i = 0; i < root->ac_reloff_num; i++) {
patt = root->ac_reloff[i];
- if(!map) {
+ if(!info) {
data->offset[patt->offset_min] = CLI_OFF_NONE;
- } else if((ret = cli_caloff(NULL, &info, map, root->type, patt->offdata, &data->offset[patt->offset_min], &data->offset[patt->offset_max]))) {
+ } else if((ret = cli_caloff(NULL, info, root->type, patt->offdata, &data->offset[patt->offset_min], &data->offset[patt->offset_max]))) {
cli_errmsg("cli_ac_caloff: Can't calculate relative offset in signature for %s\n", patt->virname);
- if(info.exeinfo.section)
- free(info.exeinfo.section);
return ret;
- } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length > info.fsize)) {
+ } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length > info->fsize)) {
data->offset[patt->offset_min] = CLI_OFF_NONE;
}
}
- if(map && info.exeinfo.section)
- free(info.exeinfo.section);
return CL_SUCCESS;
}
@@ -1072,15 +1062,19 @@ inline static int ac_addtype(struct cli_matched_type **list, cli_file_t type, of
static inline void lsig_sub_matched(const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t lsigid1, uint32_t lsigid2, uint32_t realoff)
{
- if(realoff != CLI_OFF_NONE)
+ const struct cli_lsig_tdb *tdb = &root->ac_lsigtable[lsigid1]->tdb;
+
+ if(realoff != CLI_OFF_NONE) {
+ if(mdata->lsigsuboff[lsigid1][lsigid2] != CLI_OFF_NONE && realoff <= mdata->lsigsuboff[lsigid1][lsigid2])
+ return;
mdata->lsigcnt[lsigid1][lsigid2]++;
+ if(mdata->lsigcnt[lsigid1][lsigid2] <= 1 || !tdb->macro_ptids || !tdb->macro_ptids[lsigid2])
+ mdata->lsigsuboff[lsigid1][lsigid2] = realoff;
+ }
- if(mdata->lsigsuboff[lsigid1][lsigid2] == CLI_OFF_NONE)
- mdata->lsigsuboff[lsigid1][lsigid2] = realoff;
- else if (mdata->lsigcnt[lsigid1][lsigid2] > 1) {
+ if (mdata->lsigcnt[lsigid1][lsigid2] > 1) {
/* Check that the previous match had a macro match following it at the
* correct distance. This check is only done after the 1st match.*/
- const struct cli_lsig_tdb *tdb = &root->ac_lsigtable[lsigid1]->tdb;
const struct cli_ac_patt *macropt;
uint32_t id, last_macro_match, smin, smax, last_macroprev_match;
if (!tdb->macro_ptids)
@@ -1222,17 +1216,17 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
return CL_EMEM;
}
- mdata->offmatrix[pt->sigid - 1][0] = cli_malloc(pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t));
+ mdata->offmatrix[pt->sigid - 1][0] = cli_malloc(pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 2) * sizeof(int32_t));
if(!mdata->offmatrix[pt->sigid - 1][0]) {
cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u][0]\n", pt->sigid - 1);
free(mdata->offmatrix[pt->sigid - 1]);
mdata->offmatrix[pt->sigid - 1] = NULL;
return CL_EMEM;
}
- memset(mdata->offmatrix[pt->sigid - 1][0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t));
+ memset(mdata->offmatrix[pt->sigid - 1][0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 2) * sizeof(int32_t));
mdata->offmatrix[pt->sigid - 1][0][0] = 0;
for(j = 1; j < pt->parts; j++) {
- mdata->offmatrix[pt->sigid - 1][j] = mdata->offmatrix[pt->sigid - 1][0] + j * (CLI_DEFAULT_AC_TRACKLEN + 1);
+ mdata->offmatrix[pt->sigid - 1][j] = mdata->offmatrix[pt->sigid - 1][0] + j * (CLI_DEFAULT_AC_TRACKLEN + 2);
mdata->offmatrix[pt->sigid - 1][j][0] = 0;
}
}
@@ -1240,8 +1234,8 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(pt->partno != 1) {
found = 0;
- for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[pt->partno - 2][j] != -1; j++) {
- found = 1;
+ for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN + 1 && offmatrix[pt->partno - 2][j] != -1; j++) {
+ found = j;
if(pt->maxdist)
if(realoff - offmatrix[pt->partno - 2][j] > pt->maxdist)
found = 0;
@@ -1255,8 +1249,12 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
}
}
+ if(pt->partno == 2 && found > 1)
+ offmatrix[0][1] = offmatrix[0][found];
+
if(pt->partno == 1 || (found && (pt->partno != pt->parts))) {
- offmatrix[pt->partno - 1][0] %= CLI_DEFAULT_AC_TRACKLEN;
+ if(offmatrix[pt->partno - 1][0] == CLI_DEFAULT_AC_TRACKLEN + 1)
+ offmatrix[pt->partno - 1][0] = 1;
offmatrix[pt->partno - 1][0]++;
offmatrix[pt->partno - 1][offmatrix[pt->partno - 1][0]] = offset + matchend;
@@ -1272,20 +1270,22 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
cli_dbgmsg("Matched signature for file type %s\n", pt->virname);
type = pt->type;
if(ftoffset && (!*ftoffset || (*ftoffset)->cnt < MAX_EMBEDDED_OBJ || type == CL_TYPE_ZIPSFX) && (type >= CL_TYPE_SFX || ((ftype == CL_TYPE_MSEXE || ftype == CL_TYPE_ZIP || ftype == CL_TYPE_MSOLE2) && type == CL_TYPE_MSEXE))) {
- /* FIXME: we don't know which offset of the first part is the correct one */
- for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN && offmatrix[0][j] != -1; j++)
+ /* FIXME: the first offset in the array is most likely the correct one but
+ * it may happen it is not
+ */
+ for(j = 1; j <= CLI_DEFAULT_AC_TRACKLEN + 1 && offmatrix[0][j] != -1; j++)
if(ac_addtype(ftoffset, type, offmatrix[pt->parts - 1][j], ctx))
return CL_EMEM;
}
- memset(offmatrix[0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 1) * sizeof(int32_t));
+ memset(offmatrix[0], -1, pt->parts * (CLI_DEFAULT_AC_TRACKLEN + 2) * sizeof(int32_t));
for(j = 0; j < pt->parts; j++)
offmatrix[j][0] = 0;
}
} else { /* !pt->type */
if(pt->lsigid[0]) {
- lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], realoff);
+ lsig_sub_matched(root, mdata, pt->lsigid[1], pt->lsigid[2], offmatrix[pt->parts - 1][1]);
pt = pt->next_same;
continue;
}
@@ -1297,7 +1297,7 @@ int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
newres->virname = pt->virname;
newres->customdata = pt->customdata;
newres->next = *res;
- newres->offset = realoff;
+ newres->offset = offmatrix[pt->parts - 1][1];
*res = newres;
pt = pt->next_same;
@@ -1766,7 +1766,7 @@ int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hex
if(new->lsigid[0])
root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
- ret = cli_caloff(offset, NULL, NULL, root->type, new->offdata, &new->offset_min, &new->offset_max);
+ ret = cli_caloff(offset, NULL, root->type, new->offdata, &new->offset_min, &new->offset_max);
if(ret != CL_SUCCESS) {
mpool_free(root->mempool, new->prefix ? new->prefix : new->pattern);
mpool_ac_free_special(root->mempool, new);
diff --git a/libclamav/matcher-ac.h b/libclamav/matcher-ac.h
index 18f53ee..da2cefd 100644
--- a/libclamav/matcher-ac.h
+++ b/libclamav/matcher-ac.h
@@ -64,10 +64,10 @@ struct cli_ac_patt {
uint16_t parts, partno, special, special_pattern;
struct cli_ac_special **special_table;
struct cli_ac_patt *next, *next_same;
- uint8_t depth;
uint16_t rtype, type;
uint32_t offdata[4], offset_min, offset_max;
uint32_t boundary;
+ uint8_t depth;
};
struct cli_ac_node {
@@ -95,7 +95,7 @@ void cli_ac_freedata(struct cli_ac_data *data);
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
int cli_ac_buildtrie(struct cli_matcher *root);
int cli_ac_init(struct cli_matcher *root, uint8_t mindepth, uint8_t maxdepth, uint8_t dconf_prefiltering);
-int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, fmap_t *map);
+int cli_ac_caloff(const struct cli_matcher *root, struct cli_ac_data *data, const struct cli_target_info *info);
void cli_ac_free(struct cli_matcher *root);
int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options);
diff --git a/libclamav/matcher-bm.c b/libclamav/matcher-bm.c
index 3dd7714..696e6d0 100644
--- a/libclamav/matcher-bm.c
+++ b/libclamav/matcher-bm.c
@@ -52,7 +52,7 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const
return CL_EMALFDB;
}
- if((ret = cli_caloff(offset, NULL, NULL, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
+ if((ret = cli_caloff(offset, NULL, root->type, pattern->offdata, &pattern->offset_min, &pattern->offset_max))) {
cli_errmsg("cli_bm_addpatt: Can't calculate offset for signature %s\n", pattern->virname);
return ret;
}
@@ -63,7 +63,9 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const
root->bm_reloff_num++;
}
- if(root->filter) {
+ /* bm_offmode doesn't use the prefilter for BM signatures anyway, so
+ * don't add these to the filter. */
+ if(root->filter && !root->bm_offmode) {
/* the bm_suffix load balancing below can shorten the sig,
* we want to see the entire signature! */
if (filter_add_static(root->filter, pattern->pattern, pattern->length, pattern->virname) == -1) {
@@ -152,12 +154,11 @@ int cli_bm_init(struct cli_matcher *root)
return CL_SUCCESS;
}
-int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, fmap_t *map)
+int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, const struct cli_target_info *info)
{
int ret;
unsigned int i;
struct cli_bm_patt *patt;
- struct cli_target_info info;
if(!root->bm_patterns) {
@@ -165,8 +166,6 @@ int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, fmap
data->cnt = data->pos = 0;
return CL_SUCCESS;
}
- memset(&info, 0, sizeof(info));
- info.fsize = map->len;
data->cnt = data->pos = 0;
data->offtab = (uint32_t *) cli_malloc(root->bm_patterns * sizeof(uint32_t));
@@ -184,27 +183,23 @@ int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, fmap
patt = root->bm_pattab[i];
if(patt->offdata[0] == CLI_OFF_ABSOLUTE) {
data->offtab[data->cnt] = patt->offset_min + patt->prefix_length;
- if(data->offtab[data->cnt] >= map->len)
+ if(data->offtab[data->cnt] >= info->fsize)
continue;
data->cnt++;
- } else if((ret = cli_caloff(NULL, &info, map, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) {
+ } else if((ret = cli_caloff(NULL, info, root->type, patt->offdata, &data->offset[patt->offset_min], NULL))) {
cli_errmsg("cli_bm_initoff: Can't calculate relative offset in signature for %s\n", patt->virname);
- if(info.exeinfo.section)
- free(info.exeinfo.section);
free(data->offtab);
free(data->offset);
return ret;
- } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length <= info.fsize)) {
+ } else if((data->offset[patt->offset_min] != CLI_OFF_NONE) && (data->offset[patt->offset_min] + patt->length <= info->fsize)) {
if(!data->cnt || (data->offset[patt->offset_min] + patt->prefix_length != data->offtab[data->cnt - 1])) {
data->offtab[data->cnt] = data->offset[patt->offset_min] + patt->prefix_length;
- if(data->offtab[data->cnt] >= map->len)
+ if(data->offtab[data->cnt] >= info->fsize)
continue;
data->cnt++;
}
}
}
- if(info.exeinfo.section)
- free(info.exeinfo.section);
cli_qsort(data->offtab, data->cnt, sizeof(uint32_t), NULL);
return CL_SUCCESS;
@@ -249,7 +244,7 @@ void cli_bm_free(struct cli_matcher *root)
}
}
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, fmap_t *map, struct cli_bm_off *offdata)
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata)
{
uint32_t i, j, off, off_min, off_max;
uint8_t found, pchain, shift;
@@ -257,7 +252,6 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
struct cli_bm_patt *p;
const unsigned char *bp, *pt;
unsigned char prefix;
- struct cli_target_info info;
int ret;
if(!root || !root->bm_shift)
@@ -266,7 +260,6 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(length < BM_MIN_LENGTH)
return CL_CLEAN;
- memset(&info, 0, sizeof(info));
i = BM_MIN_LENGTH - BM_BLOCK_SIZE;
if(offdata) {
if(!offdata->cnt)
@@ -362,11 +355,9 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
if(found && p->length + p->prefix_length == j) {
if(!offdata && (p->offset_min != CLI_OFF_ANY)) {
if(p->offdata[0] != CLI_OFF_ABSOLUTE) {
- ret = cli_caloff(NULL, &info, map, root->type, p->offdata, &off_min, &off_max);
+ ret = cli_caloff(NULL, info, root->type, p->offdata, &off_min, &off_max);
if(ret != CL_SUCCESS) {
cli_errmsg("cli_bm_scanbuff: Can't calculate relative offset in signature for %s\n", p->virname);
- if(info.exeinfo.section)
- free(info.exeinfo.section);
return ret;
}
} else {
@@ -383,8 +374,6 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
*virname = p->virname;
if(patt)
*patt = p;
- if(info.exeinfo.section)
- free(info.exeinfo.section);
return CL_VIRUS;
}
p = p->next;
@@ -404,7 +393,5 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v
}
- if(info.exeinfo.section)
- free(info.exeinfo.section);
return CL_CLEAN;
}
diff --git a/libclamav/matcher-bm.h b/libclamav/matcher-bm.h
index 6fe480f..9cb45fc 100644
--- a/libclamav/matcher-bm.h
+++ b/libclamav/matcher-bm.h
@@ -45,9 +45,9 @@ struct cli_bm_off {
int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const char *offset);
int cli_bm_init(struct cli_matcher *root);
-int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, fmap_t *map);
+int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, const struct cli_target_info *info);
void cli_bm_freeoff(struct cli_bm_off *data);
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, fmap_t *map, struct cli_bm_off *offdata);
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, const struct cli_target_info *info, struct cli_bm_off *offdata);
void cli_bm_free(struct cli_matcher *root);
#endif
diff --git a/libclamav/matcher-md5.c b/libclamav/matcher-md5.c
new file mode 100644
index 0000000..9bb2d63
--- /dev/null
+++ b/libclamav/matcher-md5.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007-2010 Sourcefire, Inc.
+ *
+ * Authors: Tomasz Kojm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#if HAVE_CONFIG_H
+#include "clamav-config.h"
+#endif
+
+#include <stdio.h>
+
+#include "clamav.h"
+#include "memory.h"
+#include "mpool.h"
+#include "others.h"
+#include "cltypes.h"
+#include "matcher.h"
+#include "matcher-md5.h"
+
+#define HASH(a,b,c) (211 * a + 37 * b + c)
+
+int cli_md5m_addpatt(struct cli_matcher *root, struct cli_md5m_patt *patt)
+{
+ unsigned int idx;
+ struct cli_md5m_patt *prev, *next = NULL;
+
+ idx = HASH(patt->md5[0], patt->md5[1], patt->md5[2]);
+ prev = next = root->md5tab[idx];
+ while(next) {
+ if(patt->md5[0] >= next->md5[0])
+ break;
+ prev = next;
+ next = next->next;
+ }
+
+ if(next == root->md5tab[idx]) {
+ patt->next = root->md5tab[idx];
+ root->md5tab[idx] = patt;
+ } else {
+ patt->next = prev->next;
+ prev->next = patt;
+ }
+
+ root->md5_patterns++;
+ return CL_SUCCESS;
+}
+
+int cli_md5m_init(struct cli_matcher *root)
+{
+#ifdef USE_MPOOL
+ if(!root->mempool) {
+ cli_errmsg("cli_md5m_init: mempool must be initialized\n");
+ return CL_EMEM;
+ }
+#endif
+
+ if(!(root->md5tab = (struct cli_md5m_patt **) mpool_calloc(root->mempool, HASH(255, 255, 255) + 1, sizeof(struct cli_md5m_patt *)))) {
+ mpool_free(root->mempool, root->bm_shift);
+ return CL_EMEM;
+ }
+
+ return CL_SUCCESS;
+}
+
+void cli_md5m_free(struct cli_matcher *root)
+{
+ struct cli_md5m_patt *patt, *prev;
+ unsigned int i, size = HASH(255, 255, 255) + 1;
+
+ if(root->md5tab) {
+ for(i = 0; i < size; i++) {
+ patt = root->md5tab[i];
+ while(patt) {
+ prev = patt;
+ patt = patt->next;
+ if(prev->virname)
+ mpool_free(root->mempool, prev->virname);
+ mpool_free(root->mempool, prev);
+ }
+ }
+ mpool_free(root->mempool, root->md5tab);
+ }
+}
+
+int cli_md5m_scan(const unsigned char *md5, uint32_t filesize, const char **virname, const struct cli_matcher *root)
+{
+ unsigned int pchain = 0, idx;
+ struct cli_md5m_patt *p;
+
+ if(!root)
+ return CL_CLEAN;
+
+ idx = HASH(md5[0], md5[1], md5[2]);
+ p = root->md5tab[idx];
+ if(!p || (!p->next && p->filesize != filesize))
+ return CL_CLEAN;
+
+ while(p) {
+ if(p->md5[0] != md5[0]) {
+ if(pchain)
+ break;
+ p = p->next;
+ continue;
+ } else pchain = 1;
+
+ if(p->filesize != filesize) {
+ p = p->next;
+ continue;
+ }
+
+ if(!memcmp(p->md5, md5, 16)) {
+ if(virname)
+ *virname = p->virname;
+ return CL_VIRUS;
+ }
+ p = p->next;
+ }
+
+ return CL_CLEAN;
+}
diff --git a/libclamav/matcher-md5.h b/libclamav/matcher-md5.h
new file mode 100644
index 0000000..b63adf7
--- /dev/null
+++ b/libclamav/matcher-md5.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007-2010 Sourcefire, Inc.
+ *
+ * Authors: Tomasz Kojm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#ifndef __MATCHER_MD5_H
+#define __MATCHER_MD5_H
+
+#include "matcher.h"
+#include "cltypes.h"
+
+struct cli_md5m_patt {
+ unsigned char md5[16];
+ uint32_t filesize;
+ char *virname;
+ struct cli_md5m_patt *next;
+};
+
+int cli_md5m_addpatt(struct cli_matcher *root, struct cli_md5m_patt *patt);
+int cli_md5m_init(struct cli_matcher *root);
+int cli_md5m_scan(const unsigned char *md5, uint32_t filesize, const char **virname, const struct cli_matcher *root);
+void cli_md5m_free(struct cli_matcher *root);
+
+#endif
diff --git a/libclamav/matcher.c b/libclamav/matcher.c
index c09658c..1675714 100644
--- a/libclamav/matcher.c
+++ b/libclamav/matcher.c
@@ -34,6 +34,7 @@
#include "others.h"
#include "matcher-ac.h"
#include "matcher-bm.h"
+#include "matcher-md5.h"
#include "md5.h"
#include "filetypes.h"
#include "matcher.h"
@@ -50,6 +51,8 @@
#include "regex/regex.h"
#include "filtering.h"
#include "perflogging.h"
+#include "bytecode_priv.h"
+#include "bytecode_api_impl.h"
#ifdef HAVE__INTERNAL__SHA_COLLECT
#include "sha256.h"
@@ -83,9 +86,11 @@ static inline int matcher_run(const struct cli_matcher *root,
const unsigned char *buffer, uint32_t length,
const char **virname, struct cli_ac_data *mdata,
uint32_t offset,
+ const struct cli_target_info *tinfo,
cli_file_t ftype,
struct cli_matched_type **ftoffset,
unsigned int acmode,
+ struct cli_ac_result **acres,
fmap_t *map,
struct cli_bm_off *offdata)
{
@@ -124,15 +129,15 @@ static inline int matcher_run(const struct cli_matcher *root,
/* Don't use prefiltering for BM offset mode, since BM keeps tracks
* of offsets itself, and doesn't work if we skip chunks of input
* data */
- ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, map, offdata);
+ ret = cli_bm_scanbuff(orig_buffer, orig_length, virname, NULL, root, orig_offset, tinfo, offdata);
} else {
- ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, map, offdata);
+ ret = cli_bm_scanbuff(buffer, length, virname, NULL, root, offset, tinfo, offdata);
}
if (ret == CL_VIRUS)
return ret;
}
PERF_LOG_TRIES(acmode, 0, length);
- ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, root, mdata, offset, ftype, ftoffset, acmode, NULL);
+ ret = cli_ac_scanbuff(buffer, length, virname, NULL, acres, root, mdata, offset, ftype, ftoffset, acmode, NULL);
return ret;
}
@@ -166,19 +171,19 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
- ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, ftype, NULL, AC_SCAN_VIR, *ctx->fmap, NULL);
+ ret = matcher_run(troot, buffer, length, virname, acdata ? (acdata[0]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
if(!acdata)
cli_ac_freedata(&mdata);
- if(ret == CL_VIRUS)
+ if(ret == CL_VIRUS || ret == CL_EMEM)
return ret;
}
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)))
return ret;
- ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, ftype, NULL, AC_SCAN_VIR, *ctx->fmap, NULL);
+ ret = matcher_run(groot, buffer, length, virname, acdata ? (acdata[1]): (&mdata), offset, NULL, ftype, NULL, AC_SCAN_VIR, NULL, *ctx->fmap, NULL);
if(!acdata)
cli_ac_freedata(&mdata);
@@ -192,9 +197,8 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset,
* offdata[2]: max shift
* offdata[3]: section number
*/
-int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
+int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max)
{
- int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
char offcpy[65];
unsigned int n, val;
char *pt;
@@ -307,33 +311,6 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, un
return CL_SUCCESS;
}
- if((offdata[0] == CLI_OFF_EOF_MINUS)) {
- if(!info->fsize)
- info->fsize = map->len;
- } else if(!info->status) {
- if(target == 1)
- einfo = cli_peheader;
- else if(target == 6)
- einfo = cli_elfheader;
- else if(target == 9)
- einfo = cli_machoheader;
-
- if(!einfo) {
- cli_errmsg("cli_caloff: Invalid offset/filetype\n");
- return CL_EMALFDB;
- }
-
- if(einfo(map, &info->exeinfo)) {
- /* einfo *may* fail */
- info->status = -1;
- *offset_min = CLI_OFF_NONE;
- if(offset_max)
- *offset_max = CLI_OFF_NONE;
- return CL_SUCCESS;
- }
- info->status = 1;
- }
-
switch(offdata[0]) {
case CLI_OFF_EOF_MINUS:
*offset_min = info->fsize - offdata[1];
@@ -376,15 +353,37 @@ int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, un
return CL_SUCCESS;
}
+static void targetinfo(struct cli_target_info *info, unsigned int target, fmap_t *map)
+{
+ int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
+
+
+ memset(info, 0, sizeof(struct cli_target_info));
+ info->fsize = map->len;
+
+ if(target == 1)
+ einfo = cli_peheader;
+ else if(target == 6)
+ einfo = cli_elfheader;
+ else if(target == 9)
+ einfo = cli_machoheader;
+ else return;
+
+ if(einfo(map, &info->exeinfo))
+ info->status = -1;
+ else
+ info->status = 1;
+}
+
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
{
char md5[33];
unsigned int i;
const char *virname;
- const struct cli_bm_patt *patt = NULL;
+ const struct cli_md5m_patt *patt = NULL;
- if(ctx->engine->md5_fp && cli_bm_scanbuff(digest, 16, &virname, &patt, ctx->engine->md5_fp, 0, NULL, NULL) == CL_VIRUS && patt->filesize == size) {
+ if(ctx->engine->md5_fp && cli_md5m_scan(digest, size, &virname, ctx->engine->md5_fp) == CL_VIRUS) {
cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname);
return CL_CLEAN;
}
@@ -422,26 +421,82 @@ int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx)
}
#endif
+ if(ctx->virsize && !*ctx->virsize) {
+ if(ctx->virsize)
+ *ctx->virsize = size;
+ if(ctx->virhash)
+ strcpy(ctx->virhash, md5);
+ }
+
return CL_VIRUS;
}
-static int matchicon(cli_ctx *ctx, const char *grp1, const char *grp2)
+static int matchicon(cli_ctx *ctx, struct cli_exe_info *exeinfo, const char *grp1, const char *grp2)
{
icon_groupset iconset;
+ if(!ctx ||
+ !ctx->engine ||
+ !ctx->engine->iconcheck ||
+ !ctx->engine->iconcheck->group_counts[0] ||
+ !ctx->engine->iconcheck->group_counts[1] ||
+ !exeinfo->res_addr
+ ) return CL_CLEAN;
+
cli_icongroupset_init(&iconset);
cli_icongroupset_add(grp1 ? grp1 : "*", &iconset, 0, ctx);
cli_icongroupset_add(grp2 ? grp2 : "*", &iconset, 1, ctx);
- return cli_match_icon(&iconset, ctx);
+ return cli_scanicon(&iconset, exeinfo->res_addr, ctx, exeinfo->section, exeinfo->nsections, exeinfo->hdr_size);
}
-int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode)
+int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx , const uint8_t* grp1, int32_t grp1len,
+ const uint8_t* grp2, int32_t grp2len)
+{
+ int ret;
+ char group1[128], group2[128];
+ const char **oldvirname;
+ struct cli_exe_info info;
+
+ if (!ctx->hooks.pedata->ep) {
+ cli_dbgmsg("bytecode: matchicon only works with PE files\n");
+ return -1;
+ }
+ if (grp1len > sizeof(group1)-1 ||
+ grp2len > sizeof(group2)-1)
+ return -1;
+ oldvirname = ((cli_ctx*)ctx->ctx)->virname;
+ ((cli_ctx*)ctx->ctx)->virname = NULL;
+ memcpy(group1, grp1, grp1len);
+ memcpy(group2, grp2, grp2len);
+ group1[grp1len] = 0;
+ group2[grp2len] = 0;
+ memset(&info, 0, sizeof(info));
+ if (ctx->bc->kind == BC_PE_UNPACKER) {
+ if(le16_to_host(ctx->hooks.pedata->file_hdr.Characteristics) & 0x2000 ||
+ !ctx->hooks.pedata->dirs[2].Size)
+ info.res_addr = 0;
+ else
+ info.res_addr = le32_to_host(ctx->hooks.pedata->dirs[2].VirtualAddress);
+ } else
+ info.res_addr = ctx->resaddr; /* from target_info */
+ info.section = (struct cli_exe_section*)ctx->sections;
+ info.nsections = ctx->hooks.pedata->nsections;
+ info.hdr_size = ctx->hooks.pedata->hdr_size;
+ cli_dbgmsg("bytecode matchicon %s %s\n", group1, group2);
+ ret = matchicon(ctx->ctx, &info, group1[0] ? group1 : NULL,
+ group2[0] ? group2 : NULL);
+ ((cli_ctx*)ctx->ctx)->virname = oldvirname;
+ return ret;
+}
+
+
+int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
{
int ret = CL_EMEM, empty;
fmap_t *map = *ctx->fmap;
if((*ctx->fmap = fmap_check_empty(desc, 0, 0, &empty))) {
- ret = cli_fmap_scandesc(ctx, ftype, ftonly, ftoffset, acmode, NULL);
+ ret = cli_fmap_scandesc(ctx, ftype, ftonly, ftoffset, acmode, acres, NULL);
map->dont_cache_flag = (*ctx->fmap)->dont_cache_flag;
funmap(*ctx->fmap);
}
@@ -451,12 +506,10 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
return ret;
}
-int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata)
+int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info)
{
unsigned int i, evalcnt;
uint64_t evalids;
- int (*einfo)(fmap_t *, struct cli_exe_info *) = NULL;
- struct cli_exe_info exeinfo;
fmap_t *map = *ctx->fmap;
for(i = 0; i < root->ac_lsigs; i++) {
@@ -470,40 +523,34 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
continue;
if(root->ac_lsigtable[i]->tdb.ep || root->ac_lsigtable[i]->tdb.nos) {
- einfo = NULL;
- if(root->type == 1)
- einfo = cli_peheader;
- else if(root->type == 6)
- einfo = cli_elfheader;
- else if(root->type == 9)
- einfo = cli_machoheader;
- if(!einfo)
+ if(!target_info || target_info->status != 1)
continue;
- memset(&exeinfo, 0, sizeof(exeinfo));
- if(einfo(map, &exeinfo))
+ if(root->ac_lsigtable[i]->tdb.ep && (root->ac_lsigtable[i]->tdb.ep[0] > target_info->exeinfo.ep || root->ac_lsigtable[i]->tdb.ep[1] < target_info->exeinfo.ep))
continue;
- if(exeinfo.section)
- free(exeinfo.section);
- if(root->ac_lsigtable[i]->tdb.ep && (root->ac_lsigtable[i]->tdb.ep[0] > exeinfo.ep || root->ac_lsigtable[i]->tdb.ep[1] < exeinfo.ep))
- continue;
- if(root->ac_lsigtable[i]->tdb.nos && (root->ac_lsigtable[i]->tdb.nos[0] > exeinfo.nsections || root->ac_lsigtable[i]->tdb.nos[1] < exeinfo.nsections))
+ if(root->ac_lsigtable[i]->tdb.nos && (root->ac_lsigtable[i]->tdb.nos[0] > target_info->exeinfo.nsections || root->ac_lsigtable[i]->tdb.nos[1] < target_info->exeinfo.nsections))
continue;
}
+
if(root->ac_lsigtable[i]->tdb.icongrp1 || root->ac_lsigtable[i]->tdb.icongrp2) {
- if(matchicon(ctx, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
- if(ctx->virname)
- *ctx->virname = root->ac_lsigtable[i]->virname;
- return CL_VIRUS;
- } else {
+ if(!target_info || target_info->status != 1)
continue;
+ if(matchicon(ctx, &target_info->exeinfo, root->ac_lsigtable[i]->tdb.icongrp1, root->ac_lsigtable[i]->tdb.icongrp2) == CL_VIRUS) {
+ if(!root->ac_lsigtable[i]->bc_idx) {
+ if(ctx->virname)
+ *ctx->virname = root->ac_lsigtable[i]->virname;
+ return CL_VIRUS;
+ } else if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff[i], map) == CL_VIRUS) {
+ return CL_VIRUS;
+ }
}
+ continue;
}
if(!root->ac_lsigtable[i]->bc_idx) {
if(ctx->virname)
*ctx->virname = root->ac_lsigtable[i]->virname;
return CL_VIRUS;
}
- if(cli_bytecode_runlsig(ctx, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff[i], map) == CL_VIRUS) {
+ if(cli_bytecode_runlsig(ctx, target_info, &ctx->engine->bcs, root->ac_lsigtable[i]->bc_idx, ctx->virname, acdata->lsigcnt[i], acdata->lsigsuboff[i], map) == CL_VIRUS) {
return CL_VIRUS;
}
}
@@ -511,17 +558,18 @@ int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *ac
return CL_CLEAN;
}
-int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, unsigned char *refhash)
+int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
{
unsigned char *buff;
int ret = CL_CLEAN, type = CL_CLEAN, bytes;
- unsigned int i, bm_offmode = 0;
+ unsigned int i = 0, bm_offmode = 0;
uint32_t maxpatlen, offset = 0;
struct cli_ac_data gdata, tdata;
struct cli_bm_off toff;
cli_md5_ctx md5ctx;
unsigned char digest[16];
struct cli_matcher *groot = NULL, *troot = NULL;
+ struct cli_target_info info;
fmap_t *map = *ctx->fmap;
if(!ctx->engine) {
@@ -553,22 +601,31 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
maxpatlen = groot->maxpatlen;
}
+ targetinfo(&info, i, map);
+
if(!ftonly)
- if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, map)))
+ if((ret = cli_ac_initdata(&gdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(groot, &gdata, &info))) {
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
return ret;
+ }
if(troot) {
- if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, map))) {
+ if((ret = cli_ac_initdata(&tdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN)) || (ret = cli_ac_caloff(troot, &tdata, &info))) {
if(!ftonly)
cli_ac_freedata(&gdata);
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
return ret;
}
if(troot->bm_offmode) {
if(map->len >= CLI_DEFAULT_BM_OFFMODE_FSIZE) {
- if((ret = cli_bm_initoff(troot, &toff, map))) {
+ if((ret = cli_bm_initoff(troot, &toff, &info))) {
if(!ftonly)
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
return ret;
}
bm_offmode = 1;
@@ -587,28 +644,33 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
*ctx->scanned += bytes / CL_COUNT_PRECISION;
if(troot) {
- ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, ftype, ftoffset, acmode, map, bm_offmode ? &toff : NULL);
+ ret = matcher_run(troot, buff, bytes, ctx->virname, &tdata, offset, &info, ftype, ftoffset, acmode, acres, map, bm_offmode ? &toff : NULL);
- if(ret == CL_VIRUS) {
+ if(ret == CL_VIRUS || ret == CL_EMEM) {
if(!ftonly)
cli_ac_freedata(&gdata);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
- return CL_VIRUS;
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
+ return ret;
}
}
if(!ftonly) {
- ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, ftype, ftoffset, acmode, map, NULL);
- if(ret == CL_VIRUS) {
+ ret = matcher_run(groot, buff, bytes, ctx->virname, &gdata, offset, &info, ftype, ftoffset, acmode, acres, map, NULL);
+
+ if(ret == CL_VIRUS || ret == CL_EMEM) {
cli_ac_freedata(&gdata);
if(troot) {
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
}
- return CL_VIRUS;
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
+ return ret;
} else if((acmode & AC_SCAN_FT) && ret >= CL_TYPENO) {
if(ret > type)
type = ret;
@@ -623,7 +685,7 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
}
if(troot) {
- ret = cli_lsig_eval(ctx, troot, &tdata);
+ ret = cli_lsig_eval(ctx, troot, &tdata, &info);
cli_ac_freedata(&tdata);
if(bm_offmode)
cli_bm_freeoff(&toff);
@@ -631,20 +693,23 @@ int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli
if(groot) {
if(ret != CL_VIRUS)
- ret = cli_lsig_eval(ctx, groot, &gdata);
+ ret = cli_lsig_eval(ctx, groot, &gdata, &info);
cli_ac_freedata(&gdata);
}
+ if(info.exeinfo.section)
+ free(info.exeinfo.section);
+
if(ret == CL_VIRUS)
return CL_VIRUS;
if(!ftonly && ctx->engine->md5_hdb) {
- const struct cli_bm_patt *patt;
+ const struct cli_md5m_patt *patt;
if(!refhash) {
cli_md5_final(digest, &md5ctx);
refhash = digest;
}
- if(cli_bm_scanbuff(refhash, 16, ctx->virname, &patt, ctx->engine->md5_hdb, 0, NULL, NULL) == CL_VIRUS && patt->filesize == map->len && (cli_bm_scanbuff(refhash, 16, NULL, &patt, ctx->engine->md5_fp, 0, NULL, NULL) != CL_VIRUS || patt->filesize != map->len))
+ if(cli_md5m_scan(refhash, map->len, ctx->virname, ctx->engine->md5_hdb) == CL_VIRUS && cli_md5m_scan(refhash, map->len, NULL, ctx->engine->md5_fp) != CL_VIRUS)
return CL_VIRUS;
}
diff --git a/libclamav/matcher.h b/libclamav/matcher.h
index c2ae651..7d32fbf 100644
--- a/libclamav/matcher.h
+++ b/libclamav/matcher.h
@@ -30,6 +30,12 @@
#include "cltypes.h"
#include "md5.h"
+struct cli_target_info {
+ off_t fsize;
+ struct cli_exe_info exeinfo;
+ int status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
+};
+
#include "matcher-ac.h"
#include "matcher-bm.h"
#include "hashtab.h"
@@ -52,6 +58,7 @@ struct cli_lsig_tdb {
uint32_t *val, *range;
char *str;
uint32_t cnt[3];
+ uint32_t subsigs;
const uint32_t *target;
const uint32_t *engine, *nos, *ep, *filesize;
@@ -62,7 +69,6 @@ struct cli_lsig_tdb {
*/
const char *icongrp1, *icongrp2;
uint32_t *macro_ptids;
- uint32_t subsigs;
#ifdef USE_MPOOL
mpool_t *mempool;
#endif
@@ -71,10 +77,10 @@ struct cli_lsig_tdb {
struct cli_bc;
struct cli_ac_lsig {
uint32_t id;
+ unsigned bc_idx;
char *logic;
const char *virname;
struct cli_lsig_tdb tdb;
- unsigned bc_idx;
};
struct cli_matcher {
@@ -87,6 +93,10 @@ struct cli_matcher {
uint32_t *soff, soff_len; /* for PE section sigs */
uint32_t bm_offmode, bm_patterns, bm_reloff_num, bm_absoff_num;
+ /* MD5 */
+ struct cli_md5m_patt **md5tab;
+ uint32_t md5_patterns;
+
/* Extended Aho-Corasick */
uint32_t ac_partsigs, ac_nodes, ac_patterns, ac_lsigs;
struct cli_ac_lsig **ac_lsigtable;
@@ -144,12 +154,6 @@ static const struct cli_mtarget cli_mtargets[CLI_MTARGETS] = {
{ CL_TYPE_MACHO, "MACH-O", 9, 1, 0 }
};
-struct cli_target_info {
- off_t fsize;
- struct cli_exe_info exeinfo;
- int8_t status; /* 0 == not initialised, 1 == initialised OK, -1 == error */
-};
-
#define CLI_OFF_ANY 0xffffffff
#define CLI_OFF_NONE 0xfffffffe
#define CLI_OFF_ABSOLUTE 1
@@ -163,10 +167,10 @@ struct cli_target_info {
int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, cli_ctx *ctx, cli_file_t ftype, struct cli_ac_data **acdata);
-int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode);
-int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, unsigned char *refhash);
-int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata);
-int cli_caloff(const char *offstr, struct cli_target_info *info, fmap_t *map, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
+int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres);
+int cli_fmap_scandesc(cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash);
+int cli_lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info);
+int cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
int cli_checkfp(unsigned char *digest, size_t size, cli_ctx *ctx);
diff --git a/libclamav/mpool.c b/libclamav/mpool.c
index 98b5bc7..f81d51b 100644
--- a/libclamav/mpool.c
+++ b/libclamav/mpool.c
@@ -44,15 +44,16 @@
#include "str.h"
#include "readdb.h"
+/*#define CL_DEBUG*/
#ifdef CL_DEBUG
#include <assert.h>
-#define MPOOLMAGIC 0x5adeada5
+#define MPOOLMAGIC 0xadde
#define ALLOCPOISON 0x5a
#define FREEPOISON 0xde
#endif
-/* #define DEBUGMPOOL */
-/* #define EXIT_ON_FLUSH */
+/*#define DEBUGMPOOL
+#define EXIT_ON_FLUSH*/
#ifdef DEBUGMPOOL
#define spam(...) cli_warnmsg( __VA_ARGS__)
#else
@@ -65,72 +66,80 @@ static inline void spam(const char *fmt, ...) { fmt = fmt; } /* gcc STFU */
#if SIZEOF_VOID_P==8
static const unsigned int fragsz[] = {
-/* SIZE PERM TEMP MAX ACT! */
- 16, /* 1487281 7051 1487281 USE */
- 24, /* 89506 103 89510 USE */
- 32, /* 1313968 65 1313969 USE */
- 40, /* 23221 43 23222 USE */
- 48, /* 800586 87 800588 USE */
- 56, /* 5634 32 5634 USE */
- 64, /* 2762 31 2762 USE */
- 72, /* 2343 29 2343 USE */
- 80, /* 1857605 32 1857606 USE */
- 88, /* 2619 28 2619 USE */
- 96, /* 3556 27 3556 USE */
- 104, /* 3670 24 3670 USE */
- 112, /* 3998 23 3998 USE */
- 120, /* 5100 22 5100 USE */
- 128, /* 3092 22 3092 USE */
- 136, /* 4075 22 4075 USE */
- 144, /* 4412 22 4412 USE */
- 152, /* 41875 21 41875 USE */
- 160, /* 17264 21 17264 USE */
- 176, /* 517 20 517 USE */
- 192, /* 332 20 332 USE */
- 208, /* 451 20 451 USE */
- 216, /* 408 20 408 USE */
- 224, /* 276 20 276 USE */
- 240, /* 484 19 484 USE */
- 256, /* 529 19 529 USE */
- 264, /* 219 19 219 USE */
- 272, /* 368 19 368 USE */
- 280, /* 239 19 239 USE */
- 288, /* 252 19 252 USE */
- 312, /* 744 19 744 USE */
- 352, /* 23 19 23 USE */
- 384, /* 11 18 11 USE */
- 408, /* 11 18 11 USE */
- 512, /* 1 18 2 USE */
- 520, /* 3 18 4 USE */
- 632, /* 2 18 3 USE */
- 1024, /* 0 17 1 USE */
- 2048, /* 0 17 1 USE */
- 2056, /* 11920 16 11920 USE */
- 4096, /* 0 16 1 USE */
- 6144, /* 1 15 1 USE */
- 8192, /* 0 14 1 USE */
- 8816, /* 1 13 1 USE */
- 8872, /* 1 12 1 USE */
- 11376, /* 1 10 1 USE */
- 16384, /* 0 8 1 USE */
- 16392, /* 256 8 257 USE */
- 21096, /* 1 7 1 USE */
- 32768, /* 0 7 1 USE */
- 34752, /* 1 6 2 USE */
- 44736, /* 1 4 1 USE */
- 48384, /* 1 3 1 USE */
- 63504, /* 9 3 10 USE */
- 65536, /* 0 3 1 USE */
- 91624, /* 1 2 1 USE */
- 105568, /* 1 1 1 USE */
- 131072, /* 0 1 1 USE */
- 131088, /* 6 1 7 USE */
- 131784, /* 1 1 2 USE */
- 154896, /* 1 1 1 USE */
- 262144, /* 0 1 1 USE */
- 372712, /* 1 0 1 USE */
- 507976, /* 9 0 9 USE */
- 524288, /* 0 0 0 USE */
+/* SIZE, MAX */
+ 8, /* 783293 */
+ 11, /* 4445 */
+ 13, /* 10160 */
+ 15, /* 8365 */
+ 16, /* 24857 */
+ 17, /* 24630 */
+ 19, /* 136608 */
+ 20, /* 90714 */
+ 21, /* 176421 */
+ 23, /* 52766 */
+ 24, /* 161770 */
+ 25, /* 38590 */
+ 29, /* 18023 */
+ 31, /* 15987 */
+ 32, /* 104854 */
+ 33, /* 9312 */
+ 35, /* 371084 */
+ 41, /* 5068 */
+ 43, /* 142581 */
+ 44, /* 99347 */
+ 45, /* 74173 */
+ 47, /* 31516 */
+ 48, /* 320748 */
+ 49, /* 45256 */
+ 56, /* 1543 */
+ 64, /* 963 */
+ 74, /* 12397 */
+ 76, /* 17846 */
+ 79, /* 15721 */
+ 80, /* 599771 */
+ 81, /* 5618 */
+ 93, /* 2101 */
+ 97, /* 2425 */
+ 104, /* 1495 */
+ 113, /* 3107 */
+ 116, /* 2403 */
+ 123, /* 1415 */
+ 128, /* 2368 */
+ 131, /* 2697 */
+ 143, /* 10539 */
+ 150, /* 10982 */
+ 151, /* 6869 */
+ 152, /* 28254 */
+ 153, /* 13670 */
+ 229, /* 501 */
+ 256, /* 830 */
+ 304, /* 834 */
+ 320, /* 377 */
+ 512, /* 17 */
+ 1024, /* 6 */
+ 2048, /* 3 */
+ 2056, /* 10116 */
+ 4096, /* 3 */
+ 8192, /* 2 */
+ 9334, /* 3 */
+ 12163, /* 4 */
+ 16392, /* 257 */
+ 18440, /* 2 */
+ 21952, /* 1 */
+ 32768, /* 1 */
+ 35311, /* 1 */
+ 43256, /* 2 */
+ 48914, /* 1 */
+ 63504, /* 8 */
+ 65536, /* 0 */
+ 92794, /* 1 */
+ 107602, /* 1 */
+ 131832, /* 7 */
+ 156920, /* 1 */
+ 262144, /* 1 */
+ 374608, /* 1 */
+ 507976, /* 10 */
+ 524288, /* 0 */
1048576,
2097152,
4194304,
@@ -141,79 +150,104 @@ static const unsigned int fragsz[] = {
#else
static const unsigned int fragsz[] = {
-/* SIZE PERM TEMP ACT! */
- 16, /* 1487589 7134 1487589 USE */
- 24, /* 116448 127 116452 USE */
- 32, /* 1287128 95 1287134 USE */
- 40, /* 23174 60 23174 USE */
- 48, /* 800778 81 800779 USE */
- 56, /* 5633 51 5633 USE */
- 64, /* 1857039 49 1857040 USE */
- 72, /* 2341 44 2341 USE */
- 80, /* 3702 43 3702 USE */
- 88, /* 2619 41 2619 USE */
- 96, /* 3563 40 3563 USE */
- 104, /* 3667 40 3667 USE */
- 112, /* 3997 40 3997 USE */
- 120, /* 34560 40 34560 USE */
- 128, /* 3093 38 3093 USE */
- 136, /* 3988 38 3988 USE */
- 144, /* 4412 38 4412 USE */
- 152, /* 12413 38 12413 USE */
- 160, /* 17264 38 17264 USE */
- 168, /* 397 38 397 USE */
- 176, /* 517 38 517 USE */
- 184, /* 328 37 328 USE */
- 192, /* 332 36 332 USE */
- 208, /* 451 36 451 USE */
- 216, /* 408 36 408 USE */
- 224, /* 276 36 276 USE */
- 240, /* 483 36 483 USE */
- 248, /* 254 36 254 USE */
- 256, /* 529 36 529 USE */
- 264, /* 219 36 219 USE */
- 272, /* 368 36 368 USE */
- 288, /* 252 36 252 USE */
- 304, /* 315 36 315 USE */
- 312, /* 744 36 744 USE */
- 336, /* 51 36 51 USE */
- 352, /* 23 36 23 USE */
- 368, /* 29 36 29 USE */
- 408, /* 11 36 11 USE */
- 440, /* 11 34 11 USE */
- 512, /* 1 34 1 USE */
- 520, /* 3 34 4 USE */
- 592, /* 10 34 10 USE */
- 632, /* 2 34 3 USE */
- 736, /* 1 34 2 USE */
- 1024, /* 0 34 1 USE */
- 1032, /* 11920 33 11920 USE */
- 2048, /* 0 32 2 USE */
- 3080, /* 1 30 1 USE */
- 4096, /* 0 28 1 USE */
- 4416, /* 1 26 1 USE */
- 4440, /* 1 25 1 USE */
- 5696, /* 1 20 1 USE */
- 8192, /* 0 16 1 USE */
- 10248, /* 1 16 2 USE */
- 11272, /* 256 14 257 USE */
- 16384, /* 0 14 1 USE */
- 17384, /* 1 12 2 USE */
- 22376, /* 1 8 1 USE */
- 24200, /* 1 6 1 USE */
- 32768, /* 0 6 1 USE */
- 45816, /* 1 5 1 USE */
- 52792, /* 1 2 1 USE */
- 63504, /* 9 2 10 USE */
- 65536, /* 0 2 1 USE */
- 131072, /* 0 2 1 USE */
- 131088, /* 6 2 7 USE */
- 131528, /* 1 2 2 USE */
- 154896, /* 1 2 1 USE */
- 186360, /* 1 1 1 USE */
- 253992, /* 9 0 9 USE */
- 262144, /* 0 0 0 USE */
- 525752,
+/* SIZE, MAX */
+ 4, /* 576046 */
+ 7, /* 205452 */
+ 8, /* 2448 */
+ 9, /* 1633 */
+ 11, /* 2740 */
+ 12, /* 6315 */
+ 13, /* 8821 */
+ 15, /* 15903 */
+ 16, /* 31401 */
+ 17, /* 28027 */
+ 19, /* 136365 */
+ 20, /* 95662 */
+ 21, /* 176094 */
+ 23, /* 54138 */
+ 24, /* 156993 */
+ 25, /* 39393 */
+ 28, /* 16340 */
+ 29, /* 9807 */
+ 30, /* 5132 */
+ 31, /* 176283 */
+ 32, /* 484214 */
+ 33, /* 129187 */
+ 37, /* 1163 */
+ 40, /* 3311 */
+ 41, /* 1513 */
+ 48, /* 3930 */
+ 49, /* 1018 */
+ 56, /* 2303 */
+ 58, /* 13518 */
+ 59, /* 4709 */
+ 60, /* 13577 */
+ 61, /* 3093 */
+ 62, /* 10407 */
+ 63, /* 3973 */
+ 64, /* 26914 */
+ 65, /* 2963 */
+ 73, /* 2314 */
+ 81, /* 2038 */
+ 85, /* 1306 */
+ 88, /* 1395 */
+ 93, /* 885 */
+ 96, /* 878 */
+ 104, /* 3746 */
+ 108, /* 685 */
+ 113, /* 2940 */
+ 115, /* 3625 */
+ 116, /* 3827 */
+ 117, /* 2517 */
+ 119, /* 4260 */
+ 120, /* 17485 */
+ 121, /* 1945 */
+ 128, /* 2653 */
+ 131, /* 2304 */
+ 136, /* 1090 */
+ 143, /* 10787 */
+ 148, /* 1292 */
+ 152, /* 3494 */
+ 153, /* 11788 */
+ 168, /* 505 */
+ 176, /* 652 */
+ 200, /* 350 */
+ 216, /* 312 */
+ 232, /* 402 */
+ 248, /* 495 */
+ 256, /* 140 */
+ 284, /* 439 */
+ 309, /* 817 */
+ 452, /* 57 */
+ 512, /* 3 */
+ 784, /* 14 */
+ 1024, /* 2 */
+ 1028, /* 3191 */
+ 1032, /* 7777 */
+ 2048, /* 5 */
+ 4096, /* 3 */
+ 5128, /* 5 */
+ 8192, /* 3 */
+ 11264, /* 5 */
+ 11268, /* 238 */
+ 11272, /* 243 */
+ 16384, /* 1 */
+ 17657, /* 1 */
+ 21632, /* 2 */
+ 23188, /* 2 */
+ 24458, /* 1 */
+ 32768, /* 1 */
+ 46398, /* 1 */
+ 53804, /* 1 */
+ 63504, /* 7 */
+ 65536, /* 1 */
+ 131072, /* 0 */
+ 131080, /* 7 */
+ 131544, /* 2 */
+ 156920, /* 1 */
+ 187304, /* 1 */
+ 253988, /* 10 */
+ 262144, /* 0 */
1048576,
2097152,
4194304,
@@ -237,23 +271,23 @@ struct MP {
} u;
};
+/* alignment of fake handled in the code! */
+struct alloced {
+ uint8_t padding;
+ uint8_t sbits;
+ uint8_t fake;
+};
+
struct FRAG {
#ifdef CL_DEBUG
- unsigned int magic;
+ uint16_t magic;
#endif
union {
- struct FRAG *next;
- unsigned int sbits;
- int64_t dummy_align;
- /* needed to align to 64-bit on sparc, since pointers are 32-bit only,
- * yet we need 64-bit alignment for struct containing int64 members */
+ struct alloced a;
+ struct unaligned_ptr next;
} u;
- void *fake;
};
-#define FRAG_OVERHEAD (offsetof(struct FRAG, fake))
-
-#define align_to_voidptr(size) (((size) / MAX(sizeof(void *), 8) + ((size) % MAX(sizeof(void *), 8) != 0)) * MAX(sizeof(void *), 8))
-#define mpool_roundup(size) (FRAG_OVERHEAD + align_to_voidptr(size))
+#define FRAG_OVERHEAD (offsetof(struct FRAG, u.a.fake))
static unsigned int align_to_pagesize(struct MP *mp, unsigned int size) {
return (size / mp->psize + (size % mp->psize != 0)) * mp->psize;
@@ -265,25 +299,65 @@ static unsigned int to_bits(unsigned int size) {
if(fragsz[i] >= size) return i;
return FRAGSBITS;
}
+
static unsigned int from_bits(unsigned int bits) {
if (bits >= FRAGSBITS) return 0;
return fragsz[bits];
}
+static inline unsigned int alignof(unsigned int size)
+{
+ /* conservative estimate of alignment.
+ * A struct that needs alignment of 'align' is padded by the compiler
+ * so that sizeof(struct)%align == 0
+ * (otherwise you wouldn't be able to use it in an array)
+ * Also align = 2^n.
+ * Largest alignment we need is 8 bytes (ptr/int64), since we don't use long
+ * double or __aligned attribute.
+ * This conservatively estimates that size 32 needs alignment of 8 (even if it might only
+ * need an alignment of 4).
+ */
+ switch (size%8) {
+ case 0:
+ return 8;
+ case 2:
+ case 6:
+ return 2;
+ case 4:
+ return 4;
+ default:
+ return 1;
+ }
+}
+
+static inline size_t alignto(size_t p, size_t size)
+{
+ /* size is power of 2 */
+ return (p+size-1)&(~(size-1));
+}
+
struct MP *mpool_create() {
struct MP mp, *mpool_p;
unsigned int sz;
memset(&mp, 0, sizeof(mp));
mp.psize = cli_getpagesize();
sz = align_to_pagesize(&mp, MIN_FRAGSIZE);
- mp.u.mpm.usize = align_to_voidptr(sizeof(struct MPMAP));
- mp.u.mpm.size = sz - align_to_voidptr(sizeof(mp));
+ mp.u.mpm.usize = sizeof(struct MPMAP);
+ mp.u.mpm.size = sz - sizeof(mp);
#ifndef _WIN32
if ((mpool_p = (struct MP *)mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE|ANONYMOUS_MAP, -1, 0)) == MAP_FAILED)
#else
if(!(mpool_p = (struct MP *)VirtualAlloc(NULL, sz, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)))
#endif
return NULL;
+ if (FRAGSBITS > 255) {
+ cli_errmsg("At most 255 frags possible!\n");
+ return NULL;
+ }
+ if (fragsz[0] < sizeof(void*)) {
+ cli_errmsg("fragsz[0] too small!\n");
+ return NULL;
+ }
#ifdef CL_DEBUG
memset(mpool_p, ALLOCPOISON, sz);
#endif
@@ -310,10 +384,10 @@ void mpool_destroy(struct MP *mp) {
}
mpmsize = mp->u.mpm.size;
#ifdef CL_DEBUG
- memset(mp, FREEPOISON, mpmsize + align_to_voidptr(sizeof(*mp)));
+ memset(mp, FREEPOISON, mpmsize + sizeof(*mp));
#endif
#ifndef _WIN32
- munmap((void *)mp, mpmsize + align_to_voidptr(sizeof(*mp)));
+ munmap((void *)mp, mpmsize + sizeof(*mp));
#else
VirtualFree(mp, 0, MEM_RELEASE);
#endif
@@ -345,17 +419,17 @@ void mpool_flush(struct MP *mp) {
used += mpm->size;
}
- mused = align_to_pagesize(mp, mp->u.mpm.usize + align_to_voidptr(sizeof(*mp)));
- if (mused < mp->u.mpm.size + align_to_voidptr(sizeof(*mp))) {
+ mused = align_to_pagesize(mp, mp->u.mpm.usize + sizeof(*mp));
+ if (mused < mp->u.mpm.size + sizeof(*mp)) {
#ifdef CL_DEBUG
- memset((char *)mp + mused, FREEPOISON, mp->u.mpm.size + align_to_voidptr(sizeof(*mp)) - mused);
+ memset((char *)mp + mused, FREEPOISON, mp->u.mpm.size + sizeof(*mp) - mused);
#endif
#ifndef _WIN32
- munmap((char *)mp + mused, mp->u.mpm.size + align_to_voidptr(sizeof(*mp)) - mused);
+ munmap((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused);
#else
- VirtualFree((char *)mp + mused, mp->u.mpm.size + align_to_voidptr(sizeof(*mp)) - mused, MEM_DECOMMIT);
+ VirtualFree((char *)mp + mused, mp->u.mpm.size + sizeof(*mp) - mused, MEM_DECOMMIT);
#endif
- mp->u.mpm.size = mused - align_to_voidptr(sizeof(*mp));
+ mp->u.mpm.size = mused - sizeof(*mp);
}
used += mp->u.mpm.size;
spam("Map flushed @%p, in use: %lu\n", mp, used);
@@ -382,8 +456,48 @@ int mpool_getstats(const struct cl_engine *eng, size_t *used, size_t *total)
return 0;
}
+static inline unsigned align_increase(unsigned size, unsigned a)
+{
+ /* we must pad with at most a-1 bytes to align start of struct */
+ return size + a - 1;
+}
+
+static void* allocate_aligned(struct MPMAP *mpm, unsigned long size, unsigned align, const char *dbg)
+{
+ /* We could always align the size to maxalign (8), however that wastes
+ * space.
+ * So just align the start of each allocation as needed, and then see in
+ * which sbits bin we fit into.
+ * Since we are no longer allocating in multiple of 8, we must always
+ * align the start of each allocation!
+ *| end of previous allocation | padding | FRAG_OVERHEAD | ptr_aligned |*/
+ unsigned p = mpm->usize + FRAG_OVERHEAD;
+ unsigned p_aligned = alignto(p, align);
+ struct FRAG *f = (struct FRAG*)((char*)mpm + p_aligned - FRAG_OVERHEAD);
+ unsigned realneed = p_aligned + size - mpm->usize;
+ unsigned sbits = to_bits(realneed);
+ unsigned needed = from_bits(sbits);
+#ifdef CL_DEBUG
+ assert(p_aligned + size <= mpm->size);
+#endif
+ f->u.a.sbits = sbits;
+ f->u.a.padding = p_aligned - p;
+
+ mpm->usize += needed;
+#ifdef CL_DEBUG
+ assert(mpm->usize <= mpm->size);
+#endif
+ spam("malloc @%p size %u (%s) origsize %u overhead %u\n", f, realneed, dbg, size, needed - size);
+#ifdef CL_DEBUG
+ f->magic = MPOOLMAGIC;
+ memset(&f->u.a.fake, ALLOCPOISON, size);
+#endif
+ return &f->u.a.fake;
+}
+
void *mpool_malloc(struct MP *mp, size_t size) {
- unsigned int i, needed = align_to_voidptr(size + FRAG_OVERHEAD);
+ unsigned align = alignof(size);
+ unsigned int i, needed = align_increase(size+FRAG_OVERHEAD, align);
const unsigned int sbits = to_bits(needed);
struct FRAG *f = NULL;
struct MPMAP *mpm = &mp->u.mpm;
@@ -396,14 +510,18 @@ void *mpool_malloc(struct MP *mp, size_t size) {
/* Case 1: We have a free'd frag */
if((f = mp->avail[sbits])) {
- spam("malloc @%p size %u (freed)\n", f, align_to_voidptr(size + FRAG_OVERHEAD));
- mp->avail[sbits] = f->u.next;
- f->u.sbits = sbits;
+ struct FRAG *fold = f;
+ mp->avail[sbits] = f->u.next.ptr;
+ /* we always have enough space for this, align_increase ensured that */
+ f = (struct FRAG*)(alignto((unsigned long)f + FRAG_OVERHEAD, align)-FRAG_OVERHEAD);
+ f->u.a.sbits = sbits;
+ f->u.a.padding = (char*)f - (char*)fold;
#ifdef CL_DEBUG
- f->magic = MPOOLMAGIC;
- memset(&f->fake, ALLOCPOISON, size);
+ f->magic = MPOOLMAGIC;
+ memset(&f->u.a.fake, ALLOCPOISON, size);
#endif
- return &f->fake;
+ spam("malloc @%p size %u (freed) origsize %u overhead %u\n", f, f->u.a.padding + FRAG_OVERHEAD + size, size, needed - size);
+ return &f->u.a.fake;
}
if (!(needed = from_bits(sbits))) {
@@ -413,23 +531,14 @@ void *mpool_malloc(struct MP *mp, size_t size) {
/* Case 2: We have nuff room available for this frag already */
while(mpm) {
- if(mpm->size - mpm->usize >= needed) {
- f = (struct FRAG *)((char *)mpm + mpm->usize);
- spam("malloc @%p size %u (hole)\n", f, align_to_voidptr(size + FRAG_OVERHEAD));
- mpm->usize += needed;
- f->u.sbits = sbits;
-#ifdef CL_DEBUG
- f->magic = MPOOLMAGIC;
- memset(&f->fake, ALLOCPOISON, size);
-#endif
- return &f->fake;
- }
+ if(mpm->size - mpm->usize >= needed)
+ return allocate_aligned(mpm, size, align, "hole");
mpm = mpm->next;
}
/* Case 3: We allocate more */
- if (needed + align_to_voidptr(sizeof(*mpm)) > MIN_FRAGSIZE)
- i = align_to_pagesize(mp, needed + align_to_voidptr(sizeof(*mpm)));
+ if (needed + sizeof(*mpm) > MIN_FRAGSIZE)
+ i = align_to_pagesize(mp, needed + sizeof(*mpm));
else
i = align_to_pagesize(mp, MIN_FRAGSIZE);
@@ -446,16 +555,18 @@ void *mpool_malloc(struct MP *mp, size_t size) {
memset(mpm, ALLOCPOISON, i);
#endif
mpm->size = i;
- mpm->usize = needed + align_to_voidptr(sizeof(*mpm));
+ mpm->usize = sizeof(*mpm);
mpm->next = mp->u.mpm.next;
mp->u.mpm.next = mpm;
- f = (struct FRAG *)((char *)mpm + align_to_voidptr(sizeof(*mpm)));
- spam("malloc @%p size %u (new map)\n", f, align_to_voidptr(size + FRAG_OVERHEAD));
- f->u.sbits = sbits;
+ return allocate_aligned(mpm, size, align, "new map");
+}
+
+static void *allocbase_fromfrag(struct FRAG *f)
+{
#ifdef CL_DEBUG
- f->magic = MPOOLMAGIC;
+ assert(f->u.a.padding < 8);
#endif
- return &f->fake;
+ return (char*)f - f->u.a.padding;
}
void mpool_free(struct MP *mp, void *ptr) {
@@ -465,13 +576,17 @@ void mpool_free(struct MP *mp, void *ptr) {
#ifdef CL_DEBUG
assert(f->magic == MPOOLMAGIC && "Attempt to mpool_free a pointer we did not allocate!");
- memset(ptr, FREEPOISON, from_bits(f->u.sbits) - FRAG_OVERHEAD);
#endif
- sbits = f->u.sbits;
- f->u.next = mp->avail[sbits];
- mp->avail[sbits] = f;
spam("free @%p\n", f);
+ sbits = f->u.a.sbits;
+ f = allocbase_fromfrag(f);
+#ifdef CL_DEBUG
+ memset(f, FREEPOISON, from_bits(sbits));
+#endif
+
+ f->u.next.ptr = mp->avail[sbits];
+ mp->avail[sbits] = f;
}
void *mpool_calloc(struct MP *mp, size_t nmemb, size_t size) {
@@ -490,14 +605,14 @@ void *mpool_realloc(struct MP *mp, void *ptr, size_t size) {
void *new_ptr;
if (!ptr) return mpool_malloc(mp, size);
- if(!size || !(csize = from_bits(f->u.sbits))) {
+ if(!size || !(csize = from_bits(f->u.a.sbits))) {
cli_errmsg("mpool_realloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
return NULL;
}
- csize -= FRAG_OVERHEAD;
- if (csize >= size && (!f->u.sbits || from_bits(f->u.sbits-1)-FRAG_OVERHEAD < size)) {
+ csize -= FRAG_OVERHEAD + f->u.a.padding;
+ if (csize >= size && (!f->u.a.sbits || from_bits(f->u.a.sbits-1)-FRAG_OVERHEAD-f->u.a.padding < size)) {
spam("free @%p\n", f);
- spam("malloc @%p size %u (self)\n", f, align_to_voidptr(size + FRAG_OVERHEAD));
+ spam("malloc @%p size %u (self) origsize %u overhead %u\n", f, size + FRAG_OVERHEAD + f->u.a.padding, size, csize-size+FRAG_OVERHEAD+f->u.a.padding);
return ptr;
}
if (!(new_ptr = mpool_malloc(mp, size)))
diff --git a/libclamav/mspack.c b/libclamav/mspack.c
index 6af8648..8bae3c5 100644
--- a/libclamav/mspack.c
+++ b/libclamav/mspack.c
@@ -1947,6 +1947,8 @@ int qtm_decompress(struct qtm_stream *qtm, off_t out_bytes) {
if (window_posn == qtm->window_size) {
/* flush all currently stored data */
i = (qtm->o_end - qtm->o_ptr);
+ if(i <= 0)
+ break;
if (qtm->wflag && (ret = mspack_write(qtm->ofd, qtm->o_ptr, i, qtm->file)) != CL_SUCCESS) {
return qtm->error = ret;
}
@@ -1961,7 +1963,7 @@ int qtm_decompress(struct qtm_stream *qtm, off_t out_bytes) {
} /* while (more bytes needed) */
- if (out_bytes) {
+ if (out_bytes > 0) {
i = (int) out_bytes;
if (qtm->wflag && (ret = mspack_write(qtm->ofd, qtm->o_ptr, i, qtm->file)) != CL_SUCCESS) {
return qtm->error = ret;
diff --git a/libclamav/nsis/nulsft.c b/libclamav/nsis/nulsft.c
index 96561b7..3bab9bf 100644
--- a/libclamav/nsis/nulsft.c
+++ b/libclamav/nsis/nulsft.c
@@ -518,7 +518,7 @@ int cli_scannulsft(int desc, cli_ctx *ctx, off_t offset) {
cli_dbgmsg("NSIS: Successully extracted file #%u\n", nsist.fno);
lseek(nsist.ofd, 0, SEEK_SET);
if(nsist.fno == 1)
- ret=cli_scandesc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR);
+ ret=cli_scandesc(nsist.ofd, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
else
ret=cli_magic_scandesc(nsist.ofd, ctx);
close(nsist.ofd);
diff --git a/libclamav/others.c b/libclamav/others.c
index 3637fe3..45b28eb 100644
--- a/libclamav/others.c
+++ b/libclamav/others.c
@@ -248,6 +248,8 @@ const char *cl_strerror(int clerror)
return "CL_EFORMAT: Bad format or broken data";
case CL_EBYTECODE:
return "CL_EBYTECODE: error during bytecode execution";
+ case CL_EBYTECODE_TESTFAIL:
+ return "CL_EBYTECODE_TESTFAIL: failure in bytecode testmode";
default:
return "Unknown error code";
}
@@ -301,6 +303,7 @@ struct cl_engine *cl_engine_new(void)
new->bytecode_security = CL_BYTECODE_TRUST_SIGNED;
/* 5 seconds timeout */
new->bytecode_timeout = 60000;
+ new->bytecode_mode = CL_BYTECODE_MODE_AUTO;
new->refcount = 1;
new->ac_only = 0;
new->ac_mindepth = CLI_DEFAULT_AC_MINDEPTH;
@@ -394,11 +397,25 @@ int cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field field, long
return CL_EARG;
}
#endif
+ if (engine->dboptions & CL_DB_COMPILED) {
+ cli_errmsg("cl_engine_set_num: CL_ENGINE_BYTECODE_SECURITY cannot be set after engine was compiled\n");
+ return CL_EARG;
+ }
engine->bytecode_security = num;
break;
case CL_ENGINE_BYTECODE_TIMEOUT:
engine->bytecode_timeout = num;
break;
+ case CL_ENGINE_BYTECODE_MODE:
+ if (engine->dboptions & CL_DB_COMPILED) {
+ cli_errmsg("cl_engine_set_num: CL_ENGINE_BYTECODE_MODE cannot be set after engine was compiled\n");
+ return CL_EARG;
+ }
+ if (num == CL_BYTECODE_MODE_OFF) {
+ cli_errmsg("cl_engine_set_num: CL_BYTECODE_MODE_OFF is not settable, use dboptions to turn off!\n");
+ }
+ engine->bytecode_mode = num;
+ break;
default:
cli_errmsg("cl_engine_set_num: Incorrect field number\n");
return CL_EARG;
@@ -446,6 +463,12 @@ long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field
return engine->ac_maxdepth;
case CL_ENGINE_KEEPTMP:
return engine->keeptmp;
+ case CL_ENGINE_BYTECODE_SECURITY:
+ return engine->bytecode_security;
+ case CL_ENGINE_BYTECODE_TIMEOUT:
+ return engine->bytecode_timeout;
+ case CL_ENGINE_BYTECODE_MODE:
+ return engine->bytecode_mode;
default:
cli_errmsg("cl_engine_get: Incorrect field number\n");
if(err)
@@ -945,6 +968,10 @@ bitset_t *cli_bitset_init(void)
}
bs->length = BITSET_DEFAULT_SIZE;
bs->bitset = cli_calloc(BITSET_DEFAULT_SIZE, 1);
+ if (!bs->bitset) {
+ free(bs);
+ return NULL;
+ }
return bs;
}
@@ -1004,3 +1031,16 @@ int cli_bitset_test(bitset_t *bs, unsigned long bit_offset)
}
return (bs->bitset[char_offset] & ((unsigned char)1 << bit_offset));
}
+
+void cl_engine_set_clcb_pre_scan(struct cl_engine *engine, clcb_pre_scan callback) {
+ engine->cb_pre_scan = callback;
+}
+
+void cl_engine_set_clcb_post_scan(struct cl_engine *engine, clcb_post_scan callback) {
+ engine->cb_post_scan = callback;
+}
+
+void cl_engine_set_clcb_sigload(struct cl_engine *engine, clcb_sigload callback, void *context) {
+ engine->cb_sigload = callback;
+ engine->cb_sigload_ctx = callback ? context : NULL;
+}
diff --git a/libclamav/others.h b/libclamav/others.h
index f775477..19b55ca 100644
--- a/libclamav/others.h
+++ b/libclamav/others.h
@@ -53,7 +53,7 @@
* in re-enabling affected modules.
*/
-#define CL_FLEVEL 53
+#define CL_FLEVEL 54
#define CL_FLEVEL_DCONF CL_FLEVEL
#define CL_FLEVEL_SIGTOOL CL_FLEVEL
@@ -76,7 +76,7 @@ extern uint8_t cli_debug_flag;
((bb_size) > 0 && (sb_size) >= 0 && (size_t)(sb_size) <= (size_t)(bb_size) \
&& (sb) >= (bb) && ((sb) + (sb_size)) <= ((bb) + (bb_size)) && ((sb) + (sb_size)) >= (bb) && (sb) < ((bb) + (bb_size)))
-#define CLI_MAX_ALLOCATION 184549376
+#define CLI_MAX_ALLOCATION (182*1024*1024)
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* for NAME_MAX */
@@ -109,6 +109,8 @@ typedef struct bitset_tag
/* internal clamav context */
typedef struct cli_ctx_tag {
const char **virname;
+ char *virhash;
+ unsigned int *virsize;
unsigned long int *scanned;
const struct cli_matcher *root;
const struct cl_engine *engine;
@@ -117,11 +119,13 @@ typedef struct cli_ctx_tag {
unsigned int recursion;
unsigned int scannedfiles;
unsigned int found_possibly_unwanted;
+ unsigned int corrupted_input;
cli_file_t container_type; /* FIXME: to be made into a stack or array - see bb#1579 & bb#1293 */
size_t container_size;
struct cli_dconf *dconf;
fmap_t **fmap;
bitset_t* hook_lsig_matches;
+ void *cb_ctx;
#ifdef HAVE__INTERNAL__SHA_COLLECT
char entry_filename[2048];
int sha_collect;
@@ -246,6 +250,12 @@ struct cl_engine {
/* Used for memory pools */
mpool_t *mempool;
+ /* Callback(s) */
+ clcb_pre_scan cb_pre_scan;
+ clcb_post_scan cb_post_scan;
+ clcb_sigload cb_sigload;
+ void *cb_sigload_ctx;
+
/* Used for bytecode */
struct cli_all_bc bcs;
unsigned *hooks[_BC_LAST_HOOK - _BC_START_HOOKS];
@@ -253,6 +263,7 @@ struct cl_engine {
unsigned hook_lsig_ids;
enum bytecode_security bytecode_security;
uint32_t bytecode_timeout;
+ enum bytecode_mode bytecode_mode;
};
struct cl_settings {
@@ -331,6 +342,10 @@ union unaligned_16 {
int16_t una_s16;
} __attribute__((packed));
+struct unaligned_ptr {
+ void *ptr;
+} __attribute__((packed));
+
#ifdef HAVE_PRAGMA_PACK
#pragma pack()
#endif
diff --git a/libclamav/others_common.c b/libclamav/others_common.c
index 68a95e7..7314a3f 100644
--- a/libclamav/others_common.c
+++ b/libclamav/others_common.c
@@ -144,8 +144,9 @@ void *cli_calloc(size_t nmemb, size_t size)
void *alloc;
- if(!size || size > CLI_MAX_ALLOCATION) {
- cli_errmsg("cli_calloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) size);
+ if(!nmemb || !size || size > CLI_MAX_ALLOCATION || nmemb > CLI_MAX_ALLOCATION
+ || (nmemb*size > CLI_MAX_ALLOCATION)) {
+ cli_errmsg("cli_calloc(): Attempt to allocate %lu bytes. Please report to http://bugs.clamav.net\n", (unsigned long int) nmemb*size);
return NULL;
}
@@ -687,14 +688,24 @@ static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb
err = errno;
#endif
closedir(dd);
+ ret = CL_SUCCESS;
if (err) {
char errs[128];
cli_errmsg("Unable to readdir() directory %s: %s\n", dirname,
cli_strerror(errno, errs, sizeof(errs)));
/* report error to callback using error_stat */
ret = callback(NULL, NULL, dirname, error_stat, data);
- if (ret != CL_SUCCESS)
+ if (ret != CL_SUCCESS) {
+ if (entries) {
+ for (i=0;i<entries_cnt;i++) {
+ struct dirent_data *entry = &entries[i];
+ free(entry->filename);
+ free(entry->statbuf);
+ }
+ free(entries);
+ }
return ret;
+ }
}
if (entries) {
@@ -712,6 +723,7 @@ static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb
for (i++;i<entries_cnt;i++) {
struct dirent_data *entry = &entries[i];
free(entry->filename);
+ free(entry->statbuf);
}
free(entries);
}
diff --git a/libclamav/pdf.c b/libclamav/pdf.c
index e359da7..6d3574b 100644
--- a/libclamav/pdf.c
+++ b/libclamav/pdf.c
@@ -1,7 +1,9 @@
/*
- * Copyright (C) 2007-2008 Sourcefire, Inc.
+ * Copyright (C) 2007-2008, 2010 Sourcefire, Inc.
*
- * Authors: Nigel Horne
+ * Authors: Nigel Horne, Török Edvin
+ *
+ * Also based on Matt Olney's pdf parser in snort-nrt.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,18 +50,1085 @@ static char const rcsid[] = "$Id: pdf.c,v 1.61 2007/02/12 20:46:09 njh Exp $";
#include "scanners.h"
#include "fmap.h"
#include "str.h"
+#include "bytecode.h"
+#include "bytecode_api.h"
#ifdef CL_DEBUG
/*#define SAVE_TMP
*Save the file being worked on in tmp */
#endif
-static int try_flatedecode(unsigned char *buf, off_t real_len, off_t calculated_len, int fout, cli_ctx *ctx);
-static int flatedecode(unsigned char *buf, off_t len, int fout, cli_ctx *ctx);
+static int asciihexdecode(const char *buf, off_t len, char *output);
static int ascii85decode(const char *buf, off_t len, unsigned char *output);
static const char *pdf_nextlinestart(const char *ptr, size_t len);
static const char *pdf_nextobject(const char *ptr, size_t len);
+#if 1
+static int xrefCheck(const char *xref, const char *eof)
+{
+ const char *q;
+ while (xref < eof && (*xref == ' ' || *xref == '\n' || *xref == '\r'))
+ xref++;
+ if (xref + 4 >= eof)
+ return -1;
+ if (!memcmp(xref, "xref", 4)) {
+ cli_dbgmsg("cli_pdf: found xref\n");
+ return 0;
+ }
+ /* could be xref stream */
+ for (q=xref; q+5 < eof; q++) {
+ if (!memcmp(q,"/XRef",4)) {
+ cli_dbgmsg("cli_pdf: found /XRef\n");
+ return 0;
+ }
+ }
+ return -1;
+}
+
+struct pdf_struct {
+ struct pdf_obj *objs;
+ unsigned nobjs;
+ unsigned flags;
+ const char *map;
+ off_t size;
+ off_t offset;
+ off_t startoff;
+ cli_ctx *ctx;
+ const char *dir;
+ unsigned files;
+};
+
+static const char *findNextNonWSBack(const char *q, const char *start)
+{
+ while (q > start &&
+ (*q == 0 || *q == 9 || *q == 0xa || *q == 0xc || *q == 0xd || *q == 0x20))
+ {
+ q--;
+ }
+ return q;
+}
+
+static int find_stream_bounds(const char *start, off_t bytesleft, off_t bytesleft2, off_t *stream, off_t *endstream)
+{
+ const char *q2, *q;
+ if ((q2 = cli_memstr(start, bytesleft, "stream", 6))) {
+ q2 += 6;
+ if (q2[0] == '\xd' && q2[1] == '\xa')
+ q2 += 2;
+ if (q2[0] == '\xa')
+ q2++;
+ *stream = q2 - start;
+ bytesleft2 -= q2 - start;
+ q = q2;
+ q2 = cli_memstr(q, bytesleft2, "endstream", 9);
+ if (!q2)
+ q2 = q + bytesleft2-9; /* till EOF */
+ *endstream = q2 - start;
+ if (*endstream < *stream)
+ *endstream = *stream;
+ return 1;
+ }
+ return 0;
+}
+
+static int pdf_findobj(struct pdf_struct *pdf)
+{
+ const char *start, *q, *q2, *q3, *eof;
+ struct pdf_obj *obj;
+ off_t bytesleft;
+ unsigned genid, objid;
+
+ pdf->nobjs++;
+ pdf->objs = cli_realloc2(pdf->objs, sizeof(*pdf->objs)*pdf->nobjs);
+ if (!pdf->objs) {
+ cli_warnmsg("cli_pdf: out of memory parsing objects (%u)\n", pdf->nobjs);
+ return -1;
+ }
+ obj = &pdf->objs[pdf->nobjs-1];
+ memset(obj, 0, sizeof(*obj));
+ start = pdf->map+pdf->offset;
+ bytesleft = pdf->size - pdf->offset;
+ q2 = cli_memstr(start, bytesleft, " obj", 4);
+ if (!q2)
+ return 0;/* no more objs */
+ bytesleft -= q2 - start;
+ q = findNextNonWSBack(q2-1, start);
+ while (q > start && isdigit(*q)) { q--; }
+ genid = atoi(q);
+ q = findNextNonWSBack(q-1,start);
+ while (q > start && isdigit(*q)) { q--; }
+ objid = atoi(q);
+ obj->id = (objid << 8) | (genid&0xff);
+ obj->start = q2+4 - pdf->map;
+ obj->flags = 0;
+ bytesleft -= 4;
+ eof = pdf->map + pdf->size;
+ q = pdf->map + obj->start;
+ while (q < eof && bytesleft > 0) {
+ off_t p_stream, p_endstream;
+ q2 = pdf_nextobject(q, bytesleft);
+ if (!q2)
+ q2 = pdf->map + pdf->size;
+ bytesleft -= q2 - q;
+ if (find_stream_bounds(q-1, q2-q, bytesleft + (q2-q), &p_stream, &p_endstream)) {
+ obj->flags |= 1 << OBJ_STREAM;
+ q2 = q-1 + p_endstream + 9;
+ bytesleft -= q2 - q + 1;
+ if (bytesleft < 0) {
+ obj->flags |= 1 << OBJ_TRUNCATED;
+ pdf->offset = pdf->size;
+ return 1;/* truncated */
+ }
+ } else if ((q3 = cli_memstr(q-1, q2-q+1, "endobj", 6))) {
+ q2 = q3 + 6;
+ pdf->offset = q2 - pdf->map;
+ return 1; /* obj found and offset positioned */
+ } else {
+ q2++;
+ bytesleft--;
+ }
+ q = q2;
+ }
+ obj->flags |= 1 << OBJ_TRUNCATED;
+ pdf->offset = pdf->size;
+ return 1;/* truncated */
+}
+
+static int filter_writen(struct pdf_struct *pdf, struct pdf_obj *obj,
+ int fout, const char *buf, off_t len, off_t *sum)
+{
+ if (cli_checklimits("pdf", pdf->ctx, *sum, 0, 0))
+ return len; /* pretend it was a successful write to suppress CL_EWRITE */
+ *sum += len;
+ return cli_writen(fout, buf, len);
+}
+
+static void pdfobj_flag(struct pdf_struct *pdf, struct pdf_obj *obj, enum pdf_flag flag)
+{
+ const char *s= "";
+ pdf->flags |= 1 << flag;
+ if (!cli_debug_flag)
+ return;
+ switch (flag) {
+ case UNTERMINATED_OBJ_DICT:
+ s = "dictionary not terminated";
+ break;
+ case ESCAPED_COMMON_PDFNAME:
+ /* like /JavaScript */
+ s = "escaped common pdfname";
+ break;
+ case BAD_STREAM_FILTERS:
+ s = "duplicate stream filters";
+ break;
+ case BAD_PDF_VERSION:
+ s = "bad pdf version";
+ break;
+ case BAD_PDF_HEADERPOS:
+ s = "bad pdf header position";
+ break;
+ case BAD_PDF_TRAILER:
+ s = "bad pdf trailer";
+ break;
+ case BAD_PDF_TOOMANYOBJS:
+ s = "too many pdf objs";
+ break;
+ case BAD_FLATE:
+ s = "bad deflate stream";
+ break;
+ case BAD_FLATESTART:
+ s = "bad deflate stream start";
+ break;
+ case BAD_STREAMSTART:
+ s = "bad stream start";
+ break;
+ case UNKNOWN_FILTER:
+ s = "unknown filter used";
+ break;
+ case BAD_ASCIIDECODE:
+ s = "bad ASCII decode";
+ break;
+ case HEX_JAVASCRIPT:
+ s = "hex javascript";
+ break;
+ case BAD_INDOBJ:
+ s = "referencing nonexistent obj";
+ break;
+ case HAS_OPENACTION:
+ s = "has /OpenAction";
+ break;
+ case BAD_STREAMLEN:
+ s = "bad /Length, too small";
+ break;
+ case ENCRYPTED_PDF:
+ s = "PDF is encrypted";
+ break;
+ case LINEARIZED_PDF:
+ s = "linearized PDF";
+ break;
+ case MANY_FILTERS:
+ s = "more than 2 filters per obj";
+ break;
+ }
+ cli_dbgmsg("cli_pdf: %s flagged in object %u %u\n", s, obj->id>>8, obj->id&0xff);
+}
+
+static int filter_flatedecode(struct pdf_struct *pdf, struct pdf_obj *obj,
+ const char *buf, off_t len, int fout, off_t *sum)
+{
+ int skipped = 0;
+ int zstat;
+ z_stream stream;
+ off_t nbytes;
+ char output[BUFSIZ];
+
+ if (len == 0)
+ return CL_CLEAN;
+
+ if (*buf == '\r') {
+ buf++;
+ len--;
+ pdfobj_flag(pdf, obj, BAD_STREAMSTART);
+ /* PDF spec says stream is followed by \r\n or \n, but not \r alone.
+ * Sample 0015315109, it has \r followed by zlib header.
+ * Flag pdf as suspicious, and attempt to extract by skipping the \r.
+ */
+ if (!len)
+ return CL_CLEAN;
+ }
+
+ memset(&stream, 0, sizeof(stream));
+ stream.next_in = (Bytef *)buf;
+ stream.avail_in = len;
+ stream.next_out = (Bytef *)output;
+ stream.avail_out = sizeof(output);
+
+ zstat = inflateInit(&stream);
+ if(zstat != Z_OK) {
+ cli_warnmsg("cli_pdf: inflateInit failed\n");
+ return CL_EMEM;
+ }
+
+ nbytes = 0;
+ while(stream.avail_in) {
+ int written;
+ zstat = inflate(&stream, Z_NO_FLUSH); /* zlib */
+ switch(zstat) {
+ case Z_OK:
+ if(stream.avail_out == 0) {
+ if ((written=filter_writen(pdf, obj, fout, output, sizeof(output), sum))!=sizeof(output)) {
+ cli_errmsg("cli_pdf: failed to write output file\n");
+ inflateEnd(&stream);
+ return CL_EWRITE;
+ }
+ nbytes += written;
+ stream.next_out = (Bytef *)output;
+ stream.avail_out = sizeof(output);
+ }
+ continue;
+ case Z_STREAM_END:
+ default:
+ written = sizeof(output) - stream.avail_out;
+ if (!written && !nbytes && !skipped) {
+ /* skip till EOL, and try inflating from there, sometimes
+ * PDFs contain extra whitespace */
+ const char *q = pdf_nextlinestart(buf, len);
+ if (q) {
+ skipped = 1;
+ buf = q;
+ inflateEnd(&stream);
+ len -= q - buf;
+ stream.next_in = (Bytef *)buf;
+ stream.avail_in = len;
+ stream.next_out = (Bytef *)output;
+ stream.avail_out = sizeof(output);
+ zstat = inflateInit(&stream);
+ if(zstat != Z_OK) {
+ cli_warnmsg("cli_pdf: inflateInit failed\n");
+ return CL_EMEM;
+ }
+ pdfobj_flag(pdf, obj, BAD_FLATESTART);
+ continue;
+ }
+ }
+
+ if (filter_writen(pdf, obj, fout, output, written, sum)!=written) {
+ cli_errmsg("cli_pdf: failed to write output file\n");
+ inflateEnd(&stream);
+ return CL_EWRITE;
+ }
+ nbytes += written;
+ stream.next_out = (Bytef *)output;
+ stream.avail_out = sizeof(output);
+ if (zstat == Z_STREAM_END)
+ break;
+
+ if(stream.msg)
+ cli_dbgmsg("cli_pdf: after writing %lu bytes, got error \"%s\" inflating PDF stream in %u %u obj\n",
+ (unsigned long)nbytes,
+ stream.msg, obj->id>>8, obj->id&0xff);
+ else
+ cli_dbgmsg("cli_pdf: after writing %lu bytes, got error %d inflating PDF stream in %u %u obj\n",
+ (unsigned long)nbytes, zstat, obj->id>>8, obj->id&0xff);
+ /* mark stream as bad only if not encrypted */
+ inflateEnd(&stream);
+ if (!nbytes) {
+ cli_dbgmsg("cli_pdf: dumping raw stream (probably encrypted)\n");
+ if (filter_writen(pdf, obj, fout, buf, len, sum) != len) {
+ cli_errmsg("cli_pdf: failed to write output file\n");
+ return CL_EWRITE;
+ }
+ pdfobj_flag(pdf, obj, BAD_FLATESTART);
+ } else {
+ pdfobj_flag(pdf, obj, BAD_FLATE);
+ }
+ return CL_CLEAN;
+ }
+ break;
+ }
+
+ if(stream.avail_out != sizeof(output)) {
+ if(filter_writen(pdf, obj, fout, output, sizeof(output) - stream.avail_out, sum) < 0) {
+ cli_errmsg("cli_pdf: failed to write output file\n");
+ inflateEnd(&stream);
+ return CL_EWRITE;
+ }
+ }
+
+ inflateEnd(&stream);
+ return CL_CLEAN;
+}
+
+static struct pdf_obj *find_obj(struct pdf_struct *pdf,
+ struct pdf_obj *obj, uint32_t objid)
+{
+ unsigned j;
+ unsigned i;
+
+ /* search starting at previous obj (if exists) */
+ if (obj != pdf->objs)
+ i = obj - pdf->objs;
+ else
+ i = 0;
+ for (j=i;j<pdf->nobjs;j++) {
+ obj = &pdf->objs[j];
+ if (obj->id == objid)
+ return obj;
+ }
+ /* restart search from beginning if not found */
+ for (j=0;j<i;j++) {
+ obj = &pdf->objs[j];
+ if (obj->id == objid)
+ return obj;
+ }
+ return NULL;
+}
+
+static int find_length(struct pdf_struct *pdf,
+ struct pdf_obj *obj,
+ const char *start, off_t len)
+{
+ int length;
+ const char *q;
+ q = cli_memstr(start, len, "/Length", 7);
+ if (!q)
+ return 0;
+ q++;
+ len -= q - start;
+ start = pdf_nextobject(q, len);
+ if (!start)
+ return 0;
+ /* len -= start - q; */
+ q = start;
+ length = atoi(q);
+ while (isdigit(*q)) q++;
+ if (*q == ' ') {
+ int genid;
+ q++;
+ genid = atoi(q);
+ while(isdigit(*q)) q++;
+ if (q[0] == ' ' && q[1] == 'R') {
+ cli_dbgmsg("cli_pdf: length is in indirect object %u %u\n", length, genid);
+ obj = find_obj(pdf, obj, (length << 8) | (genid&0xff));
+ if (!obj) {
+ cli_dbgmsg("cli_pdf: indirect object not found\n");
+ return 0;
+ }
+ q = pdf_nextobject(pdf->map+obj->start, pdf->size - obj->start);
+ length = atoi(q);
+ }
+ }
+ /* limit length */
+ if (start - pdf->map + length+5 > pdf->size) {
+ length = pdf->size - (start - pdf->map)-5;
+ }
+ return length;
+}
+
+#define DUMP_MASK ((1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_A85) | (1 << OBJ_EMBEDDED_FILE) | (1 << OBJ_JAVASCRIPT) | (1 << OBJ_OPENACTION))
+
+static int obj_size(struct pdf_struct *pdf, struct pdf_obj *obj, int binary)
+{
+ unsigned i = obj - pdf->objs;
+ i++;
+ if (i < pdf->nobjs) {
+ int s = pdf->objs[i].start - obj->start - 4;
+ if (s > 0) {
+ if (!binary) {
+ const char *p = pdf->map + obj->start;
+ const char *q = p + s;
+ while (q > p && (isspace(*q) || isdigit(*q)))
+ q--;
+ if (q > p+5 && !memcmp(q-5,"endobj",6))
+ q -= 6;
+ q = findNextNonWSBack(q, p);
+ q++;
+ return q - p;
+ }
+ return s;
+ }
+ }
+ if (binary)
+ return pdf->size - obj->start;
+ return pdf->offset - obj->start - 6;
+}
+
+static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd,
+ int dumpid)
+{
+ int ret;
+ struct cli_bc_ctx *bc_ctx;
+ cli_ctx *ctx = pdf->ctx;
+ fmap_t *map;
+
+ bc_ctx = cli_bytecode_context_alloc();
+ if (!bc_ctx) {
+ cli_errmsg("cli_pdf: can't allocate memory for bc_ctx");
+ return CL_EMEM;
+ }
+
+ map = *ctx->fmap;
+ if (fd != -1) {
+ map = fmap(fd, 0, 0);
+ if (!map) {
+ cli_warnmsg("can't mmap pdf extracted obj\n");
+ map = *ctx->fmap;
+ fd = -1;
+ }
+ }
+ cli_bytecode_context_setpdf(bc_ctx, phase, pdf->nobjs, pdf->objs,
+ &pdf->flags, pdf->size, pdf->startoff);
+ cli_bytecode_context_setctx(bc_ctx, ctx);
+ ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PDF, map, ctx->virname);
+ cli_bytecode_context_destroy(bc_ctx);
+ if (fd != -1) {
+ funmap(map);
+ }
+ return ret;
+}
+
+static int pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj)
+{
+ char fullname[NAME_MAX + 1];
+ int fout;
+ off_t sum = 0;
+ int rc = CL_SUCCESS;
+ char *ascii_decoded = NULL;
+ int dump = 1;
+
+ /* TODO: call bytecode hook here, allow override dumpability */
+ if ((!(obj->flags & (1 << OBJ_STREAM)) ||
+ (obj->flags & (1 << OBJ_HASFILTERS)))
+ && !(obj->flags & DUMP_MASK)) {
+ /* don't dump all streams */
+ dump = 0;
+ }
+ if ((obj->flags & (1 << OBJ_IMAGE)) &&
+ !(obj->flags & (1 << OBJ_FILTER_DCT))) {
+ /* don't dump / scan non-JPG images */
+ dump = 0;
+ }
+ if (obj->flags & (1 << OBJ_FORCEDUMP)) {
+ /* bytecode can force dump by setting this flag */
+ dump = 1;
+ }
+ if (!dump)
+ return CL_CLEAN;
+ cli_dbgmsg("cli_pdf: dumping obj %u %u\n", obj->id>>8, obj->id);
+ snprintf(fullname, sizeof(fullname), "%s"PATHSEP"pdf%02u", pdf->dir, pdf->files++);
+ fout = open(fullname,O_RDWR|O_CREAT|O_EXCL|O_TRUNC|O_BINARY, 0600);
+ if (fout < 0) {
+ char err[128];
+ cli_errmsg("cli_pdf: can't create temporary file %s: %s\n", fullname, cli_strerror(errno, err, sizeof(err)));
+ free(ascii_decoded);
+ return CL_ETMPFILE;
+ }
+
+ do {
+ if (obj->flags & (1 << OBJ_STREAM)) {
+ const char *start = pdf->map + obj->start;
+ off_t p_stream = 0, p_endstream = 0;
+ off_t length;
+ find_stream_bounds(start, pdf->size - obj->start,
+ pdf->size - obj->start,
+ &p_stream, &p_endstream);
+ if (p_stream && p_endstream) {
+ const char *flate_in;
+ long ascii_decoded_size = 0;
+ size_t size = p_endstream - p_stream;
+ off_t orig_length;
+
+ length = find_length(pdf, obj, start, p_stream);
+ if (length < 0)
+ length = 0;
+ orig_length = length;
+ if (length > pdf->size || obj->start + p_stream + length > pdf->size) {
+ cli_dbgmsg("cli_pdf: length out of file: %ld + %ld > %ld\n",
+ p_stream, length, pdf->size);
+ length = pdf->size - (obj->start + p_stream);
+ }
+ if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && length <= 0) {
+ const char *q = start + p_endstream;
+ length = size;
+ q--;
+ if (*q == '\n') {
+ q--;
+ length--;
+ if (*q == '\r')
+ length--;
+ } else if (*q == '\r') {
+ length--;
+ }
+ if (length < 0)
+ length = 0;
+ cli_dbgmsg("cli_pdf: calculated length %ld\n", length);
+ } else {
+ if (size > length+2) {
+ cli_dbgmsg("cli_pdf: calculated length %ld < %ld\n",
+ length, size);
+ length = size;
+ }
+ }
+ if (orig_length && size > orig_length + 20) {
+ cli_dbgmsg("cli_pdf: orig length: %ld, length: %ld, size: %ld\n",
+ orig_length, length, size);
+ pdfobj_flag(pdf, obj, BAD_STREAMLEN);
+ }
+ if (!length)
+ length = size;
+
+ if (obj->flags & (1 << OBJ_FILTER_AH)) {
+ ascii_decoded = cli_malloc(length/2 + 1);
+ if (!ascii_decoded) {
+ cli_errmsg("Cannot allocate memory for asciidecode\n");
+ rc = CL_EMEM;
+ break;
+ }
+ ascii_decoded_size = asciihexdecode(start + p_stream,
+ length,
+ ascii_decoded);
+ } else if (obj->flags & (1 << OBJ_FILTER_A85)) {
+ ascii_decoded = cli_malloc(length*5);
+ if (!ascii_decoded) {
+ cli_errmsg("Cannot allocate memory for asciidecode\n");
+ rc = CL_EMEM;
+ break;
+ }
+ ascii_decoded_size = ascii85decode(start+p_stream,
+ length,
+ (unsigned char*)ascii_decoded);
+ }
+ if (ascii_decoded_size < 0) {
+ /* don't flag for images or truncated objs*/
+ if (!(obj->flags &
+ ((1 << OBJ_IMAGE) | (1 << OBJ_TRUNCATED))))
+ pdfobj_flag(pdf, obj, BAD_ASCIIDECODE);
+ cli_dbgmsg("cli_pdf: failed to asciidecode in %u %u obj\n", obj->id>>8,obj->id&0xff);
+ free(ascii_decoded);
+ ascii_decoded = NULL;
+ /* attempt to directly flatedecode it */
+ }
+ /* either direct or ascii-decoded input */
+ if (!ascii_decoded)
+ ascii_decoded_size = length;
+ flate_in = ascii_decoded ? ascii_decoded : start+p_stream;
+
+ if (obj->flags & (1 << OBJ_FILTER_FLATE)) {
+ cli_dbgmsg("cli_pdf: deflate len %ld (orig %ld)\n", ascii_decoded_size, (long)orig_length);
+ rc = filter_flatedecode(pdf, obj, flate_in, ascii_decoded_size, fout, &sum);
+ } else {
+ if (filter_writen(pdf, obj, fout, flate_in, ascii_decoded_size, &sum) != ascii_decoded_size)
+ rc = CL_EWRITE;
+ }
+ }
+ } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
+ const char *q2;
+ const char *q = pdf->map+obj->start;
+ /* TODO: get obj-endobj size */
+ off_t bytesleft = obj_size(pdf, obj, 0);
+ if (bytesleft < 0)
+ break;
+
+ q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
+ if (!q2)
+ break;
+ bytesleft -= q2 - q;
+ do {
+ q2++;
+ bytesleft--;
+ q = pdf_nextobject(q2, bytesleft);
+ if (!q)
+ break;
+ bytesleft -= q - q2;
+ q2 = q;
+ } while (*q == '/');
+ if (!q)
+ break;
+ if (*q == '(') {
+ if (filter_writen(pdf, obj, fout, q+1, bytesleft-1, &sum) != (bytesleft-1)) {
+ rc = CL_EWRITE;
+ break;
+ }
+ } else if (*q == '<') {
+ char *decoded;
+ q2 = memchr(q+1, '>', bytesleft);
+ if (!q2) q2 = q + bytesleft;
+ decoded = cli_malloc(q2 - q);
+ if (!decoded) {
+ rc = CL_EMEM;
+ break;
+ }
+ cli_hex2str_to(q2, decoded, q2-q-1);
+ decoded[q2-q-1] = '\0';
+ cli_dbgmsg("cli_pdf: found hexadecimal encoded javascript in %u %u obj\n",
+ obj->id>>8, obj->id&0xff);
+ pdfobj_flag(pdf, obj, HEX_JAVASCRIPT);
+ filter_writen(pdf, obj, fout, decoded, q2-q-1, &sum);
+ free(decoded);
+ }
+ } else {
+ off_t bytesleft = obj_size(pdf, obj, 0);
+ if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft,&sum) != bytesleft)
+ rc = CL_EWRITE;
+ }
+ } while (0);
+ cli_dbgmsg("cli_pdf: extracted %ld bytes %u %u obj to %s\n", sum, obj->id>>8, obj->id&0xff, fullname);
+ if (sum) {
+ int rc2;
+ cli_updatelimits(pdf->ctx, sum);
+ /* TODO: invoke bytecode on this pdf obj with metainformation associated
+ * */
+ lseek(fout, 0, SEEK_SET);
+ rc2 = cli_magic_scandesc(fout, pdf->ctx);
+ if (rc2 == CL_VIRUS || rc == CL_SUCCESS)
+ rc = rc2;
+ if (rc == CL_CLEAN) {
+ rc2 = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout, obj - pdf->objs);
+ if (rc2 == CL_VIRUS)
+ rc = rc2;
+ }
+ }
+ close(fout);
+ free(ascii_decoded);
+ if (!pdf->ctx->engine->keeptmp)
+ if (cli_unlink(fullname) && rc != CL_VIRUS)
+ rc = CL_EUNLINK;
+ return rc;
+}
+
+enum objstate {
+ STATE_NONE,
+ STATE_S,
+ STATE_FILTER,
+ STATE_JAVASCRIPT,
+ STATE_OPENACTION,
+ STATE_LINEARIZED,
+ STATE_ANY /* for actions table below */
+};
+
+struct pdfname_action {
+ const char *pdfname;
+ enum pdf_objflags set_objflag;/* OBJ_DICT is noop */
+ enum objstate from_state;/* STATE_NONE is noop */
+ enum objstate to_state;
+};
+
+static struct pdfname_action pdfname_actions[] = {
+ {"ASCIIHexDecode", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER},
+ {"ASCII85Decode", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER},
+ {"A85", OBJ_FILTER_A85, STATE_FILTER, STATE_FILTER},
+ {"AHx", OBJ_FILTER_AH, STATE_FILTER, STATE_FILTER},
+ {"EmbeddedFile", OBJ_EMBEDDED_FILE, STATE_NONE, STATE_NONE},
+ {"FlateDecode", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER},
+ {"Fl", OBJ_FILTER_FLATE, STATE_FILTER, STATE_FILTER},
+ {"Image", OBJ_IMAGE, STATE_NONE, STATE_NONE},
+ {"LZWDecode", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER},
+ {"LZW", OBJ_FILTER_LZW, STATE_FILTER, STATE_FILTER},
+ {"RunLengthDecode", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER},
+ {"RL", OBJ_FILTER_RL, STATE_FILTER, STATE_FILTER},
+ {"CCITTFaxDecode", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER},
+ {"CCF", OBJ_FILTER_FAX, STATE_FILTER, STATE_FILTER},
+ {"JBIG2Decode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER},
+ {"DCTDecode", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER},
+ {"DCT", OBJ_FILTER_DCT, STATE_FILTER, STATE_FILTER},
+ {"JPXDecode", OBJ_FILTER_JPX, STATE_FILTER, STATE_FILTER},
+ {"Crypt", OBJ_FILTER_CRYPT, STATE_FILTER, STATE_NONE},
+ {"Standard", OBJ_FILTER_CRYPT, STATE_FILTER, STATE_FILTER},
+ {"Sig", OBJ_SIGNED, STATE_ANY, STATE_NONE},
+ {"V", OBJ_SIGNED, STATE_ANY, STATE_NONE},
+ {"R", OBJ_SIGNED, STATE_ANY, STATE_NONE},
+ {"Linearized", OBJ_DICT, STATE_NONE, STATE_LINEARIZED},
+ {"Filter", OBJ_HASFILTERS, STATE_ANY, STATE_FILTER},
+ {"JavaScript", OBJ_JAVASCRIPT, STATE_S, STATE_JAVASCRIPT},
+ {"Length", OBJ_DICT, STATE_FILTER, STATE_NONE},
+ {"S", OBJ_DICT, STATE_NONE, STATE_S},
+ {"Type", OBJ_DICT, STATE_NONE, STATE_NONE},
+ {"OpenAction", OBJ_OPENACTION, STATE_ANY, STATE_OPENACTION}
+};
+
+#define KNOWN_FILTERS ((1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_RL) | (1 << OBJ_FILTER_A85) | (1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_LZW) | (1 << OBJ_FILTER_FAX) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_JPX) | (1 << OBJ_FILTER_CRYPT))
+
+static void handle_pdfname(struct pdf_struct *pdf, struct pdf_obj *obj,
+ const char *pdfname, int escapes,
+ enum objstate *state)
+{
+ struct pdfname_action *act = NULL;
+ unsigned j;
+ for (j=0;j<sizeof(pdfname_actions)/sizeof(pdfname_actions[0]);j++) {
+ if (!strcmp(pdfname, pdfname_actions[j].pdfname)) {
+ act = &pdfname_actions[j];
+ break;
+ }
+ }
+ if (!act) {
+ if (*state == STATE_FILTER &&
+ !(obj->flags & (1 << OBJ_SIGNED)) &&
+ /* these are digital signature objects, filter doesn't matter,
+ * we don't need them anyway */
+ !(obj->flags & KNOWN_FILTERS)) {
+ cli_dbgmsg("cli_pdf: unknown filter %s\n", pdfname);
+ obj->flags |= 1 << OBJ_FILTER_UNKNOWN;
+ }
+ return;
+ }
+ if (escapes) {
+ /* if a commonly used PDF name is escaped that is certainly
+ suspicious. */
+ cli_dbgmsg("cli_pdf: pdfname %s is escaped\n", pdfname);
+ pdfobj_flag(pdf, obj, ESCAPED_COMMON_PDFNAME);
+ }
+ if (act->from_state == *state ||
+ act->from_state == STATE_ANY) {
+ *state = act->to_state;
+
+ if (*state == STATE_FILTER &&
+ act->set_objflag !=OBJ_DICT &&
+ (obj->flags & (1 << act->set_objflag))) {
+ cli_dbgmsg("cli_pdf: duplicate stream filter %s\n", pdfname);
+ pdfobj_flag(pdf, obj, BAD_STREAM_FILTERS);
+ }
+ obj->flags |= 1 << act->set_objflag;
+ } else {
+ /* auto-reset states */
+ switch (*state) {
+ case STATE_S:
+ *state = STATE_NONE;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
+{
+ /* enough to hold common pdf names, we don't need all the names */
+ char pdfname[64];
+ const char *q2, *q3;
+ const char *q = obj->start + pdf->map;
+ const char *dict, *start;
+ off_t dict_length;
+ off_t bytesleft = obj_size(pdf, obj, 1);
+ unsigned i, filters=0;
+ enum objstate objstate = STATE_NONE;
+
+ if (bytesleft < 0)
+ return;
+ start = q;
+ /* find start of dictionary */
+ do {
+ q2 = pdf_nextobject(q, bytesleft);
+ bytesleft -= q2 -q;
+ if (!q2 || bytesleft < 0) {
+ return;
+ }
+ q3 = memchr(q-1, '<', q2-q+1);
+ q2++;
+ bytesleft--;
+ q = q2;
+ } while (!q3 || q3[1] != '<');
+ dict = q3+2;
+ q = dict;
+ bytesleft = obj_size(pdf, obj, 1) - (q - start);
+ /* find end of dictionary */
+ do {
+ q2 = pdf_nextobject(q, bytesleft);
+ bytesleft -= q2 -q;
+ if (!q2 || bytesleft < 0) {
+ return;
+ }
+ q3 = memchr(q-1, '>', q2-q+1);
+ q2++;
+ bytesleft--;
+ q = q2;
+ } while (!q3 || q3[1] != '>');
+ obj->flags |= 1 << OBJ_DICT;
+ dict_length = q3 - dict;
+
+ /* process pdf names */
+ for (q = dict;dict_length;) {
+ int escapes = 0;
+ q2 = memchr(q, '/', dict_length);
+ if (!q2)
+ break;
+ dict_length -= q2 - q;
+ q = q2;
+ /* normalize PDF names */
+ for (i = 0;dict_length && (i < sizeof(pdfname)-1); i++) {
+ q++;
+ dict_length--;
+ if (*q == '#') {
+ cli_hex2str_to(q+1, pdfname+i, 2);
+ q += 2;
+ dict_length -= 2;
+ escapes = 1;
+ continue;
+ }
+ if (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n' ||
+ *q == '/' || *q == '>' || *q == ']' || *q == '[' || *q == '<')
+ break;
+ pdfname[i] = *q;
+ }
+ pdfname[i] = '\0';
+
+ handle_pdfname(pdf, obj, pdfname, escapes, &objstate);
+ if (objstate == STATE_LINEARIZED) {
+ pdfobj_flag(pdf, obj, LINEARIZED_PDF);
+ objstate = STATE_NONE;
+ }
+ if (objstate == STATE_JAVASCRIPT ||
+ objstate == STATE_OPENACTION) {
+ if (objstate == STATE_OPENACTION)
+ pdfobj_flag(pdf, obj, HAS_OPENACTION);
+ q2 = pdf_nextobject(q, dict_length);
+ if (q2 && isdigit(*q2)) {
+ uint32_t objid = atoi(q2) << 8;
+ while (isdigit(*q2)) q2++;
+ q2 = pdf_nextobject(q2, dict_length);
+ if (q2 && isdigit(*q2)) {
+ objid |= atoi(q2) & 0xff;
+ q2 = pdf_nextobject(q2, dict_length);
+ if (*q2 == 'R') {
+ struct pdf_obj *obj2;
+ cli_dbgmsg("cli_pdf: found %s stored in indirect object %u %u\n",
+ pdfname,
+ objid >> 8, objid&0xff);
+ obj2 = find_obj(pdf, obj, objid);
+ if (obj2) {
+ enum pdf_objflags flag = objstate == STATE_JAVASCRIPT ?
+ OBJ_JAVASCRIPT : OBJ_OPENACTION;
+ obj2->flags |= 1 << flag;
+ obj->flags &= ~(1 << flag);
+ } else {
+ pdfobj_flag(pdf, obj, BAD_INDOBJ);
+ }
+ }
+ }
+ }
+ objstate = STATE_NONE;
+ }
+ }
+ for (i=0;i<sizeof(pdfname_actions)/sizeof(pdfname_actions[0]);i++) {
+ const struct pdfname_action *act = &pdfname_actions[i];
+ if ((obj->flags & (1 << act->set_objflag)) &&
+ act->from_state == STATE_FILTER &&
+ act->to_state == STATE_FILTER &&
+ act->set_objflag != OBJ_FILTER_CRYPT) {
+ filters++;
+ }
+ }
+ if (filters > 2) { /* more than 2 non-crypt filters */
+ pdfobj_flag(pdf, obj, MANY_FILTERS);
+ }
+ if (obj->flags & ((1 << OBJ_SIGNED) | KNOWN_FILTERS))
+ obj->flags &= ~(1 << OBJ_FILTER_UNKNOWN);
+ if (obj->flags & (1 << OBJ_FILTER_UNKNOWN))
+ pdfobj_flag(pdf, obj, UNKNOWN_FILTER);
+ cli_dbgmsg("cli_pdf: %u %u obj flags: %02x\n", obj->id>>8, obj->id&0xff, obj->flags);
+}
+
+int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
+{
+ struct pdf_struct pdf;
+ fmap_t *map = *ctx->fmap;
+ size_t size = map->len - offset;
+ off_t versize = size > 1032 ? 1032 : size;
+ off_t map_off, bytesleft;
+ long xref;
+ const char *pdfver, *start, *eofmap, *q, *eof;
+ int rc;
+ unsigned i;
+
+ cli_dbgmsg("in cli_pdf(%s)\n", dir);
+ memset(&pdf, 0, sizeof(pdf));
+ pdf.ctx = ctx;
+ pdf.dir = dir;
+
+ pdfver = start = fmap_need_off_once(map, offset, versize);
+
+ /* Check PDF version */
+ if (!pdfver) {
+ cli_errmsg("cli_pdf: mmap() failed (1)\n");
+ return CL_EMAP;
+ }
+ /* offset is 0 when coming from filetype2 */
+ pdfver = cli_memstr(pdfver, versize, "%PDF-", 5);
+ if (!pdfver) {
+ cli_dbgmsg("cli_pdf: no PDF- header found\n");
+ return CL_SUCCESS;
+ }
+ /* Check for PDF-1.[0-9]. Although 1.7 is highest now, allow for future
+ * versions */
+ if (pdfver[5] != '1' || pdfver[6] != '.' ||
+ pdfver[7] < '1' || pdfver[7] > '9') {
+ pdf.flags |= 1 << BAD_PDF_VERSION;
+ cli_dbgmsg("cli_pdf: bad pdf version: %.8s\n", pdfver);
+ }
+ if (pdfver != start || offset) {
+ pdf.flags |= 1 << BAD_PDF_HEADERPOS;
+ cli_dbgmsg("cli_pdf: PDF header is not at position 0: %ld\n",pdfver-start+offset);
+ }
+ offset += pdfver - start;
+
+ /* find trailer and xref, don't fail if not found */
+ map_off = map->len - 2048;
+ if (map_off < 0)
+ map_off = 0;
+ bytesleft = map->len - map_off;
+ eofmap = fmap_need_off_once(map, map_off, bytesleft);
+ if (!eofmap) {
+ cli_errmsg("cli_pdf: mmap() failed (2)\n");
+ return CL_EMAP;
+ }
+ eof = eofmap + bytesleft;
+ for (q=&eofmap[bytesleft-5]; q > eofmap; q--) {
+ if (memcmp(q, "%%EOF", 5) == 0)
+ break;
+ }
+ if (q <= eofmap) {
+ pdf.flags |= 1 << BAD_PDF_TRAILER;
+ cli_dbgmsg("cli_pdf: %%%%EOF not found\n");
+ } else {
+ const char *t;
+ size = q - eofmap + map_off;
+ for (;q > eofmap;q--) {
+ if (memcmp(q, "startxref", 9) == 0)
+ break;
+ }
+ if (q <= eofmap) {
+ pdf.flags |= 1 << BAD_PDF_TRAILER;
+ cli_dbgmsg("cli_pdf: startxref not found\n");
+ } else {
+ for (t=q;t > eofmap; t--) {
+ if (memcmp(t,"trailer",7) == 0)
+ break;
+ }
+ if (t > eofmap) {
+ if (cli_memstr(t, q-t, "/Encrypt", 8)) {
+ pdf.flags |= 1 << ENCRYPTED_PDF;
+ cli_dbgmsg("cli_pdf: encrypted pdf found, stream will probably fail to decompress!\n");
+ }
+ }
+ q += 9;
+ while (q < eof && (*q == ' ' || *q == '\n' || *q == '\r')) { q++; }
+ xref = atol(q);
+ bytesleft = map->len - offset - xref;
+ if (bytesleft > 4096)
+ bytesleft = 4096;
+ q = fmap_need_off_once(map, offset + xref, bytesleft);
+ if (!q || xrefCheck(q, q+bytesleft) == -1) {
+ cli_dbgmsg("cli_pdf: did not find valid xref\n");
+ pdf.flags |= 1 << BAD_PDF_TRAILER;
+ }
+ }
+ }
+ size -= offset;
+
+ pdf.size = size;
+ pdf.map = fmap_need_off(map, offset, size);
+ pdf.startoff = offset;
+ if (!pdf.map) {
+ cli_errmsg("cli_pdf: mmap() failed (3)\n");
+ return CL_EMAP;
+ }
+ /* parse PDF and find obj offsets */
+ while ((rc = pdf_findobj(&pdf)) > 0) {
+ struct pdf_obj *obj = &pdf.objs[pdf.nobjs-1];
+ cli_dbgmsg("found %d %d obj @%ld\n", obj->id >> 8, obj->id&0xff, obj->start + offset);
+ }
+ if (pdf.nobjs)
+ pdf.nobjs--;
+ if (rc == -1)
+ pdf.flags |= 1 << BAD_PDF_TOOMANYOBJS;
+
+ /* must parse after finding all objs, so we can flag indirect objects */
+ for (i=0;i<pdf.nobjs;i++) {
+ struct pdf_obj *obj = &pdf.objs[i];
+ pdf_parseobj(&pdf, obj);
+ }
+
+ rc = run_pdf_hooks(&pdf, PDF_PHASE_PARSED, -1, -1);
+ /* extract PDF objs */
+ for (i=0;!rc && i<pdf.nobjs;i++) {
+ struct pdf_obj *obj = &pdf.objs[i];
+ rc = pdf_extract_obj(&pdf, obj);
+ }
+
+ if (pdf.flags & (1 << ENCRYPTED_PDF))
+ pdf.flags &= ~ ((1 << BAD_FLATESTART) | (1 << BAD_STREAMSTART) |
+ (1 << BAD_ASCIIDECODE));
+
+ if (pdf.flags && !rc) {
+ cli_dbgmsg("cli_pdf: flags 0x%02x\n", pdf.flags);
+ rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1, -1);
+ if (!rc && (ctx->options & CL_SCAN_ALGORITHMIC)) {
+ if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
+ /* for example /Fl#61te#44#65#63#6f#64#65 instead of /FlateDecode */
+ *ctx->virname = "Heuristics.PDF.ObfuscatedNameObject";
+ rc = cli_found_possibly_unwanted(ctx);
+ }
+ }
+#if 0
+ /* TODO: find both trailers, and /Encrypt settings */
+ if (pdf.flags & (1 << LINEARIZED_PDF))
+ pdf.flags &= ~ (1 << BAD_ASCIIDECODE);
+ if (pdf.flags & (1 << MANY_FILTERS))
+ pdf.flags &= ~ (1 << BAD_ASCIIDECODE);
+ if (!rc && (pdf.flags &
+ ((1 << BAD_PDF_TOOMANYOBJS) | (1 << BAD_STREAM_FILTERS) |
+ (1<<BAD_FLATE) | (1<<BAD_ASCIIDECODE)|
+ (1<<UNTERMINATED_OBJ_DICT) | (1<<UNKNOWN_FILTER)))) {
+ rc = CL_EUNPACK;
+ }
+#endif
+ }
+ cli_dbgmsg("cli_pdf: returning %d\n", rc);
+ free(pdf.objs);
+ return rc;
+}
+
+#else
+static int try_flatedecode(unsigned char *buf, off_t real_len, off_t calculated_len, int fout, cli_ctx *ctx);
+static int flatedecode(unsigned char *buf, off_t len, int fout, cli_ctx *ctx);
int
cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
{
@@ -652,7 +1721,25 @@ flatedecode(unsigned char *buf, off_t len, int fout, cli_ctx *ctx)
inflateEnd(&stream);
return CL_CLEAN;
}
+#endif
+static int asciihexdecode(const char *buf, off_t len, char *output)
+{
+ unsigned i,j;
+ for (i=0,j=0;i+1<len;i++) {
+ if (buf[i] == ' ')
+ continue;
+ if (buf[i] == '>')
+ break;
+ if (cli_hex2str_to(buf+i, output+j++, 2) == -1) {
+ if (len - i < 4)
+ continue;
+ return -1;
+ }
+ i++;
+ }
+ return j;
+}
/*
* ascii85 inflation, returns number of bytes in output, -1 for error
*
@@ -717,9 +1804,7 @@ ascii85decode(const char *buf, off_t len, unsigned char *output)
ret += quintet;
for(i = 0; i < quintet - 1; i++)
*output++ = (unsigned char)((sum >> (24 - 8 * i)) & 0xFF);
- quintet = 0;
}
- len = 0;
break;
} else if(!isspace(byte)) {
cli_dbgmsg("ascii85Decode: invalid character 0x%x, len %lu\n",
@@ -784,6 +1869,8 @@ pdf_nextobject(const char *ptr, size_t len)
break;
case '/': /* Start of a name object */
return ptr;
+ case '(': /* start of JS */
+ return ptr;
default:
if(!inobject)
/* TODO: parse and return object type */
diff --git a/libclamav/pdf.h b/libclamav/pdf.h
index 99fdaf9..233738c 100644
--- a/libclamav/pdf.h
+++ b/libclamav/pdf.h
@@ -21,6 +21,11 @@
#define __PDF_H
#include "others.h"
+struct pdf_obj {
+ uint32_t start;
+ uint32_t id;
+ uint32_t flags;
+};
int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset);
diff --git a/libclamav/pe.c b/libclamav/pe.c
index 1caaf9e..1bf2477 100644
--- a/libclamav/pe.c
+++ b/libclamav/pe.c
@@ -54,11 +54,10 @@
#include "mew.h"
#include "upack.h"
#include "matcher.h"
-#include "matcher-bm.h"
+#include "matcher-md5.h"
#include "disasm.h"
#include "special.h"
#include "ishield.h"
-#include "pe_icons.h"
#define DCONF ctx->dconf->pe
@@ -190,6 +189,8 @@ FSGSTUFF; \
#define CLI_UNPRESULTSFSG1(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,free(sections)),EXPR,GOOD,FREEME)
#define CLI_UNPRESULTSFSG2(NAME,EXPR,GOOD,FREEME) CLI_UNPRESULTS_(NAME,FSGCASE(NAME,(void)0),EXPR,GOOD,FREEME)
+#define DETECT_BROKEN_PE (DETECT_BROKEN && !ctx->corrupted_input)
+
struct offset_list {
uint32_t offset;
struct offset_list *next;
@@ -499,7 +500,7 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc
fmap_unneed_ptr(map, oentry, entries*8);
}
-int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
+int cli_scanpe(cli_ctx *ctx)
{
uint16_t e_magic; /* DOS signature ("MZ") */
uint16_t nsections;
@@ -552,7 +553,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
if(fmap_readn(map, &e_lfanew, 58 + sizeof(e_magic), sizeof(e_lfanew)) != sizeof(e_lfanew)) {
cli_dbgmsg("Can't read new header address\n");
/* truncated header? */
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -682,15 +683,17 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
nsections = EC16(file_hdr.NumberOfSections);
if(nsections < 1 || nsections > 96) {
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
}
- if(nsections)
- cli_warnmsg("PE file contains %d sections\n", nsections);
- else
- cli_warnmsg("PE file contains no sections\n");
+ if(!ctx->corrupted_input) {
+ if(nsections)
+ cli_warnmsg("PE file contains %d sections\n", nsections);
+ else
+ cli_warnmsg("PE file contains no sections\n");
+ }
return CL_CLEAN;
}
cli_dbgmsg("NumberOfSections: %d\n", nsections);
@@ -702,7 +705,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
if (EC16(file_hdr.SizeOfOptionalHeader) < sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("SizeOfOptionalHeader too small\n");
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -713,7 +716,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
at = e_lfanew + sizeof(struct pe_image_file_hdr);
if(fmap_readn(map, &optional_hdr32, at, sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("Can't read optional file header\n");
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -727,7 +730,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
if(EC16(file_hdr.SizeOfOptionalHeader)!=sizeof(struct pe_image_optional_hdr64)) {
/* FIXME: need to play around a bit more with xp64 */
cli_dbgmsg("Incorrect SizeOfOptionalHeader for PE32+\n");
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -742,8 +745,9 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
either way it's a 32bit thingy
*/
if(EC16(optional_hdr32.Magic) != PE32_SIGNATURE) {
- cli_warnmsg("Incorrect magic number in optional header\n");
- if(DETECT_BROKEN) {
+ if(!ctx->corrupted_input)
+ cli_warnmsg("Incorrect magic number in optional header\n");
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -785,7 +789,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
/* read the remaining part of the header */
if(fmap_readn(map, &optional_hdr32 + 1, at, sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) != sizeof(struct pe_image_optional_hdr64) - sizeof(struct pe_image_optional_hdr32)) {
cli_dbgmsg("Can't read optional file header\n");
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -865,14 +869,14 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("------------------------------------\n");
- if (DETECT_BROKEN && !native && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
+ if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment)) || (pe_plus?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment))%0x1000)) {
cli_dbgmsg("Bad virtual alignemnt\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
}
- if (DETECT_BROKEN && !native && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
+ if (DETECT_BROKEN_PE && !native && (!(pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment)) || (pe_plus?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment))%0x200)) {
cli_dbgmsg("Bad file alignemnt\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
@@ -904,7 +908,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("Possibly broken PE file\n");
free(section_hdr);
free(exe_sections);
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -971,7 +975,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("------------------------------------\n");
- if (DETECT_BROKEN && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */
+ if (DETECT_BROKEN_PE && (!valign || (exe_sections[i].urva % valign))) { /* Bad virtual alignment */
cli_dbgmsg("VirtualAddress is misaligned\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
@@ -985,7 +989,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("Broken PE file - Section %d starts beyond the end of file (Offset@ %lu, Total filesize %lu)\n", i, (unsigned long)exe_sections[i].raw, (unsigned long)fsize);
free(section_hdr);
free(exe_sections);
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -1002,9 +1006,9 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) {
if(md5_sect->soff[j] == exe_sections[i].rsz) {
unsigned char md5_dig[16];
- const struct cli_bm_patt *patt;
- if(cli_md5sect(map, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, &patt, ctx->engine->md5_mdb, 0, NULL, NULL) == CL_VIRUS && patt->filesize == exe_sections[i].rsz) {
- if(cli_bm_scanbuff(md5_dig, 16, NULL, &patt, ctx->engine->md5_fp, 0, NULL, NULL) != CL_VIRUS || patt->filesize != fsize) {
+ const struct cli_md5m_patt *patt;
+ if(cli_md5sect(map, &exe_sections[i], md5_dig) && cli_md5m_scan(md5_dig, exe_sections[i].rsz, ctx->virname, ctx->engine->md5_mdb) == CL_VIRUS) {
+ if(cli_md5m_scan(md5_dig, fsize, NULL, ctx->engine->md5_fp) != CL_VIRUS) {
free(section_hdr);
free(exe_sections);
return CL_VIRUS;
@@ -1020,7 +1024,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("Found PE values with sign bit set\n");
free(section_hdr);
free(exe_sections);
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -1029,7 +1033,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
}
if(!i) {
- if (DETECT_BROKEN && exe_sections[i].urva!=hdr_size) { /* Bad first section RVA */
+ if (DETECT_BROKEN_PE && exe_sections[i].urva!=hdr_size) { /* Bad first section RVA */
cli_dbgmsg("First section is in the wrong place\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
@@ -1040,7 +1044,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
min = exe_sections[i].rva;
max = exe_sections[i].rva + exe_sections[i].rsz;
} else {
- if (DETECT_BROKEN && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
+ if (DETECT_BROKEN_PE && exe_sections[i].urva - exe_sections[i-1].urva != exe_sections[i-1].vsz) { /* No holes, no overlapping, no virtual disorder */
cli_dbgmsg("Virtually misplaced section (wrong order, overlapping, non contiguous)\n");
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
@@ -1063,7 +1067,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
if(!(ep = cli_rawaddr(vep, exe_sections, nsections, &err, fsize, hdr_size)) && err) {
cli_dbgmsg("EntryPoint out of file\n");
free(exe_sections);
- if(DETECT_BROKEN) {
+ if(DETECT_BROKEN_PE) {
if(ctx->virname)
*ctx->virname = "Heuristics.Broken.Executable";
return CL_VIRUS;
@@ -1073,15 +1077,6 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
cli_dbgmsg("EntryPoint offset: 0x%x (%d)\n", ep, ep);
- if(iconset){
- if(!dll && dirs[2].Size && cli_scanicon(iconset, EC32(dirs[2].VirtualAddress), ctx, exe_sections, nsections, hdr_size) == CL_VIRUS) {
- free(exe_sections);
- return CL_VIRUS;
- }
- free(exe_sections);
- return CL_CLEAN;
- }
-
if(pe_plus) { /* Do not continue for PE32+ files */
free(exe_sections);
return CL_CLEAN;
@@ -2270,6 +2265,7 @@ int cli_scanpe(cli_ctx *ctx, icon_groupset *iconset)
ret = cli_bytecode_runhook(ctx, ctx->engine, bc_ctx, BC_PE_UNPACKER, map, ctx->virname);
switch (ret) {
case CL_VIRUS:
+ cli_bytecode_context_destroy(bc_ctx);
return CL_VIRUS;
case CL_SUCCESS:
ndesc = cli_bytecode_context_getresult_file(bc_ctx, &tempfile);
@@ -2378,7 +2374,7 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
valign = (pe_plus)?EC32(optional_hdr64.SectionAlignment):EC32(optional_hdr32.SectionAlignment);
falign = (pe_plus)?EC32(optional_hdr64.FileAlignment):EC32(optional_hdr32.FileAlignment);
- hdr_size = PESALIGN(hdr_size, valign);
+ peinfo->hdr_size = hdr_size = PESALIGN(hdr_size, valign);
peinfo->section = (struct cli_exe_section *) cli_calloc(peinfo->nsections, sizeof(struct cli_exe_section));
@@ -2442,6 +2438,11 @@ int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo)
return -1;
}
+ if(EC16(file_hdr.Characteristics) & 0x2000 || !dirs[2].Size)
+ peinfo->res_addr = 0;
+ else
+ peinfo->res_addr = EC32(dirs[2].VirtualAddress);
+
while(dirs[2].Size && peinfo->vinfo) {
struct vinfo_list vlist;
uint8_t *vptr, *baseptr;
diff --git a/libclamav/pe.h b/libclamav/pe.h
index dc5db56..62d20ce 100644
--- a/libclamav/pe.h
+++ b/libclamav/pe.h
@@ -152,7 +152,7 @@ struct cli_pe_hook_data {
uint32_t hdr_size;/**< internally needed by rawaddr */
};
-int cli_scanpe(cli_ctx *ctx, icon_groupset *set);
+int cli_scanpe(cli_ctx *ctx);
int cli_peheader(fmap_t *map, struct cli_exe_info *peinfo);
diff --git a/libclamav/pe_icons.c b/libclamav/pe_icons.c
index 3f1bc5b..326e0b9 100644
--- a/libclamav/pe_icons.c
+++ b/libclamav/pe_icons.c
@@ -30,6 +30,7 @@
#define EC32(x) le32_to_host(x)
+#define EC16(x) le16_to_host(x)
#define USE_FLOATS
#ifdef USE_FLOATS
#define LABDIFF(x) labdiff(x)
@@ -111,8 +112,8 @@ int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct c
while(icnt && gsz >= 14) {
dir = (struct icondir *)grp;
- cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", gicons.rvas[curicon], dir->w, dir->h, dir->depth, dir->id, dir->planes, dir->palcnt, dir->rsvd, dir->sz);
- findres(3, dir->id, resdir_rva, map, exe_sections, nsections, hdr_size, icon_cb, &icons);
+ cli_dbgmsg("cli_scanicon: Icongrp @%x - %ux%ux%u - (id=%x, rsvd=%u, planes=%u, palcnt=%u, sz=%x)\n", gicons.rvas[curicon], dir->w, dir->h, cli_readint16(&dir->depth), cli_readint16(&dir->id), cli_readint16(&dir->planes), dir->palcnt, dir->rsvd, cli_readint32(&dir->sz));
+ findres(3, cli_readint16(&dir->id), resdir_rva, map, exe_sections, nsections, hdr_size, icon_cb, &icons);
grp += 14;
gsz -= 14;
}
@@ -1230,7 +1231,7 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
width = EC32(bmphdr.w);
height = EC32(bmphdr.h) / 2;
- depth = EC32(bmphdr.depth);
+ depth = EC16(bmphdr.depth);
if(width > 256 || height > 256 || width < 16 || height < 16) {
cli_dbgmsg("parseicon: Image too small or too big (%ux%u)\n", width, height);
return CL_SUCCESS;
@@ -1306,7 +1307,7 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
have = 8;
}
have -= depth;
- imagedata[(height - 1 - y) * width + x] = palette[(c >> have) & ((1<<depth)-1)];
+ imagedata[(height - 1 - y) * width + x] = EC32(palette[(c >> have) & ((1<<depth)-1)]);
}
break;
}
@@ -1503,13 +1504,6 @@ static int parseicon(icon_groupset *set, uint32_t rva, cli_ctx *ctx, struct cli_
return CL_SUCCESS;
}
-
-int cli_match_icon(icon_groupset *set, cli_ctx *ctx) {
- if(!ctx || !ctx->engine || !ctx->engine->iconcheck || !ctx->engine->iconcheck->group_counts[0] || !ctx->engine->iconcheck->group_counts[1])
- return CL_CLEAN;
- return cli_scanpe(ctx, set);
-}
-
void cli_icongroupset_add(const char *groupname, icon_groupset *set, unsigned int type, cli_ctx *ctx) {
struct icon_matcher *matcher;
unsigned int i, j;
diff --git a/libclamav/pe_icons.h b/libclamav/pe_icons.h
index 5e6e3ee..46c9a25 100644
--- a/libclamav/pe_icons.h
+++ b/libclamav/pe_icons.h
@@ -23,7 +23,6 @@
#include "pe.h"
int cli_scanicon(icon_groupset *set, uint32_t resdir_rva, cli_ctx *ctx, struct cli_exe_section *exe_sections, uint16_t nsections, uint32_t hdr_size);
-int cli_match_icon(icon_groupset *set, cli_ctx *ctx);
void cli_icongroupset_add(const char *groupname, icon_groupset *set, unsigned int type, cli_ctx *ctx);
static inline void cli_icongroupset_init(icon_groupset *set) {
diff --git a/libclamav/phishcheck.c b/libclamav/phishcheck.c
index 583d743..30e7865 100644
--- a/libclamav/phishcheck.c
+++ b/libclamav/phishcheck.c
@@ -1000,6 +1000,7 @@ static int isURL(char* URL, int accept_anyproto)
{
char *last_tld_end = NULL, *q;
const char *start = NULL, *p, *end;
+ int has_proto = 0;
if(!URL)
return 0;
@@ -1035,6 +1036,7 @@ static int isURL(char* URL, int accept_anyproto)
start++;
} else
start++;
+ has_proto = 1;
}
else
start = URL; /* scheme invalid */
@@ -1044,6 +1046,16 @@ static int isURL(char* URL, int accept_anyproto)
end = strchr(p, '/');
if (!end)
end = p + strlen(p);
+
+ if (!has_proto && (q = memchr(p, '@', end-p))) {
+ /* don't phishcheck if displayed URL is email, but do phishcheck if
+ * foo.TLD at host is used */
+ const char *q2 = q-1;
+ while (q2 > p && *q2 != '.') q2--;
+ if (q2 == p || !in_tld_set(q2+1, q-q2-1))
+ return 0;
+ }
+
do {
q = strchr(p, '.');
if (q > end)
diff --git a/libclamav/readdb.c b/libclamav/readdb.c
index 9ce9e67..9be421b 100644
--- a/libclamav/readdb.c
+++ b/libclamav/readdb.c
@@ -46,6 +46,7 @@
#endif
#include "matcher-ac.h"
#include "matcher-bm.h"
+#include "matcher-md5.h"
#include "matcher.h"
#include "others.h"
#include "str.h"
@@ -549,6 +550,11 @@ static int cli_loaddb(FILE *fs, struct cl_engine *engine, unsigned int *signo, u
if(engine->ignored && cli_chkign(engine->ignored, start, buffer_cpy))
continue;
+ if(engine->cb_sigload && engine->cb_sigload("db", start, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loaddb: skipping %s due to callback\n", start);
+ continue;
+ }
+
if(*pt == '=') continue;
if((ret = cli_parse_add(root, start, pt, 0, 0, "*", 0, NULL, options))) {
@@ -593,8 +599,10 @@ static int cli_loadidb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
return CL_EMEM;
if(engine->ignored)
- if(!(buffer_cpy = cli_malloc(FILEBUFF)))
+ if(!(buffer_cpy = cli_malloc(FILEBUFF))) {
+ mpool_free(engine->mempool, matcher);
return CL_EMEM;
+ }
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
@@ -621,6 +629,11 @@ static int cli_loadidb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
if(engine->ignored && cli_chkign(engine->ignored, tokens[0], buffer_cpy))
continue;
+ if(engine->cb_sigload && engine->cb_sigload("idb", tokens[0], engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadidb: skipping %s due to callback\n", tokens[0]);
+ continue;
+ }
+
hash = (uint8_t *)tokens[3];
if(cli_hexnibbles((char *)hash, 124)) {
cli_errmsg("cli_loadidb: Malformed hash at line %u (bad chars)\n", line);
@@ -890,6 +903,11 @@ static int cli_loadndb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
if(engine->ignored && cli_chkign(engine->ignored, virname, buffer_cpy))
continue;
+ if(engine->cb_sigload && engine->cb_sigload("ndb", virname, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadndb: skipping %s due to callback\n", virname);
+ continue;
+ }
+
if(tokens_count > 4) { /* min version */
pt = tokens[4];
@@ -1193,6 +1211,11 @@ static int load_oneldb(char *buffer, int chkpua, int chkign, struct cl_engine *e
if (chkign && cli_chkign(engine->ignored, virname, buffer_cpy))
return CL_SUCCESS;
+ if(engine->cb_sigload && engine->cb_sigload("ldb", virname, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadldb: skipping %s due to callback\n", virname);
+ return CL_SUCCESS;
+ }
+
subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, NULL, 1);
if(subsigs == -1) {
return CL_EMALFDB;
@@ -1384,6 +1407,7 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
struct cli_bc *bc;
unsigned sigs = 0;
unsigned security_trust = 0;
+ unsigned i;
/* TODO: virusname have a common prefix, and whitelist by that */
@@ -1425,6 +1449,7 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
while (cli_dbgets(buf, sizeof(buf), fs, dbio)) {}
if (rc != CL_SUCCESS) {
+ cli_bytecode_destroy(bc);
cli_errmsg("Unable to load %s bytecode: %s\n", dbname, cl_strerror(rc));
return rc;
}
@@ -1473,6 +1498,20 @@ static int cli_loadcbc(FILE *fs, struct cl_engine *engine, unsigned int *signo,
}
engine->hooks[hook][cnt-1] = bcs->count-1;
} else switch (bc->kind) {
+ case BC_STARTUP:
+ for (i=0;i<bcs->count-1;i++)
+ if (bcs->all_bcs[i].kind == BC_STARTUP) {
+ struct cli_bc *bc0 = &bcs->all_bcs[i];
+ cli_errmsg("Can only load 1 BC_STARTUP bytecode, attempted to load 2nd!\n");
+ cli_warnmsg("Previous BC_STARTUP: %d %d by %s\n",
+ bc0->id, (uint32_t)bc0->metadata.timestamp,
+ bc0->metadata.sigmaker ? bc0->metadata.sigmaker : "N/A");
+ cli_warnmsg("Conflicting BC_STARTUP: %d %d by %s\n",
+ bc->id, (uint32_t)bc->metadata.timestamp,
+ bc->metadata.sigmaker ? bc->metadata.sigmaker : "N/A");
+ return CL_EMALFDB;
+ }
+ break;
default:
cli_errmsg("Bytecode: unhandled bytecode kind %u\n", bc->kind);
return CL_EMALFDB;
@@ -1829,8 +1868,8 @@ static int cli_md5db_init(struct cl_engine *engine, unsigned int mode)
#ifdef USE_MPOOL
bm->mempool = engine->mempool;
#endif
- if((ret = cli_bm_init(bm))) {
- cli_errmsg("cli_md5db_init: Failed to initialize B-M\n");
+ if((ret = cli_md5m_init(bm))) {
+ cli_errmsg("cli_md5db_init: Failed to initialize MD5 matcher\n");
return ret;
}
@@ -1851,9 +1890,10 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo,
const char *tokens[MD5_TOKENS + 1];
char buffer[FILEBUFF], *buffer_cpy = NULL;
const char *pt;
+ unsigned char *md5;
int ret = CL_SUCCESS;
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count;
- struct cli_bm_patt *new;
+ struct cli_md5m_patt *new;
struct cli_matcher *db = NULL;
@@ -1891,26 +1931,31 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo,
if(engine->ignored && cli_chkign(engine->ignored, pt, buffer_cpy))
continue;
- new = (struct cli_bm_patt *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_bm_patt));
+ if(engine->cb_sigload && engine->cb_sigload("md5", pt, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadmd5: skipping %s due to callback\n", pt);
+ continue;
+ }
+
+ new = (struct cli_md5m_patt *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_md5m_patt));
if(!new) {
ret = CL_EMEM;
break;
}
pt = tokens[md5_field]; /* md5 */
- if(strlen(pt) != 32 || !(new->pattern = (unsigned char *) cli_mpool_hex2str(engine->mempool, pt))) {
+ if(strlen(pt) != 32 || !(md5 = (unsigned char *) cli_mpool_hex2str(engine->mempool, pt))) {
cli_errmsg("cli_loadmd5: Malformed MD5 string at line %u\n", line);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
}
- new->length = 16;
+ memcpy(new->md5, md5, 16);
+ mpool_free(engine->mempool, md5);
new->filesize = atoi(tokens[size_field]);
new->virname = cli_mpool_virname(engine->mempool, tokens[2], options & CL_DB_OFFICIAL);
if(!new->virname) {
- mpool_free(engine->mempool, new->pattern);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
@@ -1918,7 +1963,6 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo,
MD5_DB;
if(!db && (ret = cli_md5db_init(engine, mode))) {
- mpool_free(engine->mempool, new->pattern);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
break;
@@ -1926,9 +1970,8 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo,
MD5_DB;
}
- if((ret = cli_bm_addpatt(db, new, "0"))) {
+ if((ret = cli_md5m_addpatt(db, new))) {
cli_errmsg("cli_loadmd5: Error adding BM pattern\n");
- mpool_free(engine->mempool, new->pattern);
mpool_free(engine->mempool, new->virname);
mpool_free(engine->mempool, new);
break;
@@ -2042,6 +2085,13 @@ static int cli_loadmd(FILE *fs, struct cl_engine *engine, unsigned int *signo, i
continue;
}
+ if(engine->cb_sigload && engine->cb_sigload("md", new->virname, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadmd: skipping %s due to callback\n", new->virname);
+ mpool_free(engine->mempool, new->virname);
+ mpool_free(engine->mempool, new);
+ continue;
+ }
+
new->encrypted = strcmp(tokens[1], "*") ? atoi(tokens[1]) : 2;
if(strcmp(tokens[2], "*") && cli_regcomp(&new->name, tokens[2], REG_EXTENDED | REG_NOSUB)) {
@@ -2175,6 +2225,13 @@ static int cli_loadcdb(FILE *fs, struct cl_engine *engine, unsigned int *signo,
continue;
}
+ if(engine->cb_sigload && engine->cb_sigload("cdb", new->virname, engine->cb_sigload_ctx)) {
+ cli_dbgmsg("cli_loadcdb: skipping %s due to callback\n", new->virname);
+ mpool_free(engine->mempool, new->virname);
+ mpool_free(engine->mempool, new);
+ continue;
+ }
+
if(!strcmp(tokens[1], "*")) {
new->ctype = CL_TYPE_ANY;
} else if((new->ctype = cli_ftcode(tokens[1])) == CL_TYPE_ERROR) {
@@ -2594,8 +2651,8 @@ int cl_load(const char *path, struct cl_engine *engine, unsigned int *signo, uns
if((ret = phishing_init(engine)))
return ret;
- if((dboptions & CL_DB_BYTECODE) && !engine->bcs.engine && (engine->dconf->bytecode & BYTECODE_ENGINE_MASK)) {
- if((ret = cli_bytecode_init(&engine->bcs, engine->dconf->bytecode)))
+ if((dboptions & CL_DB_BYTECODE) && !engine->bcs.inited) {
+ if((ret = cli_bytecode_init(&engine->bcs)))
return ret;
} else {
cli_dbgmsg("Bytecode engine disabled\n");
@@ -2871,12 +2928,12 @@ int cl_engine_free(struct cl_engine *engine)
}
if((root = engine->md5_hdb)) {
- cli_bm_free(root);
+ cli_md5m_free(root);
mpool_free(engine->mempool, root);
}
if((root = engine->md5_mdb)) {
- cli_bm_free(root);
+ cli_md5m_free(root);
mpool_free(engine->mempool, root->soff);
if(root->md5_sizes_hs.capacity) {
cli_hashset_destroy(&root->md5_sizes_hs);
@@ -2885,7 +2942,7 @@ int cl_engine_free(struct cl_engine *engine)
}
if((root = engine->md5_fp)) {
- cli_bm_free(root);
+ cli_md5m_free(root);
mpool_free(engine->mempool, root);
}
@@ -2931,7 +2988,10 @@ int cl_engine_free(struct cl_engine *engine)
struct icon_matcher *iconcheck = engine->iconcheck;
for(i=0; i<3; i++) {
if(iconcheck->icons[i]) {
- mpool_free(engine->mempool, iconcheck->icons[i]->name);
+ for (j=0;j<iconcheck->icon_counts[i];j++) {
+ struct icomtr* metric = iconcheck->icons[i];
+ mpool_free(engine->mempool, metric[j].name);
+ }
mpool_free(engine->mempool, iconcheck->icons[i]);
}
}
@@ -3008,9 +3068,14 @@ int cl_engine_compile(struct cl_engine *engine)
if((root = engine->root[i])) {
if((ret = cli_ac_buildtrie(root)))
return ret;
- cli_dbgmsg("matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : "");
+ cli_dbgmsg("Matcher[%u]: %s: AC sigs: %u (reloff: %u, absoff: %u) BM sigs: %u (reloff: %u, absoff: %u) maxpatlen %u %s\n", i, cli_mtargets[i].name, root->ac_patterns, root->ac_reloff_num, root->ac_absoff_num, root->bm_patterns, root->bm_reloff_num, root->bm_absoff_num, root->maxpatlen, root->ac_only ? "(ac_only mode)" : "");
}
}
+ if(engine->md5_hdb)
+ cli_dbgmsg("MD5 sigs (files): %u\n", engine->md5_hdb->md5_patterns);
+
+ if(engine->md5_mdb)
+ cli_dbgmsg("MD5 sigs (PE sections): %u\n", engine->md5_mdb->md5_patterns);
if((ret = cli_build_regex_list(engine->whitelist_matcher))) {
return ret;
@@ -3028,7 +3093,7 @@ int cl_engine_compile(struct cl_engine *engine)
mpool_flush(engine->mempool);
/* Compile bytecode */
- if((ret = cli_bytecode_prepare(&engine->bcs, engine->dconf->bytecode))) {
+ if((ret = cli_bytecode_prepare2(engine, &engine->bcs, engine->dconf->bytecode))) {
cli_errmsg("Unable to compile/load bytecode: %s\n", cl_strerror(ret));
return ret;
}
diff --git a/libclamav/regex_list.h b/libclamav/regex_list.h
index de1841d..bc7a977 100644
--- a/libclamav/regex_list.h
+++ b/libclamav/regex_list.h
@@ -28,6 +28,7 @@
#include "readdb.h"
#include "matcher.h"
#include "filtering.h"
+#include "hashtab.h"
#include <zlib.h> /* for gzFile */
#include "mpool.h"
diff --git a/libclamav/scanners.c b/libclamav/scanners.c
index ef41184..fa21862 100644
--- a/libclamav/scanners.c
+++ b/libclamav/scanners.c
@@ -185,7 +185,7 @@ static int cli_unrar_scanmetadata(int desc, unrar_metadata_t *metadata, cli_ctx
if(DETECT_ENCRYPTED && metadata->encrypted) {
cli_dbgmsg("RAR: Encrypted files found in archive.\n");
lseek(desc, 0, SEEK_SET);
- ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
if(ret != CL_VIRUS) {
*ctx->virname = "Heuristics.Encrypted.RAR";
return CL_VIRUS;
@@ -227,7 +227,7 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
cli_dbgmsg("RAR: Encrypted main header\n");
if(DETECT_ENCRYPTED) {
lseek(desc, 0, SEEK_SET);
- ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(desc, ctx, 0, 0, NULL, AC_SCAN_VIR, NULL);
if(ret != CL_VIRUS)
*ctx->virname = "Heuristics.Encrypted.RAR";
return CL_VIRUS;
@@ -705,6 +705,7 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
unsigned int files = 0;
struct cab_archive cab;
struct cab_file *file;
+ unsigned int corrupted_input;
cli_dbgmsg("in cli_scanmscab()\n");
@@ -740,13 +741,16 @@ static int cli_scanmscab(int desc, cli_ctx *ctx, off_t sfx_offset)
if((ret = cab_extract(file, tempname))) {
cli_dbgmsg("CAB: Failed to extract file: %s\n", cl_strerror(ret));
} else {
- if(file->length != file->written_size)
+ corrupted_input = ctx->corrupted_input;
+ if(file->length != file->written_size) {
cli_dbgmsg("CAB: Length from header %u but wrote %u bytes\n", (unsigned int) file->length, (unsigned int) file->written_size);
-
+ ctx->corrupted_input = 1;
+ }
ret = cli_scanfile(tempname, ctx);
+ ctx->corrupted_input = corrupted_input;
}
if(!ctx->engine->keeptmp) {
- if (cli_unlink(tempname)) {
+ if (!access(tempname, R_OK) && cli_unlink(tempname)) {
free(tempname);
ret = CL_EUNLINK;
break;
@@ -976,7 +980,7 @@ static int cli_scanhtml(cli_ctx *ctx)
snprintf(fullname, 1024, "%s"PATHSEP"nocomment.html", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if (fd >= 0) {
- ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
close(fd);
}
@@ -986,7 +990,7 @@ static int cli_scanhtml(cli_ctx *ctx)
snprintf(fullname, 1024, "%s"PATHSEP"notags.html", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if(fd >= 0) {
- ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
close(fd);
}
}
@@ -995,10 +999,10 @@ static int cli_scanhtml(cli_ctx *ctx)
snprintf(fullname, 1024, "%s"PATHSEP"javascript", tempname);
fd = open(fullname, O_RDONLY|O_BINARY);
if(fd >= 0) {
- ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, ctx, CL_TYPE_HTML, 0, NULL, AC_SCAN_VIR, NULL);
if (ret == CL_CLEAN) {
lseek(fd, 0, SEEK_SET);
- ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(fd, ctx, CL_TYPE_TEXT_ASCII, 0, NULL, AC_SCAN_VIR, NULL);
}
close(fd);
}
@@ -1103,9 +1107,9 @@ static int cli_scanscript(cli_ctx *ctx)
}
free(normalized);
if(ret != CL_VIRUS) {
- ret = cli_lsig_eval(ctx, troot, &tmdata);
+ ret = cli_lsig_eval(ctx, troot, &tmdata, NULL);
if(ret != CL_VIRUS)
- ret = cli_lsig_eval(ctx, groot, &gmdata);
+ ret = cli_lsig_eval(ctx, groot, &gmdata, NULL);
}
cli_ac_freedata(&tmdata);
cli_ac_freedata(&gmdata);
@@ -1625,12 +1629,13 @@ static int cli_scan_structured(int desc, cli_ctx *ctx)
return CL_CLEAN;
}
-static int cli_scanembpe(int desc, cli_ctx *ctx)
+static int cli_scanembpe(cli_ctx *ctx, off_t offset)
{
int fd, bytes, ret = CL_CLEAN;
- unsigned long int size = 0;
- char buff[512];
+ unsigned long int size = 0, todo;
+ char *buff;
char *tmpname;
+ fmap_t *map = *ctx->fmap;
tmpname = cli_gentemp(ctx->engine->tmpdir);
if(!tmpname)
@@ -1642,10 +1647,27 @@ static int cli_scanembpe(int desc, cli_ctx *ctx)
return CL_ECREAT;
}
- while((bytes = read(desc, buff, sizeof(buff))) > 0) {
+ todo = map->len - offset;
+ while(1) {
+ bytes = MIN(todo, map->pgsz);
+ if(!bytes)
+ break;
+
+ if(!(buff = fmap_need_off_once(map, offset + size, bytes))) {
+ close(fd);
+ if(!ctx->engine->keeptmp) {
+ if (cli_unlink(tmpname)) {
+ free(tmpname);
+ return CL_EUNLINK;
+ }
+ }
+ free(tmpname);
+ return CL_EREAD;
+ }
size += bytes;
+ todo -= bytes;
- if(cli_checklimits("cli_scanembpe", ctx, size + sizeof(buff), 0, 0)!=CL_CLEAN)
+ if(cli_checklimits("cli_scanembpe", ctx, size, 0, 0)!=CL_CLEAN)
break;
if(cli_writen(fd, buff, bytes) != bytes) {
@@ -1657,7 +1679,7 @@ static int cli_scanembpe(int desc, cli_ctx *ctx)
return CL_EUNLINK;
}
}
- free(tmpname);
+ free(tmpname);
return CL_EWRITE;
}
}
@@ -1709,7 +1731,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
if(typercg)
acmode |= AC_SCAN_FT;
- ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, refhash);
+ ret = cli_fmap_scandesc(ctx, type == CL_TYPE_TEXT_ASCII ? 0 : type, 0, &ftoffset, acmode, NULL, refhash);
if(ret >= CL_TYPENO) {
ctx->recursion++;
@@ -1778,7 +1800,7 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
ctx->container_type = CL_TYPE_AUTOIT;
ctx->container_size = map->len - fpt->offset; /* not precise */
cli_dbgmsg("AUTOIT signature found at %u\n", (unsigned int) fpt->offset);
- nret = cli_scanautoit(map->fd, ctx, fpt->offset + 23);
+ nret = cli_scanautoit(ctx, fpt->offset + 23);
}
break;
@@ -1808,14 +1830,12 @@ static int cli_scanraw(cli_ctx *ctx, cli_file_t type, uint8_t typercg, cli_file_
ctx->container_size = map->len - fpt->offset; /* not precise */
memset(&peinfo, 0, sizeof(struct cli_exe_info));
peinfo.offset = fpt->offset;
- lseek(map->fd, fpt->offset, SEEK_SET);
if(cli_peheader(map, &peinfo) == 0) {
cli_dbgmsg("*** Detected embedded PE file at %u ***\n", (unsigned int) fpt->offset);
if(peinfo.section)
free(peinfo.section);
- lseek(map->fd, fpt->offset, SEEK_SET);
- nret = cli_scanembpe(map->fd, ctx);
+ nret = cli_scanembpe(ctx, fpt->offset);
break_loop = 1; /* we can stop here and other
* embedded executables will
* be found recursively
@@ -1890,9 +1910,25 @@ static void emax_reached(cli_ctx *ctx) {
#define LINESTR(x) #x
#define LINESTR2(x) LINESTR(x)
#define __AT__ " at line "LINESTR2(__LINE__)
-#define ret_from_magicscan(retcode) do { \
- cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \
- return retcode; \
+#define ret_from_magicscan(retcode) do { \
+ cli_dbgmsg("cli_magic_scandesc: returning %d %s\n", retcode, __AT__); \
+ if(ctx->engine->cb_post_scan) { \
+ switch(ctx->engine->cb_post_scan(desc, retcode, retcode == CL_VIRUS && ctx->virname ? *ctx->virname : NULL, ctx->cb_ctx)) { \
+ case CL_BREAK: \
+ cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n"); \
+ return CL_CLEAN; \
+ case CL_VIRUS: \
+ cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n"); \
+ if(ctx->virname) \
+ *ctx->virname = "Detected.By.Callback"; \
+ return CL_VIRUS; \
+ case CL_CLEAN: \
+ break; \
+ default: \
+ cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n"); \
+ } \
+ } \
+ return retcode; \
} while(0)
int cli_magic_scandesc(int desc, cli_ctx *ctx)
@@ -1949,6 +1985,27 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
ret_from_magicscan(CL_EMEM);
}
+ if(ctx->engine->cb_pre_scan) {
+ switch(ctx->engine->cb_pre_scan(desc, ctx->cb_ctx)) {
+ case CL_BREAK:
+ cli_dbgmsg("cli_magic_scandesc: file whitelisted by callback\n");
+ funmap(*ctx->fmap);
+ ctx->fmap--;
+ ret_from_magicscan(CL_CLEAN);
+ case CL_VIRUS:
+ cli_dbgmsg("cli_magic_scandesc: file blacklisted by callback\n");
+ if(ctx->virname)
+ *ctx->virname = "Detected.By.Callback";
+ funmap(*ctx->fmap);
+ ctx->fmap--;
+ ret_from_magicscan(CL_VIRUS);
+ case CL_CLEAN:
+ break;
+ default:
+ cli_warnmsg("cli_magic_scandesc: ignoring bad return code from callback\n");
+ }
+ }
+
if(cache_check(hash, ctx) == CL_CLEAN) {
funmap(*ctx->fmap);
ctx->fmap--;
@@ -1964,7 +2021,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
else
cli_dbgmsg("Raw mode: No support for special files\n");
- if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, hash)) == CL_VIRUS)
+ if((ret = cli_fmap_scandesc(ctx, 0, 0, NULL, AC_SCAN_VIR, NULL, hash)) == CL_VIRUS)
cli_dbgmsg("%s found in descriptor %d\n", *ctx->virname, desc);
else if(ret == CL_CLEAN) {
if(ctx->recursion != ctx->engine->maxreclevel)
@@ -1996,6 +2053,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
ctx->hook_lsig_matches = cli_bitset_init();
if (!ctx->hook_lsig_matches) {
ctx->hook_lsig_matches = old_hook_lsig_matches;
+ ctx->fmap--;
ret_from_magicscan(CL_EMEM);
}
@@ -2058,7 +2116,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
ctx->container_type = CL_TYPE_AUTOIT;
ctx->container_size = sb.st_size;
if(SCAN_ARCHIVE && (DCONF_ARCH & ARCH_CONF_AUTOIT))
- ret = cli_scanautoit(desc, ctx, 23);
+ ret = cli_scanautoit(ctx, 23);
break;
case CL_TYPE_MSSZDD:
@@ -2290,7 +2348,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
ret = cli_scanscript(ctx);
if(ret != CL_VIRUS && ctx->container_type == CL_TYPE_MAIL) {
lseek(desc, 0, SEEK_SET);
- ret = cli_scandesc(desc, ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR);
+ ret = cli_scandesc(desc, ctx, CL_TYPE_MAIL, 0, NULL, AC_SCAN_VIR, NULL);
}
break;
/* Due to performance reasons all executables were first scanned
@@ -2298,7 +2356,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
*/
case CL_TYPE_MSEXE:
if(SCAN_PE && ctx->dconf->pe)
- ret = cli_scanpe(ctx, NULL);
+ ret = cli_scanpe(ctx);
break;
default:
break;
@@ -2326,8 +2384,65 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx)
}
}
+int cli_scandesc_stats(int desc, const char **virname, char *virhash, unsigned int *virsize, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
+{
+ cli_ctx ctx;
+ int rc;
+
+ memset(&ctx, '\0', sizeof(cli_ctx));
+ ctx.engine = engine;
+ ctx.virname = virname;
+ if(virsize) {
+ *virsize = 0;
+ ctx.virsize = virsize;
+ ctx.virhash = virhash;
+ }
+ ctx.scanned = scanned;
+ ctx.options = scanoptions;
+ ctx.found_possibly_unwanted = 0;
+ ctx.container_type = CL_TYPE_ANY;
+ ctx.container_size = 0;
+ ctx.dconf = (struct cli_dconf *) engine->dconf;
+ ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
+ if(!ctx.fmap)
+ return CL_EMEM;
+ if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
+ free(ctx.fmap);
+ return CL_EMEM;
+ }
+
+#ifdef HAVE__INTERNAL__SHA_COLLECT
+ if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
+ char link[32];
+ ssize_t linksz;
+
+ snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
+ link[sizeof(link)-1]='\0';
+ if((linksz=readlink(link, ctx.entry_filename, sizeof(ctx.entry_filename)))==-1) {
+ cli_errmsg("failed to resolve filename for descriptor %d (%s)\n", desc, link);
+ strcpy(ctx.entry_filename, "NO_IDEA");
+ } else
+ ctx.entry_filename[linksz]='\0';
+ } while(0);
+#endif
+
+ rc = cli_magic_scandesc(desc, &ctx);
+
+ cli_bitset_free(ctx.hook_lsig_matches);
+ free(ctx.fmap);
+ if(rc == CL_CLEAN && ctx.found_possibly_unwanted)
+ rc = CL_VIRUS;
+ return rc;
+}
+
int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
{
+ return cli_scandesc_stats(desc, virname, NULL, NULL, scanned, engine, scanoptions);
+}
+
+
+int cl_scandesc_callback(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions, void *context)
+{
cli_ctx ctx;
int rc;
@@ -2340,10 +2455,14 @@ int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, cons
ctx.container_type = CL_TYPE_ANY;
ctx.container_size = 0;
ctx.dconf = (struct cli_dconf *) engine->dconf;
+ ctx.cb_ctx = context;
ctx.fmap = cli_calloc(sizeof(fmap_t *), ctx.engine->maxreclevel + 2);
if(!ctx.fmap)
return CL_EMEM;
- ctx.hook_lsig_matches = cli_bitset_init();
+ if (!(ctx.hook_lsig_matches = cli_bitset_init())) {
+ free(ctx.fmap);
+ return CL_EMEM;
+ }
#ifdef HAVE__INTERNAL__SHA_COLLECT
if(scanoptions & CL_SCAN_INTERNAL_COLLECT_SHA) {
@@ -2418,6 +2537,19 @@ int cl_scanfile(const char *filename, const char **virname, unsigned long int *s
return ret;
}
+int cli_scanfile_stats(const char *filename, const char **virname, char *virhash, unsigned int *virsize, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions)
+{
+ int fd, ret;
+
+ if((fd = safe_open(filename, O_RDONLY|O_BINARY)) == -1)
+ return CL_EOPEN;
+
+ ret = cli_scandesc_stats(fd, virname, virhash, virsize, scanned, engine, scanoptions);
+ close(fd);
+
+ return ret;
+}
+
/*
Local Variables:
c-basic-offset: 4
diff --git a/libclamav/scanners.h b/libclamav/scanners.h
index e5bfa68..fe3ae03 100644
--- a/libclamav/scanners.h
+++ b/libclamav/scanners.h
@@ -26,5 +26,7 @@
int cli_magic_scandesc(int desc, cli_ctx *ctx);
int cli_found_possibly_unwanted(cli_ctx* ctx);
+int cli_scandesc_stats(int desc, const char **virname, char *virhash, unsigned int *virsize, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
+int cli_scanfile_stats(const char *filename, const char **virname, char *virhash, unsigned int *virsize, unsigned long int *scanned, const struct cl_engine *engine, unsigned int scanoptions);
#endif
diff --git a/libclamav/sha256.c b/libclamav/sha256.c
index 5d661d1..21a4620 100644
--- a/libclamav/sha256.c
+++ b/libclamav/sha256.c
@@ -249,7 +249,7 @@ SHA256Guts (SHA256_CTX *sc, const uint32_t *cbuf)
W = buf;
#ifndef SHA256_UNROLL
-#define SHA256_UNROLL 1
+#define SHA256_UNROLL 4
#endif /* !SHA256_UNROLL */
#if SHA256_UNROLL == 1
@@ -324,7 +324,6 @@ sha256_update (SHA256_CTX *sc, const void *vdata, uint32_t len)
uint32_t bufferBytesLeft;
uint32_t bytesToCopy;
int needBurn = 0;
-
#ifdef SHA256_FAST_COPY
if (sc->bufferLength) {
bufferBytesLeft = 64L - sc->bufferLength;
diff --git a/libclamav/special.c b/libclamav/special.c
index ac72f55..d9f50c0 100644
--- a/libclamav/special.c
+++ b/libclamav/special.c
@@ -272,6 +272,9 @@ static int riff_read_chunk(int fd, int big_endian, int rec_level)
}
chunk_size = riff_endian_convert_32(chunk_size, big_endian);
+ if(!memcmp(&chunk_id, "anih", 4) && chunk_size != 36)
+ return 2;
+
if (memcmp(&chunk_id, "RIFF", 4) == 0) {
return 0;
} else if (memcmp(&chunk_id, "RIFX", 4) == 0) {
@@ -345,12 +348,7 @@ int cli_check_riff_exploit(int fd)
do {
retval = riff_read_chunk(fd, big_endian, 1);
} while (retval == 1);
-
- offset = lseek(fd, 0, SEEK_CUR);
- if (offset < (int64_t)chunk_size) {
- retval = 2;
- }
return retval;
}
diff --git a/libclamav/str.c b/libclamav/str.c
index ae1b981..6033b1f 100644
--- a/libclamav/str.c
+++ b/libclamav/str.c
@@ -456,8 +456,8 @@ size_t cli_strtokenize(char *buffer, const char delim, const size_t token_count,
int cli_isnumber(const char *str)
{
- while(*str++)
- if(!strchr("0123456789", *str))
+ while(*str)
+ if(!strchr("0123456789", *str++))
return 0;
return 1;
diff --git a/libclamav/vba_extract.c b/libclamav/vba_extract.c
index b77046f..062ec20 100644
--- a/libclamav/vba_extract.c
+++ b/libclamav/vba_extract.c
@@ -290,7 +290,7 @@ cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which)
j = vba_read_project_strings(fd, FALSE);
if(!i && !j) {
close(fd);
- cli_warnmsg("vba_readdir: Unable to guess VBA type\n");
+ cli_dbgmsg("vba_readdir: Unable to guess VBA type\n");
return NULL;
}
if (i > j) {
diff --git a/m4/acinclude.m4 b/m4/acinclude.m4
index c8aa878..58d3d67 100644
--- a/m4/acinclude.m4
+++ b/m4/acinclude.m4
@@ -641,6 +641,9 @@ AC_TRY_RUN([
#define BZ2_bzReadOpen bzReadOpen
#define BZ2_bzReadClose bzReadClose
#define BZ2_bzRead bzRead
+#define BZ2_bzDecompressInit bzDecompressInit
+#define BZ2_bzDecompress bzDecompress
+#define BZ2_bzDecompressEnd bzDecompressEnd
#endif
const unsigned char poc[] = {
diff --git a/m4/mmap_private.m4 b/m4/mmap_private.m4
index 1050864..551f75a 100644
--- a/m4/mmap_private.m4
+++ b/m4/mmap_private.m4
@@ -80,7 +80,7 @@ AC_DEFUN([AC_C_FUNC_MMAP_ANONYMOUS],
[
AC_CACHE_CHECK([for MAP_ANON(YMOUS)], [ac_cv_c_mmap_anonymous],[
ac_cv_c_mmap_anonymous='no'
- AC_COMPILE_IFELSE(
+ AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <sys/mman.h>]], [[mmap((void *)0, 0, PROT_READ | PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);]])],
[ac_cv_c_mmap_anonymous='MAP_ANONYMOUS'],
[
diff --git a/shared/cdiff.c b/shared/cdiff.c
index 56a380d..68011a3 100644
--- a/shared/cdiff.c
+++ b/shared/cdiff.c
@@ -64,7 +64,7 @@ struct cdiff_ctx {
char *open_db;
struct cdiff_node *add_start, *add_last;
struct cdiff_node *del_start;
- struct cdiff_node *xchg_start;
+ struct cdiff_node *xchg_start, *xchg_last;
};
struct cdiff_cmd {
@@ -324,32 +324,12 @@ static int cdiff_cmd_xchg(const char *cmdstr, struct cdiff_ctx *ctx, char *lbuf,
new->str2 = arg2;
new->lineno = lineno;
- if(!ctx->xchg_start) {
-
+ if(!ctx->xchg_start)
ctx->xchg_start = new;
+ else
+ ctx->xchg_last->next = new;
- } else {
-
- if(lineno < ctx->xchg_start->lineno) {
- new->next = ctx->xchg_start;
- ctx->xchg_start = new;
-
- } else {
- pt = ctx->xchg_start;
-
- while(pt) {
- last = pt;
- if((pt->lineno < lineno) && (!pt->next || lineno < pt->next->lineno))
- break;
-
- pt = pt->next;
- }
-
- new->next = last->next;
- last->next = new;
- }
- }
-
+ ctx->xchg_last = new;
return 0;
}
diff --git a/shared/optparser.c b/shared/optparser.c
index b093821..9866ce5 100644
--- a/shared/optparser.c
+++ b/shared/optparser.c
@@ -80,7 +80,7 @@ const struct clam_option __clam_options[] = {
{ NULL, "multiscan", 'm', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
{ NULL, "fdpass", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
{ NULL, "stream", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMDSCAN, "", "" },
- { NULL, "database", 'd', TYPE_STRING, NULL, -1, DATADIR, FLAG_REQUIRED, OPT_CLAMSCAN, "", "" }, /* merge it with DatabaseDirectory (and fix conflict with --datadir */
+ { NULL, "database", 'd', TYPE_STRING, NULL, -1, DATADIR, FLAG_REQUIRED | FLAG_MULTIPLE, OPT_CLAMSCAN, "", "" }, /* merge it with DatabaseDirectory (and fix conflict with --datadir */
{ NULL, "recursive", 'r', TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", "" },
{ NULL, "bell", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", "" },
{ NULL, "no-summary", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", "" },
@@ -177,11 +177,13 @@ const struct clam_option __clam_options[] = {
{ "LogVerbose", NULL, 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Enable verbose logging.", "yes" },
+ { "ExtendedDetectionInfo", NULL, 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD, "Provide additional information about the infected file, such as its\nsize and hash, together with the virus name.", "yes" },
+
{ "PidFile", "pid", 'p', TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_MILTER, "Save the process ID to a file.", "/var/run/clam.pid" },
{ "TemporaryDirectory", "tempdir", 0, TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER | OPT_CLAMSCAN | OPT_SIGTOOL, "This option allows you to change the default temporary directory.", "/tmp" },
- { "DatabaseDirectory", "datadir", 0, TYPE_STRING, NULL, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM, "This option allows you to change the default database directory.\nIf you enable it, please make sure it points to the same directory in\nboth clamd and freshclam.", "/var/lib/clamav" },
+ { "DatabaseDirectory", "datadir", 0, TYPE_STRING, NULL, -1, DATADIR, 0, OPT_CLAMD | OPT_FRESHCLAM | OPT_SIGTOOL, "This option allows you to change the default database directory.\nIf you enable it, please make sure it points to the same directory in\nboth clamd and freshclam.", "/var/lib/clamav" },
{ "OfficialDatabaseOnly", "official-db-only", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Only load the official signatures published by the ClamAV project.", "no" },
@@ -252,6 +254,8 @@ const struct clam_option __clam_options[] = {
"Set bytecode security level.\nPossible values:\n\tNone - no security at all, meant for debugging. DO NOT USE THIS ON PRODUCTION SYSTEMS\n\tTrustSigned - trust bytecode loaded from signed .c[lv]d files,\n\t\t insert runtime safety checks for bytecode loaded from other sources\n\tParanoid - don't trust any bytecode, insert runtime checks for all\nRecommended: TrustSigned, because bytecode in .cvd files already has these checks\n","TrustSigned"},
{ "BytecodeTimeout", "bytecode-timeout", 0, TYPE_NUMBER, MATCH_NUMBER, 60000, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN,
"Set bytecode timeout in miliseconds.\n","60000"},
+ { "BytecodeMode", "bytecode-mode", 0, TYPE_STRING, "^(Auto|ForceJIT|ForceInterpreter|Test)$", -1, "Auto", FLAG_REQUIRED, OPT_CLAMD | OPT_CLAMSCAN,
+ "Set bytecode execution mode.\nPossible values:\n\tAuto - automatically choose JIT if possible, fallback to interpreter\nForceJIT - always choose JIT, fail if not possible\nForceIntepreter - always choose interpreter\nTest - run with both JIT and interpreter and compare results. Make all failures fatal\n","Auto"},
{ "DetectPUA", "detect-pua", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Detect Potentially Unwanted Applications.", "yes" },
{ "ExcludePUA", "exclude-pua", 0, TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD | OPT_CLAMSCAN, "Exclude a specific PUA category. This directive can be used multiple times.\nSee http://www.clamav.net/support/pua for the complete list of PUA\ncategories.", "NetTool\nPWTool" },
diff --git a/sigtool/sigtool.c b/sigtool/sigtool.c
index db2d9ef..71c8c93 100644
--- a/sigtool/sigtool.c
+++ b/sigtool/sigtool.c
@@ -71,12 +71,6 @@
#define MAX_DEL_LOOKAHEAD 200
-/*
- * Force backward compatibility with the cdiff interpreter of clamav < 0.95
- */
-#define COMPATIBILITY_LIMIT 980
-
-
static const struct dblist_s {
const char *name;
unsigned int count;
@@ -640,7 +634,7 @@ static int build(const struct optstruct *opts)
struct stat foo;
unsigned char buffer[FILEBUFF];
char *tarfile, header[513], smbuff[32], builder[32], *pt, olddb[512], patch[32], broken[32];
- const char *dbname, *newcvd;
+ const char *dbname, *newcvd, *localdbdir = NULL;
struct cl_engine *engine;
FILE *cvd, *fh;
gzFile *tar;
@@ -664,6 +658,9 @@ static int build(const struct optstruct *opts)
return -1;
}
+ if(optget(opts, "datadir")->active)
+ localdbdir = optget(opts, "datadir")->strarg;
+
if(stat("COPYING", &foo) == -1) {
mprintf("!build: COPYING file not found in current working directory.\n");
return -1;
@@ -768,9 +765,9 @@ static int build(const struct optstruct *opts)
} else {
pt = freshdbdir();
- snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cvd", pt, dbname);
+ snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cvd", localdbdir ? localdbdir : pt, dbname);
if(access(olddb, R_OK))
- snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cld", pt, dbname);
+ snprintf(olddb, sizeof(olddb), "%s"PATHSEP"%s.cld", localdbdir ? localdbdir : pt, dbname);
free(pt);
}
@@ -1086,15 +1083,18 @@ static int build(const struct optstruct *opts)
static int unpack(const struct optstruct *opts)
{
char name[512], *dbdir;
+ const char *localdbdir = NULL;
+ if(optget(opts, "datadir")->active)
+ localdbdir = optget(opts, "datadir")->strarg;
if(optget(opts, "unpack-current")->enabled) {
dbdir = freshdbdir();
- snprintf(name, sizeof(name), "%s"PATHSEP"%s.cvd", dbdir, optget(opts, "unpack-current")->strarg);
+ snprintf(name, sizeof(name), "%s"PATHSEP"%s.cvd", localdbdir ? localdbdir : dbdir, optget(opts, "unpack-current")->strarg);
if(access(name, R_OK)) {
- snprintf(name, sizeof(name), "%s"PATHSEP"%s.cld", dbdir, optget(opts, "unpack-current")->strarg);
+ snprintf(name, sizeof(name), "%s"PATHSEP"%s.cld", localdbdir ? localdbdir : dbdir, optget(opts, "unpack-current")->strarg);
if(access(name, R_OK)) {
- mprintf("!unpack: Couldn't find %s CLD/CVD database\n", optget(opts, "unpack-current")->strarg);
+ mprintf("!unpack: Couldn't find %s CLD/CVD database in %s\n", optget(opts, "unpack-current")->strarg, localdbdir ? localdbdir : dbdir);
free(dbdir);
return -1;
}
@@ -1366,10 +1366,15 @@ static int listsigs(const struct optstruct *opts, int mode)
char *dbdir;
struct stat sb;
regex_t reg;
+ const char *localdbdir = NULL;
+ if(optget(opts, "datadir")->active)
+ localdbdir = optget(opts, "datadir")->strarg;
if(mode == 0) {
name = optget(opts, "list-sigs")->strarg;
+ if(access(name, R_OK) && localdbdir)
+ name = localdbdir;
if(stat(name, &sb) == -1) {
mprintf("--list-sigs: Can't get status of %s\n", name);
return -1;
@@ -1379,7 +1384,7 @@ static int listsigs(const struct optstruct *opts, int mode)
if(S_ISDIR(sb.st_mode)) {
if(!strcmp(name, DATADIR)) {
dbdir = freshdbdir();
- ret = listdir(dbdir, NULL);
+ ret = listdir(localdbdir ? localdbdir : dbdir, NULL);
free(dbdir);
} else {
ret = listdir(name, NULL);
@@ -1395,7 +1400,7 @@ static int listsigs(const struct optstruct *opts, int mode)
}
mprintf_stdout = 1;
dbdir = freshdbdir();
- ret = listdir(dbdir, ®);
+ ret = listdir(localdbdir ? localdbdir : dbdir, ®);
free(dbdir);
cli_regfree(®);
}
@@ -1537,14 +1542,42 @@ static int rundiff(const struct optstruct *opts)
return ret;
}
+static int maxlinelen(const char *file)
+{
+ int fd, bytes, n = 0, nmax = 0, i;
+ char buff[512];
+
+ if((fd = open(file, O_RDONLY)) == -1) {
+ mprintf("!maxlinelen: Can't open file %s\n", file);
+ return -1;
+ }
+
+ while((bytes = read(fd, buff, 512)) > 0) {
+ for(i = 0; i < bytes; i++, ++n) {
+ if(buff[i] == '\n') {
+ if(n > nmax)
+ nmax = n;
+ n = 0;
+ }
+ }
+ }
+
+ if(bytes == -1) {
+ mprintf("!maxlinelen: Can't read file %s\n", file);
+ return -1;
+ }
+
+ return nmax;
+}
+
static int compare(const char *oldpath, const char *newpath, FILE *diff)
{
FILE *old, *new;
- char obuff[CLI_DEFAULT_LSIG_BUFSIZE + 1], nbuff[CLI_DEFAULT_LSIG_BUFSIZE + 1], tbuff[CLI_DEFAULT_LSIG_BUFSIZE + 1], *pt, *omd5, *nmd5;
+ char *obuff, *nbuff, *tbuff, *pt, *omd5, *nmd5;
unsigned int oline = 0, tline, found, i;
+ int l1 = 0, l2;
long opos;
-
if(!access(oldpath, R_OK) && (omd5 = cli_md5file(oldpath))) {
if(!(nmd5 = cli_md5file(newpath))) {
mprintf("!compare: Can't get MD5 checksum of %s\n", newpath);
@@ -1558,30 +1591,64 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
}
free(omd5);
free(nmd5);
+ l1 = maxlinelen(oldpath);
+ }
+
+ l2 = maxlinelen(newpath);
+ if(l1 == -1 || l2 == -1)
+ return -1;
+ l1 = MAX(l1, l2) + 1;
+
+ obuff = malloc(l1);
+ if(!obuff) {
+ mprintf("!compare: Can't allocate memory for 'obuff'\n");
+ return -1;
+ }
+ nbuff = malloc(l1);
+ if(!nbuff) {
+ mprintf("!compare: Can't allocate memory for 'nbuff'\n");
+ free(obuff);
+ return -1;
+ }
+ tbuff = malloc(l1);
+ if(!tbuff) {
+ mprintf("!compare: Can't allocate memory for 'tbuff'\n");
+ free(obuff);
+ free(nbuff);
+ return -1;
}
+ if(l1 > CLI_DEFAULT_LSIG_BUFSIZE)
+ fprintf(diff, "#LSIZE %u\n", l1 + 32);
+
fprintf(diff, "OPEN %s\n", newpath);
if(!(new = fopen(newpath, "r"))) {
mprintf("!compare: Can't open file %s for reading\n", newpath);
+ free(obuff);
+ free(nbuff);
+ free(tbuff);
return -1;
}
old = fopen(oldpath, "r");
- while(fgets(nbuff, sizeof(nbuff), new)) {
+ while(fgets(nbuff, l1, new)) {
i = strlen(nbuff);
if(i >= 2 && (nbuff[i - 1] == '\r' || (nbuff[i - 1] == '\n' && nbuff[i - 2] == '\r'))) {
mprintf("!compare: New %s file contains lines terminated with CRLF or CR\n", newpath);
if(old)
fclose(old);
fclose(new);
+ free(obuff);
+ free(nbuff);
+ free(tbuff);
return -1;
}
cli_chomp(nbuff);
if(!old) {
fprintf(diff, "ADD %s\n", nbuff);
} else {
- if(fgets(obuff, sizeof(obuff), old)) {
+ if(fgets(obuff, l1, old)) {
oline++;
cli_chomp(obuff);
if(!strcmp(nbuff, obuff)) {
@@ -1590,7 +1657,7 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
tline = 0;
found = 0;
opos = ftell(old);
- while(fgets(tbuff, sizeof(tbuff), old)) {
+ while(fgets(tbuff, l1, old)) {
tline++;
cli_chomp(tbuff);
@@ -1612,7 +1679,7 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
if((pt = strchr(tbuff, ' ')))
*pt = 0;
fprintf(diff, "DEL %u %s\n", oline + i, tbuff);
- if(!fgets(tbuff, sizeof(tbuff), old))
+ if(!fgets(tbuff, l1, old))
break;
}
oline += tline;
@@ -1630,20 +1697,11 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
fprintf(diff, "ADD %s\n", nbuff);
}
}
-#ifdef COMPATIBILITY_LIMIT
- if(!cli_strbcasestr(newpath, ".cbc") && strlen(nbuff) > COMPATIBILITY_LIMIT) {
- mprintf("!compare: COMPATIBILITY_LIMIT: Found too long line in new %s\n", newpath);
- if(old)
- fclose(old);
- fclose(new);
- return -1;
- }
-#endif
}
fclose(new);
if(old) {
- while(fgets(obuff, sizeof(obuff), old)) {
+ while(fgets(obuff, l1, old)) {
oline++;
obuff[16] = 0;
if((pt = strchr(obuff, ' ')))
@@ -1654,6 +1712,9 @@ static int compare(const char *oldpath, const char *newpath, FILE *diff)
}
fprintf(diff, "CLOSE\n");
+ free(obuff);
+ free(nbuff);
+ free(tbuff);
return 0;
}
@@ -1793,39 +1854,79 @@ static int verifydiff(const char *diff, const char *cvd, const char *incdir)
return ret;
}
-static int matchsig(const char *sig, int fd)
+static void matchsig(const char *sig, int fd)
{
struct cl_engine *engine;
+ struct cli_ac_result *acres = NULL, *res;
+ struct stat sb;
+ unsigned int matches = 0;
+ cli_ctx ctx;
int ret;
if(!(engine = cl_engine_new())) {
mprintf("!matchsig: Can't create new engine\n");
- return 0;
+ return;
}
+ cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
if(cli_initroots(engine, 0) != CL_SUCCESS) {
mprintf("!matchsig: cli_initroots() failed\n");
cl_engine_free(engine);
- return 0;
+ return;
}
if(cli_parse_add(engine->root[0], "test", sig, 0, 0, "*", 0, NULL, 0) != CL_SUCCESS) {
mprintf("!matchsig: Can't parse signature\n");
cl_engine_free(engine);
- return 0;
+ return;
}
if(cl_engine_compile(engine) != CL_SUCCESS) {
mprintf("!matchsig: Can't compile engine\n");
cl_engine_free(engine);
- return 0;
+ return;
+ }
+ memset(&ctx, '\0', sizeof(cli_ctx));
+ ctx.engine = engine;
+ ctx.options = CL_SCAN_STDOPT;
+ ctx.container_type = CL_TYPE_ANY;
+ ctx.dconf = (struct cli_dconf *) engine->dconf;
+ ctx.fmap = calloc(sizeof(fmap_t *), 1);
+ if(!ctx.fmap) {
+ cl_engine_free(engine);
+ return;
}
-
lseek(fd, 0, SEEK_SET);
- ret = cl_scandesc(fd, NULL, NULL, engine, CL_SCAN_STDOPT);
+ fstat(fd, &sb);
+ if(!(*ctx.fmap = fmap(fd, 0, sb.st_size))) {
+ free(ctx.fmap);
+ cl_engine_free(engine);
+ return;
+ }
+ ret = cli_fmap_scandesc(&ctx, 0, 0, NULL, AC_SCAN_VIR, &acres, NULL);
+ res = acres;
+ while(res) {
+ matches++;
+ res = res->next;
+ }
+ if(matches) {
+ mprintf("MATCH: ** YES ** (%u %s:", matches, matches > 1 ? "matches at offsets" : "match at offset");
+ res = acres;
+ while(res) {
+ mprintf(" %u", (unsigned int) res->offset);
+ res = res->next;
+ }
+ mprintf(")\n");
+ } else {
+ mprintf("MATCH: ** NO **\n");
+ }
+ while(acres) {
+ res = acres;
+ acres = acres->next;
+ free(res);
+ }
+ free(ctx.fmap);
cl_engine_free(engine);
-
- return (ret == CL_VIRUS) ? 1 : 0;
}
static char *decodehexstr(const char *hex, unsigned int *dlen)
@@ -2229,7 +2330,8 @@ static int decodesig(char *sig, int fd)
mprintf(" +-> DECODED SUBSIGNATURE:\n");
decodehex(pt ? pt : tokens[3 + i]);
} else {
- mprintf(" +-> MATCH: %s\n", matchsig(pt ? pt : tokens[3 + i], fd) ? "YES" : "** NO **");
+ mprintf(" +-> ");
+ matchsig(pt ? pt : tokens[3 + i], fd);
}
}
} else if(strchr(sig, ':')) { /* ndb */
@@ -2290,7 +2392,7 @@ static int decodesig(char *sig, int fd)
mprintf("DECODED SIGNATURE:\n");
decodehex(tokens[3]);
} else {
- mprintf("MATCH: %s\n", matchsig(tokens[3], fd) ? "YES" : "** NO **");
+ matchsig(tokens[3], fd);
}
} else if((pt = strchr(sig, '='))) {
*pt++ = 0;
@@ -2299,7 +2401,7 @@ static int decodesig(char *sig, int fd)
mprintf("DECODED SIGNATURE:\n");
decodehex(pt);
} else {
- mprintf("MATCH: %s\n", matchsig(pt, fd) ? "YES" : "** NO **");
+ matchsig(pt, fd);
}
} else {
mprintf("decodesig: Not supported signature format\n");
@@ -2336,11 +2438,6 @@ static int testsigs(const struct optstruct *opts)
return -1;
}
- if(cl_init(CL_INIT_DEFAULT) != CL_SUCCESS) {
- mprintf("!testsigs: Can't initialize libclamav: %s\n", cl_strerror(ret));
- return -1;
- }
-
sigs = fopen(optget(opts, "test-sigs")->strarg, "rb");
if(!sigs) {
mprintf("!testsigs: Can't open file %s\n", optget(opts, "test-sigs")->strarg);
@@ -2570,6 +2667,7 @@ static void help(void)
mprintf(" --build=NAME [cvd] -b NAME build a CVD file\n");
mprintf(" --no-cdiff Don't generate .cdiff file\n");
mprintf(" --server=ADDR ClamAV Signing Service address\n");
+ mprintf(" --datadir=DIR Use DIR as default database directory\n");
mprintf(" --unpack=FILE -u FILE Unpack a CVD/CLD file\n");
mprintf(" --unpack-current=SHORTNAME Unpack local CVD/CLD into cwd\n");
mprintf(" --list-sigs[=FILE] -l[FILE] List signature names\n");
@@ -2588,13 +2686,19 @@ static void help(void)
int main(int argc, char **argv)
{
- int ret = 1;
+ int ret;
struct optstruct *opts;
struct stat sb;
if(check_flevel())
exit(1);
+ if((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
+ mprintf("!Can't initialize libclamav: %s\n", cl_strerror(ret));
+ return -1;
+ }
+ ret = 1;
+
opts = optparse(NULL, argc, argv, 1, OPT_SIGTOOL, 0, NULL);
if(!opts) {
mprintf("!Can't parse command line options\n");
diff --git a/unit_tests/check_bytecode.c b/unit_tests/check_bytecode.c
index 9a9097e..b32ac0e 100644
--- a/unit_tests/check_bytecode.c
+++ b/unit_tests/check_bytecode.c
@@ -41,7 +41,8 @@
static void runtest(const char *file, uint64_t expected, int fail, int nojit,
const char *infile, struct cli_pe_hook_data *pedata,
- struct cli_exe_section *sections, const char *expectedvirname)
+ struct cli_exe_section *sections, const char *expectedvirname,
+ int testmode)
{
fmap_t *map = NULL;
int rc;
@@ -70,7 +71,7 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
cl_debug();
if (!nojit) {
- rc = cli_bytecode_init(&bcs, BYTECODE_ENGINE_MASK);
+ rc = cli_bytecode_init(&bcs);
fail_unless(rc == CL_SUCCESS, "cli_bytecode_init failed");
} else {
bcs.engine = NULL;
@@ -83,7 +84,10 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
fail_unless(rc == CL_SUCCESS, "cli_bytecode_load failed");
fclose(f);
- rc = cli_bytecode_prepare(&bcs, BYTECODE_ENGINE_MASK);
+ if (testmode)
+ engine->bytecode_mode = CL_BYTECODE_MODE_TEST;
+
+ rc = cli_bytecode_prepare2(engine, &bcs, BYTECODE_ENGINE_MASK);
fail_unless(rc == CL_SUCCESS, "cli_bytecode_prepare failed");
if (have_clamjit && !nojit && nojit != -1) {
@@ -137,55 +141,56 @@ static void runtest(const char *file, uint64_t expected, int fail, int nojit,
START_TEST (test_retmagic_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
+ runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 1);
}
END_TEST
START_TEST (test_retmagic_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/retmagic.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_arith_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_arith_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/arith.cbc", 0xd5555555, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls_int)
{
- runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls2_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls2_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls2.cbc", 0xf00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
@@ -193,41 +198,41 @@ START_TEST (test_div0_jit)
{
cl_init(CL_INIT_DEFAULT);
/* must not crash on div#0 but catch it */
- runtest("input/div0.cbc", 0, CL_EBYTECODE, 0, NULL, NULL, NULL, NULL);
+ runtest("input/div0.cbc", 0, CL_EBYTECODE, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_div0_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/div0.cbc", 0, CL_EBYTECODE, 1, NULL, NULL, NULL, NULL);
+ runtest("input/div0.cbc", 0, CL_EBYTECODE, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_lsig_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/lsig.cbc", 0, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/lsig.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_lsig_int)
{
- runtest("input/lsig.cbc", 0, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/lsig.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inf_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inf.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL);
+ runtest("input/inf.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inf_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inf.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL);
+ runtest("input/inf.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
@@ -250,7 +255,7 @@ START_TEST (test_matchwithread_jit)
sect.uraw = 1;
sect.ursz = 512;
runtest("input/matchwithread.cbc", 0, 0, 0, "../test/clam.exe", &pedata,
- §, "ClamAV-Test-File-detected-via-bytecode");
+ §, "ClamAV-Test-File-detected-via-bytecode", 0);
}
END_TEST
@@ -273,7 +278,7 @@ START_TEST (test_matchwithread_int)
sect.uraw = 1;
sect.ursz = 512;
runtest("input/matchwithread.cbc", 0, 0, 1, "../test/clam.exe", &pedata,
- §, "ClamAV-Test-File-detected-via-bytecode");
+ §, "ClamAV-Test-File-detected-via-bytecode", 0);
}
END_TEST
@@ -281,182 +286,182 @@ END_TEST
START_TEST (test_pdf_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/pdf.cbc", 0, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/pdf.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_pdf_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/pdf.cbc", 0, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/pdf.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_bswap_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/bswap.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/bswap.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_bswap_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/bswap.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/bswap.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inflate_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inflate.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/inflate.cbc", 0xbeef, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inflate_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inflate.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/inflate.cbc", 0xbeef, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_api_extract_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/api_extract_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL);
+ runtest("input/api_extract_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_api_files_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/api_files_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL);
+ runtest("input/api_files_7.cbc", 0xf00d, 0, 0, "input/apitestfile", NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls2_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls2_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls2_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_arith_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_debug_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/debug_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/debug_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inf_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL);
+ runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_lsig_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/lsig_7.cbc", 0, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/lsig_7.cbc", 0, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_retmagic_7_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL);
+ runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_testadt_jit)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/testadt_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL);
+ runtest("input/testadt_7.cbc", 0xf00d, 0, 0, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_api_extract_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/api_extract_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL);
+ runtest("input/api_extract_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_api_files_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/api_files_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL);
+ runtest("input/api_files_7.cbc", 0xf00d, 0, 1, "input/apitestfile", NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls2_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls2_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls2_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_apicalls_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/apicalls_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/apicalls_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_arith_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/arith_7.cbc", 0xd55555dd, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_debug_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/debug_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/debug_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_inf_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL);
+ runtest("input/inf_7.cbc", 0, CL_ETIMEOUT, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_lsig_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/lsig_7.cbc", 0, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/lsig_7.cbc", 0, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_retmagic_7_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL);
+ runtest("input/retmagic_7.cbc", 0x1234f00d, CL_SUCCESS, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
START_TEST (test_testadt_int)
{
cl_init(CL_INIT_DEFAULT);
- runtest("input/testadt_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL);
+ runtest("input/testadt_7.cbc", 0xf00d, 0, 1, NULL, NULL, NULL, NULL, 0);
}
END_TEST
diff --git a/unit_tests/check_common.sh b/unit_tests/check_common.sh
index 4f93b8d..b9024d6 100644
--- a/unit_tests/check_common.sh
+++ b/unit_tests/check_common.sh
@@ -171,6 +171,29 @@ EOF
grep "phish-test-ssl: Heuristics.Phishing.Email.SSL-Spoof FOUND" clamscan3.log >/dev/null || die "phish-test1 failed";
grep "phish-test-cloak: Heuristics.Phishing.Email.Cloaked.Null FOUND" clamscan3.log >/dev/null || die "phish-test2 failed";
+
+ cat <<EOF >test-db/test.ign2
+ClamAV-Test-File
+EOF
+ cat <<EOF >test-db/test.idb
+EA0X-32x32x8:ea0x-grp1:ea0x-grp2:2046f030a42a07153f4120a0031600007000005e1617ef0000d21100cb090674150f880313970b0e7716116d01136216022500002f0a173700081a004a0e
+IScab-16x16x8:iscab-grp1:iscab-grp2:107b3000168306015c20a0105b07060be0a0b11c050bea0706cb0a0bbb060b6f00017c06018301068109086b03046705081b000a270a002a000039002b17
+EOF
+ cat <<EOF >test-db/test.ldb
+ClamAV-Test-Icon-EA0X;Engine:52-1000,Target:1,IconGroup1:ea0x-grp1,IconGroup2:*;(0);0:4d5a
+ClamAV-Test-Icon-IScab;Engine:52-1000,Target:1,IconGroup2:iscab-grp2;(0);0:4d5a
+EOF
+ if test_run 1 $CLAMSCAN --quiet -dtest-db $TESTFILES --log=clamscan4.log; then
+ scan_failed clamscan4.log "clamscan didn't detect icons correctly"
+ fi
+ grep "clam.ea05.exe: ClamAV-Test-Icon-EA0X.UNOFFICIAL FOUND" clamscan4.log || die "icon-test1 failed"
+ grep "clam.ea06.exe: ClamAV-Test-Icon-EA0X.UNOFFICIAL FOUND" clamscan4.log || die "icon-test2 failed"
+ grep "clam_IScab_ext.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND" clamscan4.log || die "icon-test3 failed"
+ grep "clam_IScab_int.exe: ClamAV-Test-Icon-IScab.UNOFFICIAL FOUND" clamscan4.log || die "icon-test4 failed"
+ NINFECTED=`grep "Infected files" clamscan4.log | cut -f2 -d: | sed -e 's/ //g'`
+ if test "x$NINFECTED" != x4; then
+ scan_failed clamscan4.log "clamscan has detected spurious icons or whitlisting was not applier properly"
+ fi
test_end $1
}
diff --git a/unit_tests/check_regex.c b/unit_tests/check_regex.c
index 0e1a4c1..6858d6f 100644
--- a/unit_tests/check_regex.c
+++ b/unit_tests/check_regex.c
@@ -177,6 +177,9 @@ static const struct rtest {
3 - blacklisted if 2nd db is loaded,
4 - invalid regex*/
} rtests[] = {
+ {NULL,"http://fake.example.com", "http://foo@key.com/", 0},
+ {NULL,"http://fake.example.com", "foo.example.com at key.com", 0},
+ {NULL,"http://fake.example.com", "foo at key.com", 2},
{NULL,"http://fake.example.com","=====key.com",0},
{NULL,"http://key.com","=====key.com",2},
{NULL," http://key.com","=====key.com",2},
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list