[Pkg-clamav-devel] Bug#926171: unblock: clamav/0.101.2+dfsg-1
Sebastian Andrzej Siewior
sebastian at breakpoint.cc
Mon Apr 1 13:42:00 BST 2019
Package: release.debian.org
User: release.debian.org at packages.debian.org
Usertags: unblock
Severity: normal
Please unblock package clamav.
This is the new upstream releases fixing 6 CVEs. Looking at the debdiff
(after removing auto generated files, copyright updates, white space
damage / reformatting) it seems also fix memory leaks in ARJ/PDF file
scanners. Those are mentioned in the "Fixes for the following assorted
bugs" in upstream[0] release notes.
unblock clamav/0.101.2+dfsg-1
[0] https://blog.clamav.net/2019/03/clamav-01012-and-01003-patches-have.html
Sebastian
-------------- next part --------------
diff -Nru clamav-0.101.1+dfsg/clamd/scanner.c clamav-0.101.2+dfsg/clamd/scanner.c
--- clamav-0.101.1+dfsg/clamd/scanner.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/clamd/scanner.c 2019-03-13 22:13:01.000000000 +0100
@@ -394,7 +394,7 @@
context.filename = fdstr;
context.virsize = 0;
context.scandata = NULL;
- ret = cl_scandesc_callback(fd, NULL, &virname, scanned, engine, options, &context);
+ ret = cl_scandesc_callback(fd, conn->filename, &virname, scanned, engine, options, &context);
thrmgr_setactivetask(NULL, NULL);
if (thrmgr_group_need_terminate(conn->group)) {
@@ -568,7 +568,7 @@
context.filename = peer_addr;
context.virsize = 0;
context.scandata = NULL;
- ret = cl_scandesc_callback(tmpd, NULL, &virname, scanned, engine, options, &context);
+ ret = cl_scandesc_callback(tmpd, tmpname, &virname, scanned, engine, options, &context);
thrmgr_setactivetask(NULL, NULL);
} else {
ret = -1;
diff -Nru clamav-0.101.1+dfsg/configure.ac clamav-0.101.2+dfsg/configure.ac
--- clamav-0.101.1+dfsg/configure.ac 2019-01-07 22:16:54.000000000 +0100
+++ clamav-0.101.2+dfsg/configure.ac 2019-03-30 14:57:20.000000000 +0100
@@ -20,7 +22,7 @@
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.101.1], [https://bugzilla.clamav.net/], [clamav], [https://www.clamav.net/])
+AC_INIT([ClamAV], [0.101.2], [https://bugzilla.clamav.net/], [clamav], [https://www.clamav.net/])
dnl enable C++
AC_PROG_CXX()
@@ -78,6 +80,7 @@
build_configure_args=`echo "$ac_configure_args" | sed -e 's/[\"]//g'`
AC_SUBST([BUILD_CONFIGURE_FLAGS], [$build_configure_args])
+m4_include([m4/reorganization/code_checks/fuzz.m4])
m4_include([m4/reorganization/code_checks/functions.m4])
m4_include([m4/reorganization/code_checks/mpool.m4])
m4_include([m4/reorganization/code_checks/unit_tests.m4])
@@ -170,6 +173,7 @@
etc/Makefile
test/Makefile
unit_tests/Makefile
+fuzz/Makefile
clamdtop/Makefile
clambc/Makefile
libfreshclam/Makefile
diff -Nru clamav-0.101.1+dfsg/debian/changelog clamav-0.101.2+dfsg/debian/changelog
--- clamav-0.101.1+dfsg/debian/changelog 2019-02-28 23:36:02.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/changelog 2019-03-30 16:25:48.000000000 +0100
@@ -1,3 +1,26 @@
+clamav (0.101.2+dfsg-1) unstable; urgency=high
+
+ * Import 0.101.2
+ - CVE-2019-1787 (An out-of-bounds heap read condition may occur when
+ scanning PDF documents)
+ - CVE-2019-1789 (An out-of-bounds heap read condition may occur when
+ scanning PE files)
+ - CVE-2019-1788 (An out-of-bounds heap write condition may occur when
+ scanning OLE2 files)
+ - CVE-2019-1786 (An out-of-bounds heap read condition may occur when
+ scanning malformed PDF documents)
+ - CVE-2019-1785 (A path-traversal write condition may occur as a result of
+ improper input validation when scanning RAR archives)
+ - CVE-2019-1798 (A use-after-free condition may occur as a result of
+ improper error handling when scanning nested RAR archives)
+ - update symbols file
+ - Remove DetectBrokenExecutables option from clamd template, it is
+ deprecated.
+ * Drop the dbgsym migration line.
+ * Bump standards-version to 4.3.0 without further change
+
+ -- Sebastian Andrzej Siewior <sebastian at breakpoint.cc> Sat, 30 Mar 2019 16:25:48 +0100
+
clamav (0.101.1+dfsg-3) unstable; urgency=medium
* Upload to unstable.
diff -Nru clamav-0.101.1+dfsg/debian/clamav-daemon.postinst.in clamav-0.101.2+dfsg/debian/clamav-daemon.postinst.in
--- clamav-0.101.1+dfsg/debian/clamav-daemon.postinst.in 2019-01-10 23:33:34.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/clamav-daemon.postinst.in 2019-03-30 16:04:35.000000000 +0100
@@ -197,7 +197,6 @@
[ -z "$DisableCache" ] && DisableCache=false
[ -z "$ScanPE" ] && ScanPE=true
[ -z "$ScanELF" ] && ScanELF=true
- [ -z "$DetectBrokenExecutables" ] && DetectBrokenExecutables=false
[ -z "$ScanOLE2" ] && ScanOLE2=true
[ -z "$OLE2BlockMacros" ] && OLE2BlockMacros=false
[ -z "$OnAccessExcludeRootUID" ] && OnAccessExcludeRootUID=no
@@ -307,7 +306,6 @@
MaxScriptNormalize $MaxScriptNormalize
MaxZipTypeRcg $MaxZipTypeRcg
ScanSWF $ScanSWF
-DetectBrokenExecutables $DetectBrokenExecutables
ExitOnOOM $ExitOnOOM
LeaveTemporaryFiles $LeaveTemporaryFiles
AlgorithmicDetection $AlgorithmicDetection
diff -Nru clamav-0.101.1+dfsg/debian/clamav-testfiles.lintian-overrides clamav-0.101.2+dfsg/debian/clamav-testfiles.lintian-overrides
--- clamav-0.101.1+dfsg/debian/clamav-testfiles.lintian-overrides 2019-01-07 23:18:26.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/clamav-testfiles.lintian-overrides 2019-03-30 16:25:48.000000000 +0100
@@ -1,2 +1,4 @@
# This is intentionally shipped compressed and uncompressed to be able to test, if clamav detects also the compressed file.
clamav-testfiles: duplicated-compressed-file usr/share/clamav-testfiles/clam.exe.bz2
+# These executable are test files for clamav (they are not executed otherwise).
+clamav-testfiles: portable-executable-missing-security-features usr/share/clamav-testfiles/*.exe *
diff -Nru clamav-0.101.1+dfsg/debian/control clamav-0.101.2+dfsg/debian/control
--- clamav-0.101.1+dfsg/debian/control 2019-01-09 23:34:23.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/control 2019-03-30 16:25:48.000000000 +0100
@@ -30,7 +30,7 @@
po-debconf,
python:native,
zlib1g-dev
-Standards-Version: 4.1.5
+Standards-Version: 4.3.0
Rules-Requires-Root: no
Vcs-Git: https://salsa.debian.org/clamav-team/clamav.git
Vcs-Browser: https://salsa.debian.org/clamav-team/clamav
diff -Nru clamav-0.101.1+dfsg/debian/copyright clamav-0.101.2+dfsg/debian/copyright
--- clamav-0.101.1+dfsg/debian/copyright 2019-01-07 23:18:26.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/copyright 2019-03-30 16:25:48.000000000 +0100
@@ -89,7 +89,6 @@
clamdscan/Makefile.am
clamscan/Makefile.am
database/Makefile.am
- docs/clamdoc.tex
docs/Makefile.am
etc/Makefile.am
examples/ex1.c
@@ -106,7 +105,6 @@
libclamav/Makefile.am
libclamav/c++/configure.ac
libclamav/c++/Makefile.am
- libclamunrar_iface/Makefile.am
Makefile.am
sigtool/Makefile.am
sigtool/vba.c
@@ -270,7 +268,7 @@
Files:
libclamav/mspack.c
libclamav/mspack.h
- libclamunrar_iface/unrar_iface.c
+ libclamunrar_iface/unrar_iface.cpp
libclamunrar_iface/unrar_iface.h
Copyright:
2003-2004 Stuart Caie
@@ -436,7 +434,6 @@
libclamav/c++/aclocal.m4
libclamav/c++/Makefile.in
libclamav/Makefile.in
- libclamunrar_iface/Makefile.in
libltdl/Makefile.in
Makefile.in
shared/Makefile.in
diff -Nru clamav-0.101.1+dfsg/debian/.git-dpm clamav-0.101.2+dfsg/debian/.git-dpm
--- clamav-0.101.1+dfsg/debian/.git-dpm 2019-01-07 23:18:28.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/.git-dpm 2019-03-30 15:32:49.000000000 +0100
@@ -1,8 +1,8 @@
# see git-dpm(1) from git-dpm package
-9ddcc71e6832d0c6ddd675d2dca3bb4758e4d7c9
-9ddcc71e6832d0c6ddd675d2dca3bb4758e4d7c9
-beeb989a01d8d941f1408bc7d7792aa985e872dd
-beeb989a01d8d941f1408bc7d7792aa985e872dd
-clamav_0.101.1+dfsg.orig.tar.xz
-0db5f62275b81d9fea65fe07990a75d64a32769f
-4987424
+cb77f255d9bc2871a474227e2a8676dfd930a483
+cb77f255d9bc2871a474227e2a8676dfd930a483
+5a612c89e68e5010b2cd71002ceb15efc03a2324
+5a612c89e68e5010b2cd71002ceb15efc03a2324
+clamav_0.101.2+dfsg.orig.tar.xz
+7f723ff0a4ce24ef821947fd3832e3f54e17a875
+4719692
diff -Nru clamav-0.101.1+dfsg/debian/libclamav9.symbols clamav-0.101.2+dfsg/debian/libclamav9.symbols
--- clamav-0.101.1+dfsg/debian/libclamav9.symbols 2019-01-07 23:20:32.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/libclamav9.symbols 2019-03-30 16:25:48.000000000 +0100
@@ -1,16 +1,16 @@
libclamav.so.9 libclamav9 #MINVER#
* Build-Depends-Package: libclamav-dev
- CLAMAV_PRIVATE at CLAMAV_PRIVATE 0.101.1
+ CLAMAV_PRIVATE at CLAMAV_PRIVATE 0.101.2
CLAMAV_PUBLIC at CLAMAV_PUBLIC 0.101.0
- base64Flush at CLAMAV_PRIVATE 0.101.1
- blobAddData at CLAMAV_PRIVATE 0.101.1
- blobCreate at CLAMAV_PRIVATE 0.101.1
- blobDestroy at CLAMAV_PRIVATE 0.101.1
- cl_ASN1_GetTimeT at CLAMAV_PRIVATE 0.101.1
+ base64Flush at CLAMAV_PRIVATE 0.101.2
+ blobAddData at CLAMAV_PRIVATE 0.101.2
+ blobCreate at CLAMAV_PRIVATE 0.101.2
+ blobDestroy at CLAMAV_PRIVATE 0.101.2
+ cl_ASN1_GetTimeT at CLAMAV_PRIVATE 0.101.2
cl_always_gen_section_hash at CLAMAV_PUBLIC 0.101.0
- cl_base64_decode at CLAMAV_PRIVATE 0.101.1
- cl_base64_encode at CLAMAV_PRIVATE 0.101.1
- cl_cleanup_crypto at CLAMAV_PRIVATE 0.101.1
+ cl_base64_decode at CLAMAV_PRIVATE 0.101.2
+ cl_base64_encode at CLAMAV_PRIVATE 0.101.2
+ cl_cleanup_crypto at CLAMAV_PRIVATE 0.101.2
cl_countsigs at CLAMAV_PUBLIC 0.101.0
cl_cvdfree at CLAMAV_PUBLIC 0.101.0
cl_cvdhead at CLAMAV_PUBLIC 0.101.0
@@ -50,19 +50,19 @@
cl_fmap_close at CLAMAV_PUBLIC 0.101.0
cl_fmap_open_handle at CLAMAV_PUBLIC 0.101.0
cl_fmap_open_memory at CLAMAV_PUBLIC 0.101.0
- cl_get_pkey_file at CLAMAV_PRIVATE 0.101.1
- cl_get_x509_from_mem at CLAMAV_PRIVATE 0.101.1
- cl_hash_data at CLAMAV_PRIVATE 0.101.1
+ cl_get_pkey_file at CLAMAV_PRIVATE 0.101.2
+ cl_get_x509_from_mem at CLAMAV_PRIVATE 0.101.2
+ cl_hash_data at CLAMAV_PRIVATE 0.101.2
cl_hash_destroy at CLAMAV_PUBLIC 0.101.0
- cl_hash_file_fd at CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fd_ctx at CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fp at CLAMAV_PRIVATE 0.101.1
+ cl_hash_file_fd at CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fd_ctx at CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fp at CLAMAV_PRIVATE 0.101.2
cl_hash_init at CLAMAV_PUBLIC 0.101.0
cl_init at CLAMAV_PUBLIC 0.101.0
- cl_initialize_crypto at CLAMAV_PRIVATE 0.101.1
+ cl_initialize_crypto at CLAMAV_PRIVATE 0.101.2
cl_load at CLAMAV_PUBLIC 0.101.0
- cl_load_cert at CLAMAV_PRIVATE 0.101.1
- cl_load_crl at CLAMAV_PRIVATE 0.101.1
+ cl_load_cert at CLAMAV_PRIVATE 0.101.2
+ cl_load_crl at CLAMAV_PRIVATE 0.101.2
cl_retdbdir at CLAMAV_PUBLIC 0.101.0
cl_retflevel at CLAMAV_PUBLIC 0.101.1
cl_retver at CLAMAV_PUBLIC 0.101.0
@@ -72,182 +72,185 @@
cl_scanfile_callback at CLAMAV_PUBLIC 0.101.0
cl_scanmap_callback at CLAMAV_PUBLIC 0.101.0
cl_set_clcb_msg at CLAMAV_PUBLIC 0.101.0
- cl_sha1 at CLAMAV_PRIVATE 0.101.1
- cl_sha256 at CLAMAV_PRIVATE 0.101.1
- cl_sign_data at CLAMAV_PRIVATE 0.101.1
- cl_sign_data_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fd at CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fp at CLAMAV_PRIVATE 0.101.1
+ cl_sha1 at CLAMAV_PRIVATE 0.101.2
+ cl_sha256 at CLAMAV_PRIVATE 0.101.2
+ cl_sign_data at CLAMAV_PRIVATE 0.101.2
+ cl_sign_data_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fd at CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fp at CLAMAV_PRIVATE 0.101.2
cl_statchkdir at CLAMAV_PUBLIC 0.101.0
cl_statfree at CLAMAV_PUBLIC 0.101.0
cl_statinidir at CLAMAV_PUBLIC 0.101.0
cl_strerror at CLAMAV_PUBLIC 0.101.0
cl_update_hash at CLAMAV_PUBLIC 0.101.0
- cl_validate_certificate_chain at CLAMAV_PRIVATE 0.101.1
- cl_validate_certificate_chain_ts_dir at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cli_ac_buildtrie at CLAMAV_PRIVATE 0.101.1
- cli_ac_chklsig at CLAMAV_PRIVATE 0.101.1
- cli_ac_free at CLAMAV_PRIVATE 0.101.1
- cli_ac_freedata at CLAMAV_PRIVATE 0.101.1
- cli_ac_init at CLAMAV_PRIVATE 0.101.1
- cli_ac_initdata at CLAMAV_PRIVATE 0.101.1
- cli_ac_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_bm_free at CLAMAV_PRIVATE 0.101.1
- cli_bm_init at CLAMAV_PRIVATE 0.101.1
- cli_bm_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_build_regex_list at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_alloc at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_clear at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_destroy at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_getresult_int at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_set_trace at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfile at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfuncid at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_int at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_ptr at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug_printsrc at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_destroy at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_done at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_init at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_load at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_prepare2 at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_printversion at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_run at CLAMAV_PRIVATE 0.101.1
- cli_bytefunc_describe at CLAMAV_PRIVATE 0.101.1
- cli_byteinst_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytetype_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytevalue_describe at CLAMAV_PRIVATE 0.101.1
- cli_calloc at CLAMAV_PRIVATE 0.101.1
- cli_checkfp_pe at CLAMAV_PRIVATE 0.101.1
- cli_chomp at CLAMAV_PRIVATE 0.101.1
- cli_ctime at CLAMAV_PRIVATE 0.101.1
- cli_cvdunpack at CLAMAV_PRIVATE 0.101.1
- cli_dbgmsg_internal at CLAMAV_PRIVATE 0.101.1
- cli_dconf_init at CLAMAV_PRIVATE 0.101.1
- cli_debug_flag at CLAMAV_PRIVATE 0.101.1
- cli_detect_environment at CLAMAV_PRIVATE 0.101.1
- cli_disasm_one at CLAMAV_PRIVATE 0.101.1
- cli_errmsg at CLAMAV_PRIVATE 0.101.1
- cli_filecopy at CLAMAV_PRIVATE 0.101.1
- cli_fmap_scandesc at CLAMAV_PRIVATE 0.101.1
- cli_ftw at CLAMAV_PRIVATE 0.101.1
- cli_genhash_pe at CLAMAV_PRIVATE 0.101.1
- cli_gentemp at CLAMAV_PRIVATE 0.101.1
- cli_gentempfd at CLAMAV_PRIVATE 0.101.1
- cli_gettmpdir at CLAMAV_PRIVATE 0.101.1
- cli_hashfile at CLAMAV_PRIVATE 0.101.1
- cli_hashset_destroy at CLAMAV_PRIVATE 0.101.1
- cli_hashstream at CLAMAV_PRIVATE 0.101.1
- cli_hex2str at CLAMAV_PRIVATE 0.101.1
- cli_hex2ui at CLAMAV_PRIVATE 0.101.1
- cli_initroots at CLAMAV_PRIVATE 0.101.1
- cli_isnumber at CLAMAV_PRIVATE 0.101.1
- cli_js_destroy at CLAMAV_PRIVATE 0.101.1
- cli_js_init at CLAMAV_PRIVATE 0.101.1
- cli_js_output at CLAMAV_PRIVATE 0.101.1
- cli_js_parse_done at CLAMAV_PRIVATE 0.101.1
- cli_js_process_buffer at CLAMAV_PRIVATE 0.101.1
- cli_ldbtokenize at CLAMAV_PRIVATE 0.101.1
- cli_malloc at CLAMAV_PRIVATE 0.101.1
- cli_memstr at CLAMAV_PRIVATE 0.101.1
- cli_ole2_extract at CLAMAV_PRIVATE 0.101.1
- cli_parse_add at CLAMAV_PRIVATE 0.101.1
- cli_pcre_build at CLAMAV_PRIVATE 0.101.1
- cli_pcre_freeoff at CLAMAV_PRIVATE 0.101.1
- cli_pcre_init at CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_events_destroy at CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_print at CLAMAV_PRIVATE 0.101.1
- cli_pcre_recaloff at CLAMAV_PRIVATE 0.101.1
- cli_pcre_scanbuf at CLAMAV_PRIVATE 0.101.1
- cli_ppt_vba_read at CLAMAV_PRIVATE 0.101.1
- cli_printcxxver at CLAMAV_PRIVATE 0.101.1
- cli_readn at CLAMAV_PRIVATE 0.101.1
- cli_realloc at CLAMAV_PRIVATE 0.101.1
- cli_regcomp at CLAMAV_PRIVATE 0.101.1
- cli_regex2suffix at CLAMAV_PRIVATE 0.101.1
- cli_regexec at CLAMAV_PRIVATE 0.101.1
- cli_regfree at CLAMAV_PRIVATE 0.101.1
- cli_rmdirs at CLAMAV_PRIVATE 0.101.1
- cli_rndnum at CLAMAV_PRIVATE 0.101.1
- cli_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_sigopts_handler at CLAMAV_PRIVATE 0.101.1
- cli_sigperf_events_destroy at CLAMAV_PRIVATE 0.101.1
- cli_sigperf_print at CLAMAV_PRIVATE 0.101.1
- cli_str2hex at CLAMAV_PRIVATE 0.101.1
- cli_strbcasestr at CLAMAV_PRIVATE 0.101.1
- cli_strdup at CLAMAV_PRIVATE 0.101.1
- cli_strerror at CLAMAV_PRIVATE 0.101.1
- cli_strlcat at CLAMAV_PRIVATE 0.101.1
- cli_strlcpy at CLAMAV_PRIVATE 0.101.1
- cli_strrcpy at CLAMAV_PRIVATE 0.101.1
- cli_strtok at CLAMAV_PRIVATE 0.101.1
- cli_strtokbuf at CLAMAV_PRIVATE 0.101.1
- cli_strtokenize at CLAMAV_PRIVATE 0.101.1
- cli_textbuffer_append_normalize at CLAMAV_PRIVATE 0.101.1
- cli_unescape at CLAMAV_PRIVATE 0.101.1
- cli_unlink at CLAMAV_PRIVATE 0.101.1
- cli_url_canon at CLAMAV_PRIVATE 0.101.1
- cli_utf16_to_utf8 at CLAMAV_PRIVATE 0.101.1
- cli_utf16toascii at CLAMAV_PRIVATE 0.101.1
- cli_vba_inflate at CLAMAV_PRIVATE 0.101.1
- cli_vba_readdir at CLAMAV_PRIVATE 0.101.1
- cli_versig2 at CLAMAV_PRIVATE 0.101.1
- cli_versig at CLAMAV_PRIVATE 0.101.1
- cli_warnmsg at CLAMAV_PRIVATE 0.101.1
- cli_wm_decrypt_macro at CLAMAV_PRIVATE 0.101.1
- cli_wm_readdir at CLAMAV_PRIVATE 0.101.1
- cli_writen at CLAMAV_PRIVATE 0.101.1
- decodeLine at CLAMAV_PRIVATE 0.101.1
- disasmbuf at CLAMAV_PRIVATE 0.101.1
- fmap at CLAMAV_PRIVATE 0.101.1
- get_fpu_endian at CLAMAV_PRIVATE 0.101.1
- have_clamjit at CLAMAV_PRIVATE 0.101.1
- have_rar at CLAMAV_PRIVATE 0.101.1
- html_normalise_map at CLAMAV_PRIVATE 0.101.1
- html_normalise_mem at CLAMAV_PRIVATE 0.101.1
- html_screnc_decode at CLAMAV_PRIVATE 0.101.1
- html_tag_arg_free at CLAMAV_PRIVATE 0.101.1
- init_domainlist at CLAMAV_PRIVATE 0.101.1
- init_regex_list at CLAMAV_PRIVATE 0.101.1
- init_whitelist at CLAMAV_PRIVATE 0.101.1
- is_regex_ok at CLAMAV_PRIVATE 0.101.1
- load_regex_matcher at CLAMAV_PRIVATE 0.101.1
+ cl_validate_certificate_chain at CLAMAV_PRIVATE 0.101.2
+ cl_validate_certificate_chain_ts_dir at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cli_ac_buildtrie at CLAMAV_PRIVATE 0.101.2
+ cli_ac_chklsig at CLAMAV_PRIVATE 0.101.2
+ cli_ac_free at CLAMAV_PRIVATE 0.101.2
+ cli_ac_freedata at CLAMAV_PRIVATE 0.101.2
+ cli_ac_init at CLAMAV_PRIVATE 0.101.2
+ cli_ac_initdata at CLAMAV_PRIVATE 0.101.2
+ cli_ac_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_bm_free at CLAMAV_PRIVATE 0.101.2
+ cli_bm_init at CLAMAV_PRIVATE 0.101.2
+ cli_bm_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_build_regex_list at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_alloc at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_clear at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_getresult_int at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_set_trace at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfile at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfuncid at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_int at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_ptr at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug_printsrc at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_done at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_init at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_load at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_prepare2 at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_printversion at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_run at CLAMAV_PRIVATE 0.101.2
+ cli_bytefunc_describe at CLAMAV_PRIVATE 0.101.2
+ cli_byteinst_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytetype_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytevalue_describe at CLAMAV_PRIVATE 0.101.2
+ cli_calloc at CLAMAV_PRIVATE 0.101.2
+ cli_checkfp_pe at CLAMAV_PRIVATE 0.101.2
+ cli_chomp at CLAMAV_PRIVATE 0.101.2
+ cli_ctime at CLAMAV_PRIVATE 0.101.2
+ cli_cvdunpack at CLAMAV_PRIVATE 0.101.2
+ cli_dbgmsg_internal at CLAMAV_PRIVATE 0.101.2
+ cli_dconf_init at CLAMAV_PRIVATE 0.101.2
+ cli_debug_flag at CLAMAV_PRIVATE 0.101.2
+ cli_detect_environment at CLAMAV_PRIVATE 0.101.2
+ cli_disasm_one at CLAMAV_PRIVATE 0.101.2
+ cli_errmsg at CLAMAV_PRIVATE 0.101.2
+ cli_filecopy at CLAMAV_PRIVATE 0.101.2
+ cli_fmap_scandesc at CLAMAV_PRIVATE 0.101.2
+ cli_free_vba_project at CLAMAV_PRIVATE 0.101.2
+ cli_ftw at CLAMAV_PRIVATE 0.101.2
+ cli_genhash_pe at CLAMAV_PRIVATE 0.101.2
+ cli_gentemp at CLAMAV_PRIVATE 0.101.2
+ cli_gentempfd at CLAMAV_PRIVATE 0.101.2
+ cli_gettmpdir at CLAMAV_PRIVATE 0.101.2
+ cli_hashfile at CLAMAV_PRIVATE 0.101.2
+ cli_hashset_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_hashstream at CLAMAV_PRIVATE 0.101.2
+ cli_hex2str at CLAMAV_PRIVATE 0.101.2
+ cli_hex2ui at CLAMAV_PRIVATE 0.101.2
+ cli_initroots at CLAMAV_PRIVATE 0.101.2
+ cli_isnumber at CLAMAV_PRIVATE 0.101.2
+ cli_js_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_js_init at CLAMAV_PRIVATE 0.101.2
+ cli_js_output at CLAMAV_PRIVATE 0.101.2
+ cli_js_parse_done at CLAMAV_PRIVATE 0.101.2
+ cli_js_process_buffer at CLAMAV_PRIVATE 0.101.2
+ cli_ldbtokenize at CLAMAV_PRIVATE 0.101.2
+ cli_malloc at CLAMAV_PRIVATE 0.101.2
+ cli_memstr at CLAMAV_PRIVATE 0.101.2
+ cli_ole2_extract at CLAMAV_PRIVATE 0.101.2
+ cli_parse_add at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_build at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_freeoff at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_init at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_events_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_print at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_recaloff at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_scanbuf at CLAMAV_PRIVATE 0.101.2
+ cli_ppt_vba_read at CLAMAV_PRIVATE 0.101.2
+ cli_printcxxver at CLAMAV_PRIVATE 0.101.2
+ cli_readn at CLAMAV_PRIVATE 0.101.2
+ cli_realloc at CLAMAV_PRIVATE 0.101.2
+ cli_regcomp at CLAMAV_PRIVATE 0.101.2
+ cli_regex2suffix at CLAMAV_PRIVATE 0.101.2
+ cli_regexec at CLAMAV_PRIVATE 0.101.2
+ cli_regfree at CLAMAV_PRIVATE 0.101.2
+ cli_rmdirs at CLAMAV_PRIVATE 0.101.2
+ cli_rndnum at CLAMAV_PRIVATE 0.101.2
+ cli_sanitize_filepath at CLAMAV_PRIVATE 0.101.2
+ cli_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_sigopts_handler at CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_events_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_print at CLAMAV_PRIVATE 0.101.2
+ cli_str2hex at CLAMAV_PRIVATE 0.101.2
+ cli_strbcasestr at CLAMAV_PRIVATE 0.101.2
+ cli_strdup at CLAMAV_PRIVATE 0.101.2
+ cli_strerror at CLAMAV_PRIVATE 0.101.2
+ cli_strlcat at CLAMAV_PRIVATE 0.101.2
+ cli_strlcpy at CLAMAV_PRIVATE 0.101.2
+ cli_strnstr at CLAMAV_PRIVATE 0.101.2
+ cli_strrcpy at CLAMAV_PRIVATE 0.101.2
+ cli_strtok at CLAMAV_PRIVATE 0.101.2
+ cli_strtokbuf at CLAMAV_PRIVATE 0.101.2
+ cli_strtokenize at CLAMAV_PRIVATE 0.101.2
+ cli_textbuffer_append_normalize at CLAMAV_PRIVATE 0.101.2
+ cli_unescape at CLAMAV_PRIVATE 0.101.2
+ cli_unlink at CLAMAV_PRIVATE 0.101.2
+ cli_url_canon at CLAMAV_PRIVATE 0.101.2
+ cli_utf16_to_utf8 at CLAMAV_PRIVATE 0.101.2
+ cli_utf16toascii at CLAMAV_PRIVATE 0.101.2
+ cli_vba_inflate at CLAMAV_PRIVATE 0.101.2
+ cli_vba_readdir at CLAMAV_PRIVATE 0.101.2
+ cli_versig2 at CLAMAV_PRIVATE 0.101.2
+ cli_versig at CLAMAV_PRIVATE 0.101.2
+ cli_warnmsg at CLAMAV_PRIVATE 0.101.2
+ cli_wm_decrypt_macro at CLAMAV_PRIVATE 0.101.2
+ cli_wm_readdir at CLAMAV_PRIVATE 0.101.2
+ cli_writen at CLAMAV_PRIVATE 0.101.2
+ decodeLine at CLAMAV_PRIVATE 0.101.2
+ disasmbuf at CLAMAV_PRIVATE 0.101.2
+ fmap at CLAMAV_PRIVATE 0.101.2
+ get_fpu_endian at CLAMAV_PRIVATE 0.101.2
+ have_clamjit at CLAMAV_PRIVATE 0.101.2
+ have_rar at CLAMAV_PRIVATE 0.101.2
+ html_normalise_map at CLAMAV_PRIVATE 0.101.2
+ html_normalise_mem at CLAMAV_PRIVATE 0.101.2
+ html_screnc_decode at CLAMAV_PRIVATE 0.101.2
+ html_tag_arg_free at CLAMAV_PRIVATE 0.101.2
+ init_domainlist at CLAMAV_PRIVATE 0.101.2
+ init_regex_list at CLAMAV_PRIVATE 0.101.2
+ init_whitelist at CLAMAV_PRIVATE 0.101.2
+ is_regex_ok at CLAMAV_PRIVATE 0.101.2
+ load_regex_matcher at CLAMAV_PRIVATE 0.101.2
lsig_sub_matched at CLAMAV_PUBLIC 0.101.0
- messageCreate at CLAMAV_PRIVATE 0.101.1
- messageDestroy at CLAMAV_PRIVATE 0.101.1
- mpool_calloc at CLAMAV_PRIVATE 0.101.1
- mpool_create at CLAMAV_PRIVATE 0.101.1
- mpool_destroy at CLAMAV_PRIVATE 0.101.1
- mpool_free at CLAMAV_PRIVATE 0.101.1
- mpool_getstats at CLAMAV_PRIVATE 0.101.1
- phishingScan at CLAMAV_PRIVATE 0.101.1
- phishing_done at CLAMAV_PRIVATE 0.101.1
- phishing_init at CLAMAV_PRIVATE 0.101.1
- regex_list_add_pattern at CLAMAV_PRIVATE 0.101.1
- regex_list_done at CLAMAV_PRIVATE 0.101.1
- regex_list_match at CLAMAV_PRIVATE 0.101.1
- tableCreate at CLAMAV_PRIVATE 0.101.1
- tableDestroy at CLAMAV_PRIVATE 0.101.1
- tableFind at CLAMAV_PRIVATE 0.101.1
- tableInsert at CLAMAV_PRIVATE 0.101.1
- tableIterate at CLAMAV_PRIVATE 0.101.1
- tableRemove at CLAMAV_PRIVATE 0.101.1
- tableUpdate at CLAMAV_PRIVATE 0.101.1
- text_normalize_init at CLAMAV_PRIVATE 0.101.1
- text_normalize_map at CLAMAV_PRIVATE 0.101.1
- text_normalize_reset at CLAMAV_PRIVATE 0.101.1
- uniq_add at CLAMAV_PRIVATE 0.101.1
- uniq_free at CLAMAV_PRIVATE 0.101.1
- uniq_get at CLAMAV_PRIVATE 0.101.1
- uniq_init at CLAMAV_PRIVATE 0.101.1
+ messageCreate at CLAMAV_PRIVATE 0.101.2
+ messageDestroy at CLAMAV_PRIVATE 0.101.2
+ mpool_calloc at CLAMAV_PRIVATE 0.101.2
+ mpool_create at CLAMAV_PRIVATE 0.101.2
+ mpool_destroy at CLAMAV_PRIVATE 0.101.2
+ mpool_free at CLAMAV_PRIVATE 0.101.2
+ mpool_getstats at CLAMAV_PRIVATE 0.101.2
+ phishingScan at CLAMAV_PRIVATE 0.101.2
+ phishing_done at CLAMAV_PRIVATE 0.101.2
+ phishing_init at CLAMAV_PRIVATE 0.101.2
+ regex_list_add_pattern at CLAMAV_PRIVATE 0.101.2
+ regex_list_done at CLAMAV_PRIVATE 0.101.2
+ regex_list_match at CLAMAV_PRIVATE 0.101.2
+ tableCreate at CLAMAV_PRIVATE 0.101.2
+ tableDestroy at CLAMAV_PRIVATE 0.101.2
+ tableFind at CLAMAV_PRIVATE 0.101.2
+ tableInsert at CLAMAV_PRIVATE 0.101.2
+ tableIterate at CLAMAV_PRIVATE 0.101.2
+ tableRemove at CLAMAV_PRIVATE 0.101.2
+ tableUpdate at CLAMAV_PRIVATE 0.101.2
+ text_normalize_init at CLAMAV_PRIVATE 0.101.2
+ text_normalize_map at CLAMAV_PRIVATE 0.101.2
+ text_normalize_reset at CLAMAV_PRIVATE 0.101.2
+ uniq_add at CLAMAV_PRIVATE 0.101.2
+ uniq_free at CLAMAV_PRIVATE 0.101.2
+ uniq_get at CLAMAV_PRIVATE 0.101.2
+ uniq_init at CLAMAV_PRIVATE 0.101.2
diff -Nru clamav-0.101.1+dfsg/debian/rules clamav-0.101.2+dfsg/debian/rules
--- clamav-0.101.1+dfsg/debian/rules 2019-01-09 23:32:24.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/rules 2019-03-30 16:25:48.000000000 +0100
@@ -142,9 +142,6 @@
T=900 dh_auto_test -- V=1 VERBOSE=1
endif
-override_dh_strip:
- dh_strip --dbgsym-migration=clamav-dbg
-
override_dh_install:
dh_install
dh_apparmor -pclamav-freshclam --profile-name=usr.bin.freshclam
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_dbload_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_dbload_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_dbload_fuzzer.cpp 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_dbload_fuzzer.cpp 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,136 @@
+/*
+ * Fuzz target for cl_load()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder
+ *
+ * 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "clamav.h"
+
+void clamav_message_callback(enum cl_msg severity, const char* fullmsg,
+ const char* msg, void* context)
+{
+}
+
+class ClamAVState
+{
+ public:
+ ClamAVState()
+ {
+ // Silence all the log messages, none of them are meaningful.
+ cl_set_clcb_msg(clamav_message_callback);
+
+ cl_init(CL_INIT_DEFAULT);
+ engine = cl_engine_new();
+ cl_engine_compile(engine);
+
+ tmp_db_name = NULL;
+ }
+
+ ~ClamAVState()
+ {
+ cl_engine_free(engine);
+
+ if (NULL != tmp_db_name) {
+ unlink(tmp_db_name);
+ }
+ }
+
+ struct cl_engine* engine;
+ const char* tmp_db_name;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ unsigned int sigs = 0;
+ FILE* fuzzdb = NULL;
+
+ unsigned int dboptions =
+ CL_DB_PHISHING | CL_DB_PHISHING_URLS |
+ CL_DB_BYTECODE | CL_DB_BYTECODE_UNSIGNED |
+ CL_DB_PUA | CL_DB_ENHANCED;
+
+#if defined(CLAMAV_FUZZ_CDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.cdb";
+#elif defined(CLAMAV_FUZZ_CFG)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.cfg";
+#elif defined(CLAMAV_FUZZ_CRB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.crb";
+#elif defined(CLAMAV_FUZZ_FP)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.fp";
+#elif defined(CLAMAV_FUZZ_FTM)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ftm";
+#elif defined(CLAMAV_FUZZ_HDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.hdb";
+#elif defined(CLAMAV_FUZZ_HSB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.hsb";
+#elif defined(CLAMAV_FUZZ_IDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.idb";
+#elif defined(CLAMAV_FUZZ_IGN)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ign";
+#elif defined(CLAMAV_FUZZ_IGN2)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ign2";
+#elif defined(CLAMAV_FUZZ_LDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ldb";
+#elif defined(CLAMAV_FUZZ_MDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.mdb";
+#elif defined(CLAMAV_FUZZ_MSB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.msb";
+#elif defined(CLAMAV_FUZZ_NDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ndb";
+#elif defined(CLAMAV_FUZZ_PDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.pdb";
+#elif defined(CLAMAV_FUZZ_WDB)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.wdb";
+#elif defined(CLAMAV_FUZZ_YARA)
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz.yara";
+#else
+ kClamAVState.tmp_db_name = "dbload_tmp_fuzz";
+#endif
+
+ fuzzdb = fopen(kClamAVState.tmp_db_name, "w");
+ fwrite(data, size, 1, fuzzdb);
+ fclose(fuzzdb);
+
+ cl_load(
+ kClamAVState.tmp_db_name,
+ kClamAVState.engine,
+ &sigs,
+ dboptions);
+
+ return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_scanfile_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_scanfile_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_scanfile_fuzzer.cpp 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_scanfile_fuzzer.cpp 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,135 @@
+/*
+ * Fuzz target for cl_scanfile()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder, Alex Gaynor
+ *
+ * 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "clamav.h"
+
+void clamav_message_callback(enum cl_msg severity, const char* fullmsg,
+ const char* msg, void* context)
+{
+}
+
+class ClamAVState
+{
+ public:
+ ClamAVState()
+ {
+ // Silence all the log messages, none of them are meaningful.
+ cl_set_clcb_msg(clamav_message_callback);
+
+ cl_init(CL_INIT_DEFAULT);
+ engine = cl_engine_new();
+ cl_engine_compile(engine);
+
+ tmp_file_name = NULL;
+ }
+
+ ~ClamAVState()
+ {
+ cl_engine_free(engine);
+
+ if (NULL != tmp_file_name) {
+ unlink(tmp_file_name);
+ }
+ }
+
+ struct cl_engine* engine;
+ const char* tmp_file_name;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+ FILE* fuzzfile = NULL;
+ struct cl_scan_options scanopts = {0};
+
+ memset(&scanopts, 0, sizeof(struct cl_scan_options));
+
+#if defined(CLAMAV_FUZZ_ARCHIVE)
+ kClamAVState.tmp_file_name = "tmp.scanfile.archive";
+ scanopts.parse |= CL_SCAN_PARSE_ARCHIVE;
+#elif defined(CLAMAV_FUZZ_MAIL)
+ kClamAVState.tmp_file_name = "tmp.scanfile.eml";
+ scanopts.parse |= CL_SCAN_PARSE_MAIL;
+#elif defined(CLAMAV_FUZZ_OLE2)
+ kClamAVState.tmp_file_name = "tmp.scanfile.ole2";
+ scanopts.parse |= CL_SCAN_PARSE_OLE2;
+#elif defined(CLAMAV_FUZZ_PDF)
+ kClamAVState.tmp_file_name = "tmp.scanfile.pdf";
+ scanopts.parse |= CL_SCAN_PARSE_PDF;
+#elif defined(CLAMAV_FUZZ_HTML)
+ kClamAVState.tmp_file_name = "tmp.scanfile.html";
+ scanopts.parse |= CL_SCAN_PARSE_HTML;
+#elif defined(CLAMAV_FUZZ_PE)
+ kClamAVState.tmp_file_name = "tmp.scanfile.pe";
+ scanopts.parse |= CL_SCAN_PARSE_PE;
+#elif defined(CLAMAV_FUZZ_ELF)
+ kClamAVState.tmp_file_name = "tmp.scanfile.elf";
+ scanopts.parse |= CL_SCAN_PARSE_ELF;
+#elif defined(CLAMAV_FUZZ_SWF)
+ kClamAVState.tmp_file_name = "tmp.scanfile.swf";
+ scanopts.parse |= CL_SCAN_PARSE_SWF;
+#elif defined(CLAMAV_FUZZ_XMLDOCS)
+ kClamAVState.tmp_file_name = "tmp.scanfile.docx";
+ scanopts.parse |= CL_SCAN_PARSE_XMLDOCS;
+#elif defined(CLAMAV_FUZZ_HWP3)
+ kClamAVState.tmp_file_name = "tmp.scanfile.hwp";
+ scanopts.parse |= CL_SCAN_PARSE_HWP3;
+#else
+ kClamAVState.tmp_file_name = "tmp.scanfile";
+ scanopts.parse |= ~(0);
+#endif
+ scanopts.general |= CL_SCAN_GENERAL_HEURISTICS;
+
+ fuzzfile = fopen(kClamAVState.tmp_file_name, "w");
+ fwrite(data, size, 1, fuzzfile);
+ fclose(fuzzfile);
+
+ const char* virus_name = nullptr;
+ unsigned long scanned = 0;
+ cl_scanfile(
+ kClamAVState.tmp_file_name,
+ &virus_name,
+ &scanned,
+ kClamAVState.engine,
+ &scanopts);
+
+ return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_scanmap_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_scanmap_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_scanmap_fuzzer.cpp 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_scanmap_fuzzer.cpp 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,117 @@
+/*
+ * Fuzz target for cl_scanmap_callback()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder, Alex Gaynor
+ *
+ * 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "clamav.h"
+
+
+void clamav_message_callback(enum cl_msg severity, const char *fullmsg,
+ const char *msg, void *context) {
+}
+
+class ClamAVState {
+public:
+ ClamAVState() {
+ // Silence all the log messages, none of them are meaningful.
+ cl_set_clcb_msg(clamav_message_callback);
+
+ cl_init(CL_INIT_DEFAULT);
+ engine = cl_engine_new();
+ cl_engine_compile(engine);
+ }
+
+ ~ClamAVState() {
+ cl_engine_free(engine);
+ }
+
+ struct cl_engine *engine;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+
+ struct cl_scan_options scanopts = {0};
+
+ cl_fmap_t *clamav_data = cl_fmap_open_memory(data, size);
+
+ memset(&scanopts, 0, sizeof(struct cl_scan_options));
+
+ scanopts.parse |=
+#if defined(CLAMAV_FUZZ_ARCHIVE)
+ CL_SCAN_PARSE_ARCHIVE;
+#elif defined(CLAMAV_FUZZ_MAIL)
+ CL_SCAN_PARSE_MAIL;
+#elif defined(CLAMAV_FUZZ_OLE2)
+ CL_SCAN_PARSE_OLE2;
+#elif defined(CLAMAV_FUZZ_PDF)
+ CL_SCAN_PARSE_PDF;
+#elif defined(CLAMAV_FUZZ_HTML)
+ CL_SCAN_PARSE_HTML;
+#elif defined(CLAMAV_FUZZ_PE)
+ CL_SCAN_PARSE_PE;
+#elif defined(CLAMAV_FUZZ_ELF)
+ CL_SCAN_PARSE_ELF;
+#elif defined(CLAMAV_FUZZ_SWF)
+ CL_SCAN_PARSE_SWF;
+#elif defined(CLAMAV_FUZZ_XMLDOCS)
+ CL_SCAN_PARSE_XMLDOCS;
+#elif defined(CLAMAV_FUZZ_HWP3)
+ CL_SCAN_PARSE_HWP3;
+#else
+ ~(0);
+#endif
+
+ scanopts.general |= CL_SCAN_GENERAL_HEURISTICS;
+
+ const char *virus_name = nullptr;
+ unsigned long scanned = 0;
+ cl_scanmap_callback(
+ clamav_data,
+ NULL,
+ &virus_name,
+ &scanned,
+ kClamAVState.engine,
+ &scanopts,
+ nullptr
+ );
+
+ cl_fmap_close(clamav_data);
+
+ return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/Makefile.am clamav-0.101.2+dfsg/fuzz/Makefile.am
--- clamav-0.101.1+dfsg/fuzz/Makefile.am 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/Makefile.am 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,247 @@
+# Process this file with automake to produce Makefile.in
+
+# By default, use our own standalone_fuzz_target_runner.
+# This runner does no fuzzing, but simply executes the inputs
+# provided via parameters.
+# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
+# to link the fuzzer(s) against a real fuzzing engine.
+#
+# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
+
+if ENABLE_FUZZ
+
+LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.a
+
+AM_CPPFLAGS = \
+ @SSL_CPPFLAGS@ \
+ -I$(top_srcdir) -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav \
+ -std=c++11 -stdlib=libc++
+
+AM_LDFLAGS = \
+ @SSL_LDFLAGS@
+
+fuzzdir = "fuzz-targets"
+
+fuzz_PROGRAMS = \
+ clamav_scanmap_fuzzer \
+ clamav_scanmap_ARCHIVE_fuzzer \
+ clamav_scanmap_MAIL_fuzzer \
+ clamav_scanmap_OLE2_fuzzer \
+ clamav_scanmap_PDF_fuzzer \
+ clamav_scanmap_HTML_fuzzer \
+ clamav_scanmap_PE_fuzzer \
+ clamav_scanmap_ELF_fuzzer \
+ clamav_scanmap_SWF_fuzzer \
+ clamav_scanmap_XMLDOCS_fuzzer \
+ clamav_scanmap_HWP3_fuzzer \
+ clamav_scanfile_fuzzer \
+ clamav_scanfile_ARCHIVE_fuzzer \
+ clamav_scanfile_MAIL_fuzzer \
+ clamav_scanfile_OLE2_fuzzer \
+ clamav_scanfile_PDF_fuzzer \
+ clamav_scanfile_HTML_fuzzer \
+ clamav_scanfile_PE_fuzzer \
+ clamav_scanfile_ELF_fuzzer \
+ clamav_scanfile_SWF_fuzzer \
+ clamav_scanfile_XMLDOCS_fuzzer \
+ clamav_scanfile_HWP3_fuzzer \
+ clamav_dbload_CDB_fuzzer \
+ clamav_dbload_CFG_fuzzer \
+ clamav_dbload_CRB_fuzzer \
+ clamav_dbload_FP_fuzzer \
+ clamav_dbload_FTM_fuzzer \
+ clamav_dbload_HDB_fuzzer \
+ clamav_dbload_HSB_fuzzer \
+ clamav_dbload_IDB_fuzzer \
+ clamav_dbload_IGN_fuzzer \
+ clamav_dbload_IGN2_fuzzer \
+ clamav_dbload_LDB_fuzzer \
+ clamav_dbload_MDB_fuzzer \
+ clamav_dbload_MSB_fuzzer \
+ clamav_dbload_NDB_fuzzer \
+ clamav_dbload_PDB_fuzzer \
+ clamav_dbload_WDB_fuzzer \
+ clamav_dbload_YARA_fuzzer
+
+dist_standalone_fuzz_target_runner_a_SOURCES = standalone_fuzz_target_runner.cpp
+noinst_LIBRARIES = standalone_fuzz_target_runner.a
+
+dist_clamav_scanmap_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+
+dist_clamav_scanmap_ARCHIVE_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_ARCHIVE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_ARCHIVE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ARCHIVE $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_MAIL_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_MAIL_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_MAIL_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MAIL $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_OLE2_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_OLE2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_OLE2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_OLE2 $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_PDF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_PDF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_PDF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_HTML_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_HTML_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_HTML_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HTML $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_PE_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_PE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_PE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PE $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_ELF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_ELF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_ELF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ELF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_SWF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_SWF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_SWF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_SWF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_XMLDOCS_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_XMLDOCS_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_XMLDOCS_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_XMLDOCS $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_HWP3_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_HWP3_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_HWP3_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HWP3 $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+
+dist_clamav_scanfile_ARCHIVE_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_ARCHIVE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_ARCHIVE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ARCHIVE $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_MAIL_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_MAIL_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_MAIL_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MAIL $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_OLE2_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_OLE2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_OLE2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_OLE2 $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_PDF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_PDF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_PDF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_HTML_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_HTML_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_HTML_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HTML $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_PE_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_PE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_PE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PE $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_ELF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_ELF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_ELF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ELF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_SWF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_SWF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_SWF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_SWF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_XMLDOCS_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_XMLDOCS_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_XMLDOCS_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_XMLDOCS $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_HWP3_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_HWP3_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_HWP3_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HWP3 $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CFG_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CFG_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CFG_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CFG $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CRB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CRB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CRB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CRB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_FP_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_FP_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_FP_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_FP $(AM_CPPFLAGS)
+
+dist_clamav_dbload_FTM_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_FTM_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_FTM_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_FTM $(AM_CPPFLAGS)
+
+dist_clamav_dbload_HDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_HDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_HDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_HSB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_HSB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_HSB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HSB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IGN_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IGN_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IGN_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IGN $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IGN2_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IGN2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IGN2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IGN2 $(AM_CPPFLAGS)
+
+dist_clamav_dbload_LDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_LDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_LDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_LDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_MDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_MDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_MDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_MSB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_MSB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_MSB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MSB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_NDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_NDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_NDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_NDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_PDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_PDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_PDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_WDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_WDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_WDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_WDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_YARA_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_YARA_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_YARA_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_YARA $(AM_CPPFLAGS)
+
+all: $(LIB_FUZZING_ENGINE)
+
+check: all
+ for type in ARCHIVE MAIL OLE2 PDF HTML PE ELF SWF XMLDOCS HWP3 ; do \
+ builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f clamav_scanmap_fuzzer -c $(top_srcdir)/../clamav-fuzz-corpus/scantype/$$type ; \
+ done
+ for type in ARCHIVE MAIL OLE2 PDF HTML PE ELF SWF XMLDOCS HWP3 ; do \
+ builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f "clamav_scanfile_"$$type"_fuzzer" -c $(top_srcdir)/../clamav-fuzz-corpus/scantype/$$type ; \
+ done
+ for type in CDB CFG CRB FP FTM HDB HSB IDB IGN IGN2 LDB MDB MSB NDB PDB WDB YARA ; do \
+ builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f "clamav_dbload_"$$type"_fuzzer" -c $(top_srcdir)/../clamav-fuzz-corpus/database/$$type ; \
+ done
+
+else
+
+all:
+check:
+ @echo "Building fuzz targets is not enabled"
+ @echo "Use: ./configure --enable-fuzz --with-libjson=no --with-pcre=no --enable-static=yes --enable-shared=no --disable-llvm"
+ @exit 1
+
+endif
+
+CLEANFILES = *.gcda *.gcno
+EXTRA_DIST = README.md run_fuzzer_tests.py
diff -Nru clamav-0.101.1+dfsg/fuzz/README.md clamav-0.101.2+dfsg/fuzz/README.md
--- clamav-0.101.1+dfsg/fuzz/README.md 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/README.md 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,20 @@
+# OSS-Fuzz
+
+ClamAV has chosen to integrate with [oss-fuzz](https://github.com/google/oss-fuzz).
+
+What this means is that this repository includes:
+
+- Fuzz targets:
+ - A function to which we apply fuzzing.
+ - For ClamAV, clamav_scanfile_fuzzer.cc may be compiled with specific macros defined to produce multiple fuzz targets.
+ - Additional fuzz targets may be added to fuzz other ClamAV inputs.
+
+- Seed corpora:
+ - A set of minimal test inputs that generate maximal code coverage.
+ - Each ClamAV fuzz target has a seed corpus located under: fuzz/corpus/<target>
+
+- Fuzzing dictionaries:
+ - A simple dictionary of tokens used by the input language. This can have a dramatic positive effect on fuzzing efficiency. For example, when fuzzing an XML parser, a dictionary of XML tokens will help.
+ - Some ClamAV fuzz targets have a dictionary located under: fuzz/dictionaries/<target>.dict
+
+For more information on how this is set up, see: [ideal OSS-Fuzz integration](https://github.com/google/oss-fuzz/blob/master/docs/ideal_integration.md)
diff -Nru clamav-0.101.1+dfsg/fuzz/run_fuzzer_tests.py clamav-0.101.2+dfsg/fuzz/run_fuzzer_tests.py
--- clamav-0.101.1+dfsg/fuzz/run_fuzzer_tests.py 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/run_fuzzer_tests.py 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+# Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+
+'''
+This script is a convenience tool to run a standalone fuzz target against each
+item in its associated fuzz corpus.
+'''
+
+from __future__ import print_function, division, absolute_import
+
+import argparse
+import os
+import subprocess
+import sys
+import tempfile
+import threading
+
+def which(program):
+ '''
+ Implements bash "which" feature.
+ Find the full path to a program located in the PATH.
+
+ https://stackoverflow.com/a/377028
+ '''
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ fpath, _ = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ return None
+
+def cmd(command):
+ '''
+ Run a command in a subprocess.
+
+ https://stackoverflow.com/a/4408409
+ https://stackoverflow.com/a/10012262
+ '''
+ with tempfile.TemporaryFile() as tempf:
+ p = subprocess.Popen(command, stderr=tempf)
+ is_killed = {'value': False}
+
+ def timeout(p, is_killed):
+ is_killed['value'] = True
+ p.kill()
+
+ timer = threading.Timer(2, timeout, [p, is_killed])
+
+ try:
+ timer.start()
+ p.wait()
+ tempf.seek(0)
+ text = tempf.read().decode("utf-8").strip()
+ returncode = p.returncode
+ finally:
+ timer.cancel()
+
+ if is_killed['value']:
+ text = 'error: timeout, ' + text
+ returncode = 1
+
+ return text, returncode
+
+def run_test(fuzzer, corpus_path):
+ '''
+ Test a standalone fuzz target with each item from the fuzz corpus.
+ '''
+ builddir = os.environ.get("builddir", ".")
+ fuzz_target = os.path.join(builddir, fuzzer)
+
+ print("Fuzz Target: {fuzzer}".format(fuzzer=fuzzer))
+ print("Corpus Path: {corpus_path}".format(corpus_path=corpus_path))
+
+ if not os.path.exists(fuzz_target):
+ print("Failed to find fuzz target: {binary}!".format(binary=fuzz_target))
+ sys.exit(1)
+
+ failures = 0
+
+ valgrind = None
+ if os.environ.get('VG', ''):
+ valgrind = which('valgrind')
+
+ for fname in os.listdir(corpus_path):
+ seedpath = os.path.join(corpus_path, fname)
+
+ text, returncode = cmd([fuzz_target, seedpath])
+ if text.strip():
+ print(text)
+
+ failed = False
+ if returncode != 0 or 'error' in text:
+ print('failure on %s' % fname)
+ failed = True
+
+ if valgrind:
+ text, returncode = cmd(
+ [valgrind, '--error-exitcode=1', fuzz_target, seedpath])
+ if returncode:
+ print(text)
+ print('failure on %s' % fname)
+ failed = True
+
+ if failed:
+ failures = failures + 1
+
+ if failures:
+ print("%i scanfile fuzzer related tests failed." % failures)
+ sys.exit(1)
+
+def main():
+ '''
+ Get command line options to support this tool.
+ '''
+ parser = argparse.ArgumentParser(description=__doc__)
+
+ parser.add_argument(
+ '-f',
+ '--fuzzer',
+ required=True,
+ help="The fuzz target to test.")
+ parser.add_argument(
+ '-c',
+ '--corpus',
+ required=True,
+ help="Path of the fuzz corpus.")
+
+ args = parser.parse_args()
+
+ run_test(args.fuzzer, args.corpus)
+
+if __name__ == '__main__':
+ main()
diff -Nru clamav-0.101.1+dfsg/fuzz/standalone_fuzz_target_runner.cpp clamav-0.101.2+dfsg/fuzz/standalone_fuzz_target_runner.cpp
--- clamav-0.101.1+dfsg/fuzz/standalone_fuzz_target_runner.cpp 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/standalone_fuzz_target_runner.cpp 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,35 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0 (the "License");
+
+// Example of a standalone runner for "fuzz targets".
+// It reads all files passed as parameters and feeds their contents
+// one by one into the fuzz target (LLVMFuzzerTestOneInput).
+// This runner does not do any fuzzing, but allows us to run the fuzz target
+// on the test corpus (e.g. "do_stuff_test_data") or on a single file,
+// e.g. the one that comes from a bug report.
+
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+// Forward declare the "fuzz target" interface.
+// We deliberately keep this inteface simple and header-free.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int main(int argc, char **argv) {
+ for (int i = 1; i < argc; i++) {
+ std::ifstream in(argv[i]);
+ in.seekg(0, in.end);
+ size_t length = in.tellg();
+ in.seekg (0, in.beg);
+ std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
+ // Allocate exactly length bytes so that we reliably catch buffer overflows.
+ std::vector<char> bytes(length);
+ in.read(bytes.data(), bytes.size());
+ assert(in);
+ LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
+ bytes.size());
+ std::cout << "Execution successful" << std::endl;
+ }
+}
\ No newline at end of file
diff -Nru clamav-0.101.1+dfsg/libclamav/7z/Xz.c clamav-0.101.2+dfsg/libclamav/7z/Xz.c
--- clamav-0.101.1+dfsg/libclamav/7z/Xz.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/7z/Xz.c 2019-03-13 22:13:01.000000000 +0100
@@ -93,6 +93,7 @@
return 0;
cl_finish_hash(p->sha, digest);
+ p->sha = NULL;
break;
default:
return 0;
diff -Nru clamav-0.101.1+dfsg/libclamav/7z/XzDec.c clamav-0.101.2+dfsg/libclamav/7z/XzDec.c
--- clamav-0.101.1+dfsg/libclamav/7z/XzDec.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/7z/XzDec.c 2019-03-13 22:13:01.000000000 +0100
@@ -614,7 +614,11 @@
void XzUnpacker_Free(CXzUnpacker *p)
{
+ if (!p)
+ return;
MixCoder_Free(&p->decoder);
+ cl_hash_destroy(p->sha);
+ p->sha = NULL;
}
SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
@@ -816,8 +820,10 @@
p->state = XZ_STATE_STREAM_INDEX_CRC;
p->indexSize += 4;
p->pos = 0;
- if ((p->sha))
+ if ((p->sha)) {
cl_finish_hash(p->sha, digest);
+ p->sha = NULL;
+ }
if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
return SZ_ERROR_CRC;
diff -Nru clamav-0.101.1+dfsg/libclamav/aspack.c clamav-0.101.2+dfsg/libclamav/aspack.c
--- clamav-0.101.1+dfsg/libclamav/aspack.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/aspack.c 2019-03-13 22:13:01.000000000 +0100
@@ -395,7 +395,9 @@
for (i = 0; i < 58; i++) {
stream.init_array[i] = j;
- j += ( 1 << image[ep+i+stream_init_multiplier_offset]); /* boundchecked in pe.c */
+ if (ep + i + stream_init_multiplier_offset < size) {
+ j += (1 << image[ep + i + stream_init_multiplier_offset]);
+ }
}
memset(stream.array1,0,sizeof(stream.array1));
diff -Nru clamav-0.101.1+dfsg/libclamav/clamav.h clamav-0.101.2+dfsg/libclamav/clamav.h
--- clamav-0.101.1+dfsg/libclamav/clamav.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/clamav.h 2019-03-13 22:13:01.000000000 +0100
@@ -157,10 +157,11 @@
};
/* general */
-#define CL_SCAN_GENERAL_ALLMATCHES 0x1 /* scan in all-match mode */
-#define CL_SCAN_GENERAL_COLLECT_METADATA 0x2 /* collect metadata (--gen-json) */
-#define CL_SCAN_GENERAL_HEURISTICS 0x4 /* option to enable heuristic alerts */
-#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE 0x8 /* allow heuristic match to take precedence. */
+#define CL_SCAN_GENERAL_ALLMATCHES 0x1 /* scan in all-match mode */
+#define CL_SCAN_GENERAL_COLLECT_METADATA 0x2 /* collect metadata (--gen-json) */
+#define CL_SCAN_GENERAL_HEURISTICS 0x4 /* option to enable heuristic alerts */
+#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE 0x8 /* allow heuristic match to take precedence. */
+#define CL_SCAN_GENERAL_UNPRIVILEGED 0x10 /* scanner will not have read access to files. */
/* parsing capabilities options */
#define CL_SCAN_PARSE_ARCHIVE 0x1
diff -Nru clamav-0.101.1+dfsg/libclamav/cpio.c clamav-0.101.2+dfsg/libclamav/cpio.c
--- clamav-0.101.1+dfsg/libclamav/cpio.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/cpio.c 2019-03-13 22:13:01.000000000 +0100
@@ -146,7 +146,7 @@
} else if(hdr_namesize % 2)
pos++;
}
- filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv));
+ filesize = (uint32_t)((uint32_t)EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv));
cli_dbgmsg("CPIO: Filesize: %u\n", filesize);
if(!filesize)
continue;
diff -Nru clamav-0.101.1+dfsg/libclamav/htmlnorm.c clamav-0.101.2+dfsg/libclamav/htmlnorm.c
--- clamav-0.101.1+dfsg/libclamav/htmlnorm.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/htmlnorm.c 2019-03-13 22:13:01.000000000 +0100
@@ -1,10 +1,10 @@
/*
- * Copyright (C) 2015, 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2007-2013 Sourcefire, Inc.
*
* Authors: Trog
- *
- * Summary: Normalise HTML text. Decode MS Script Encoder protection.
+ *
+ * Summary: Normalise HTML text. Decode MS Script Encoder protection.
* The ScrEnc decoder was initially based upon an analysis by Andreas Marx.
*
* This program is free software; you can redistribute it and/or modify
@@ -100,7 +100,7 @@
unsigned char contents[MAX_TAG_CONTENTS_LENGTH + 1];
};
-static const int base64_chars[256] = {
+static const int32_t base64_chars[256] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
@@ -590,29 +590,29 @@
}
}
ptr++;
- s->length--;
- }
- if(!s->length) {
- size_t remaining;
- if(strlen((const char*)ptr) >= 12) {
- uint32_t expected;
- expected = base64_chars[ptr[0]] << 2;
- expected += base64_chars[ptr[1]] >> 4;
- expected += (base64_chars[ptr[1]] & 0x0f) << 12;
- expected += (base64_chars[ptr[2]] >> 2) << 8;
- expected += (base64_chars[ptr[2]] & 0x03) << 22;
- expected += base64_chars[ptr[3]] << 16;
- expected += (base64_chars[ptr[4]] << 2) << 24;
- expected += (base64_chars[ptr[5]] >> 4) << 24;
- ptr += 8;
- if(s->sum != expected) {
- cli_dbgmsg("screnc_decode: checksum mismatch: %u != %u\n", s->sum, expected);
- } else {
- if(strncmp((const char*)ptr, "^#~@", 4) != 0) {
- cli_dbgmsg("screnc_decode: terminator not found\n");
- } else {
- cli_dbgmsg("screnc_decode: OK\n");
- }
+ s->length--;
+ }
+ if(!s->length) {
+ size_t remaining;
+ if(strlen((const char*)ptr) >= 12) {
+ uint32_t expected;
+ expected = base64_chars[ptr[0]] < 0 ? 0 : base64_chars[ptr[0]] << 2;
+ expected += base64_chars[ptr[1]] >> 4;
+ expected += (base64_chars[ptr[1]] & 0x0f) << 12;
+ expected += ((base64_chars[ptr[2]] >> 2) < 0 ? 0 : (base64_chars[ptr[2]] >> 2)) << 8;
+ expected += (base64_chars[ptr[2]] & 0x03) << 22;
+ expected += base64_chars[ptr[3]] < 0 ? 0 : base64_chars[ptr[3]] << 16;
+ expected += (base64_chars[ptr[4]] < 0 ? 0 : base64_chars[ptr[4]] << 2) << 24;
+ expected += ((base64_chars[ptr[5]] >> 4) < 0 ? 0 : (base64_chars[ptr[5]] >> 4)) << 24;
+ ptr += 8;
+ if(s->sum != expected) {
+ cli_dbgmsg("screnc_decode: checksum mismatch: %u != %u\n", s->sum, expected);
+ } else {
+ if(strncmp((const char*)ptr, "^#~@", 4) != 0) {
+ cli_dbgmsg("screnc_decode: terminator not found\n");
+ } else {
+ cli_dbgmsg("screnc_decode: OK\n");
+ }
}
ptr += 4;
}
@@ -647,7 +647,7 @@
static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag_arguments_t *hrefs,const struct cli_dconf* dconf)
{
int fd_tmp, tag_length = 0, tag_arg_length = 0, binary;
- int retval=FALSE, escape=FALSE, value = 0, hex=FALSE, tag_val_length=0;
+ int64_t retval = FALSE, escape = FALSE, value = 0, hex = FALSE, tag_val_length = 0;
int look_for_screnc=FALSE, in_screnc=FALSE,in_script=FALSE, text_space_written=FALSE;
FILE *stream_in = NULL;
html_state state=HTML_NORM, next_state=HTML_BAD_STATE, saved_next_state=HTML_BAD_STATE;
@@ -684,7 +684,7 @@
cli_dbgmsg("Invalid HTML fd\n");
return FALSE;
}
- lseek(fd, 0, SEEK_SET);
+ lseek(fd, 0, SEEK_SET);
fd_tmp = dup(fd);
if (fd_tmp < 0) {
return FALSE;
@@ -1459,10 +1459,16 @@
next_state = HTML_BAD_STATE;
ptr++;
} else if (isdigit(*ptr) || (hex && isxdigit(*ptr))) {
- if (hex) {
+ if (hex && (value >> 32) * 16 < INT32_MAX) {
value *= 16;
- } else {
+ } else if ((value >> 32) * 10 < INT32_MAX) {
value *= 10;
+ } else {
+ html_output_c(file_buff_o2, value);
+ state = next_state;
+ next_state = HTML_BAD_STATE;
+ ptr++;
+ break;
}
if (isdigit(*ptr)) {
value += (*ptr - '0');
@@ -1504,28 +1510,28 @@
if (strlen((const char*)ptr) < 8) {
state = HTML_NORM;
next_state = HTML_BAD_STATE;
- break;
- }
- memset(&screnc_state, 0, sizeof(screnc_state));
- screnc_state.length = base64_chars[ptr[0]] << 2;
- screnc_state.length += base64_chars[ptr[1]] >> 4;
- screnc_state.length += (base64_chars[ptr[1]] & 0x0f) << 12;
- screnc_state.length += (base64_chars[ptr[2]] >> 2) << 8;
- screnc_state.length += (base64_chars[ptr[2]] & 0x03) << 22;
- screnc_state.length += base64_chars[ptr[3]] << 16;
- screnc_state.length += (base64_chars[ptr[4]] << 2) << 24;
- screnc_state.length += (base64_chars[ptr[5]] >> 4) << 24;
- state = HTML_JSDECODE_DECRYPT;
- in_screnc = TRUE;
- next_state = HTML_BAD_STATE;
- /* for JS normalizer */
- ptr[7] = '\n';
- ptr += 8;
- break;
- case HTML_JSDECODE_DECRYPT:
- screnc_decode(ptr, &screnc_state);
- if(!screnc_state.length) {
- state = HTML_NORM;
+ break;
+ }
+ memset(&screnc_state, 0, sizeof(screnc_state));
+ screnc_state.length = base64_chars[ptr[0]] < 0 ? 0 : base64_chars[ptr[0]] << 2;
+ screnc_state.length += base64_chars[ptr[1]] >> 4;
+ screnc_state.length += (base64_chars[ptr[1]] & 0x0f) << 12;
+ screnc_state.length += ((base64_chars[ptr[2]] >> 2) < 0 ? 0 : (base64_chars[ptr[2]] >> 2)) << 8;
+ screnc_state.length += (base64_chars[ptr[2]] & 0x03) << 22;
+ screnc_state.length += base64_chars[ptr[3]] < 0 ? 0 : base64_chars[ptr[3]] << 16;
+ screnc_state.length += (base64_chars[ptr[4]] < 0 ? 0 : base64_chars[ptr[4]] << 2) << 24;
+ screnc_state.length += ((base64_chars[ptr[5]] >> 4) < 0 ? 0 : (base64_chars[ptr[5]] >> 4)) << 24;
+ state = HTML_JSDECODE_DECRYPT;
+ in_screnc = TRUE;
+ next_state = HTML_BAD_STATE;
+ /* for JS normalizer */
+ ptr[7] = '\n';
+ ptr += 8;
+ break;
+ case HTML_JSDECODE_DECRYPT:
+ screnc_decode(ptr, &screnc_state);
+ if(!screnc_state.length) {
+ state = HTML_NORM;
next_state = HTML_BAD_STATE;
in_screnc = FALSE;
break;
@@ -1603,6 +1609,15 @@
break;
case HTML_RFC2397_INIT:
if (dirname) {
+ if (NULL != file_tmp_o1) {
+ if (file_tmp_o1->fd != -1) {
+ html_output_flush(file_tmp_o1);
+ close(file_tmp_o1->fd);
+ file_tmp_o1->fd = -1;
+ }
+ free(file_tmp_o1);
+ }
+
file_tmp_o1 = (file_buff_t *) cli_malloc(sizeof(file_buff_t));
if (!file_tmp_o1) {
cli_errmsg("cli_html_normalise: Unable to allocate memory for file_tmp_o1\n");
@@ -1686,8 +1701,11 @@
break;
case HTML_RFC2397_FINISH:
if(file_tmp_o1) {
+ if (file_tmp_o1->fd != -1) {
html_output_flush(file_tmp_o1);
close(file_tmp_o1->fd);
+ file_tmp_o1->fd = -1;
+ }
free(file_tmp_o1);
file_tmp_o1 = NULL;
}
@@ -1709,7 +1727,14 @@
state = HTML_RFC2397_DATA;
break;
case HTML_ESCAPE_CHAR:
+ if ((value >> 32) * 16 < INT32_MAX) {
value *= 16;
+ } else {
+ state = next_state;
+ next_state = HTML_BAD_STATE;
+ ptr++;
+ break;
+ }
length++;
if (isxdigit(*ptr)) {
if (isdigit(*ptr)) {
@@ -1817,9 +1842,10 @@
file_buff_text=NULL;
}
if(file_tmp_o1) {
+ if (file_tmp_o1->fd != -1) {
html_output_flush(file_tmp_o1);
- if(file_tmp_o1 && file_tmp_o1->fd != -1)
close(file_tmp_o1->fd);
+ }
free(file_tmp_o1);
}
return retval;
@@ -1900,17 +1926,16 @@
ptr++;
} while (count < 8);
- memset(&screnc_state, 0, sizeof(screnc_state));
- screnc_state.length = base64_chars[tmpstr[0]] << 2;
- screnc_state.length += base64_chars[tmpstr[1]] >> 4;
- screnc_state.length += (base64_chars[tmpstr[1]] & 0x0f) << 12;
- screnc_state.length += (base64_chars[tmpstr[2]] >> 2) << 8;
- screnc_state.length += (base64_chars[tmpstr[2]] & 0x03) << 22;
- screnc_state.length += base64_chars[tmpstr[3]] << 16;
- screnc_state.length += (base64_chars[tmpstr[4]] << 2) << 24;
- screnc_state.length += (base64_chars[tmpstr[5]] >> 4) << 24;
-
- cli_writen(ofd, "<script>",strlen("<script>"));
+ memset(&screnc_state, 0, sizeof(screnc_state));
+ screnc_state.length = base64_chars[tmpstr[0]] < 0 ? 0 : base64_chars[tmpstr[0]] << 2;
+ screnc_state.length += base64_chars[tmpstr[1]] >> 4;
+ screnc_state.length += (base64_chars[tmpstr[1]] & 0x0f) << 12;
+ screnc_state.length += ((base64_chars[tmpstr[2]] >> 2) < 0 ? 0 : (base64_chars[tmpstr[2]] >> 2)) << 8;
+ screnc_state.length += (base64_chars[tmpstr[2]] & 0x03) << 22;
+ screnc_state.length += base64_chars[tmpstr[3]] < 0 ? 0 : base64_chars[tmpstr[3]] << 16;
+ screnc_state.length += (base64_chars[tmpstr[4]] < 0 ? 0 : base64_chars[tmpstr[4]] << 2) << 24;
+ screnc_state.length += ((base64_chars[tmpstr[5]] >> 4) < 0 ? 0 : (base64_chars[tmpstr[5]] >> 4)) << 24;
+ cli_writen(ofd, "<script>",strlen("<script>"));
while (screnc_state.length && line) {
screnc_decode(ptr, &screnc_state);
cli_writen(ofd, ptr, strlen((const char*)ptr));
diff -Nru clamav-0.101.1+dfsg/libclamav/ole2_extract.c clamav-0.101.2+dfsg/libclamav/ole2_extract.c
--- clamav-0.101.1+dfsg/libclamav/ole2_extract.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/ole2_extract.c 2019-03-13 22:13:01.000000000 +0100
@@ -399,9 +399,14 @@
return FALSE;
}
/* other methods: (blockno+1) * 512 or (blockno * block_size) + 512; */
+ if ((uint64_t) blockno << hdr->log2_big_block_size < INT32_MAX) {
offset = (blockno << hdr->log2_big_block_size) + MAX(512, 1 << hdr->log2_big_block_size); /* 512 is header size */
-
offend = offset + size;
+ } else {
+ offset = INT32_MAX - size;
+ offend = INT32_MAX;
+ }
+
if ((offend <= 0) || (offset < 0) || (offset >= hdr->m_length)) {
return FALSE;
} else if (offend > hdr->m_length) {
@@ -762,10 +767,16 @@
}
else {
ole2_list_delete(&node_list);
+ if (dirname)
+ free(dirname);
return ret;
}
}
}
+ if (dirname) {
+ free(dirname);
+ dirname = NULL;
+ }
if ((int)(prop_block[idx].prev) != -1) {
if ((ret=ole2_list_push(&node_list, prop_block[idx].prev)) != CL_SUCCESS) {
ole2_list_delete(&node_list);
@@ -778,8 +789,6 @@
return ret;
}
}
- if (dirname)
- free(dirname);
break;
default:
cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type);
@@ -813,10 +822,18 @@
return CL_SUCCESS;
}
name = get_property_name2(prop->name, prop->name_size);
- if (name)
- cnt = uniq_add(hdr->U, name, strlen(name), &hash);
- else
- cnt = uniq_add(hdr->U, NULL, 0, &hash);
+ if (name) {
+ if (CL_SUCCESS != uniq_add(hdr->U, name, strlen(name), &hash, &cnt)) {
+ free(name);
+ cli_dbgmsg("OLE2 [handler_writefile]: too many property names added to uniq store.\n");
+ return CL_BREAK;
+ }
+ } else {
+ if (CL_SUCCESS != uniq_add(hdr->U, NULL, 0, &hash, &cnt)) {
+ cli_dbgmsg("OLE2 [handler_writefile]: too many property names added to uniq store.\n");
+ return CL_BREAK;
+ }
+ }
snprintf(newname, sizeof(newname), "%s" PATHSEP "%s_%u", dir, hash, cnt);
newname[sizeof(newname) - 1] = '\0';
cli_dbgmsg("OLE2 [handler_writefile]: Dumping '%s' to '%s'\n", name ? name : "<empty>", newname);
diff -Nru clamav-0.101.1+dfsg/libclamav/others_common.c clamav-0.101.2+dfsg/libclamav/others_common.c
--- clamav-0.101.1+dfsg/libclamav/others_common.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/others_common.c 2019-03-13 22:13:01.000000000 +0100
@@ -29,49 +29,50 @@
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
-#ifdef HAVE_UNISTD_H
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
-#ifndef _WIN32
+#ifndef _WIN32
#include <sys/wait.h>
#include <sys/time.h>
#endif
#include <time.h>
#include <fcntl.h>
-#ifdef HAVE_PWD_H
+#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#include <errno.h>
#include "target.h"
-#ifdef HAVE_SYS_PARAM_H
+#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#ifdef HAVE_MALLOC_H
+#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include "clamav.h"
#include "others.h"
+#include "platform.h"
#include "regex/regex.h"
#include "ltdl.h"
#include "matcher-ac.h"
-static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253 };
+static unsigned char name_salt[16] = {16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253};
#ifdef CL_NOTHREADS
#undef CL_THREAD_SAFE
#endif
#ifdef CL_THREAD_SAFE
-# include <pthread.h>
+#include <pthread.h>
static pthread_mutex_t cli_gentemp_mutex = PTHREAD_MUTEX_INITIALIZER;
-# ifndef HAVE_CTIME_R
+#ifndef HAVE_CTIME_R
static pthread_mutex_t cli_ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
-# endif
+#endif
static pthread_mutex_t cli_strerror_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t cli_ctx_tls_key;
static pthread_once_t cli_ctx_tls_key_once = PTHREAD_ONCE_INIT;
@@ -81,7 +82,7 @@
pthread_key_create(&cli_ctx_tls_key, NULL);
}
-void cli_logg_setup(const cli_ctx *ctx)
+void cli_logg_setup(const cli_ctx* ctx)
{
pthread_once(&cli_ctx_tls_key_once, cli_ctx_tls_key_alloc);
pthread_setspecific(cli_ctx_tls_key, ctx);
@@ -92,22 +93,22 @@
pthread_setspecific(cli_ctx_tls_key, NULL);
}
-static inline void *cli_getctx(void)
+static inline void* cli_getctx(void)
{
- cli_ctx *ctx;
+ cli_ctx* ctx;
pthread_once(&cli_ctx_tls_key_once, cli_ctx_tls_key_alloc);
ctx = pthread_getspecific(cli_ctx_tls_key);
return ctx ? ctx->cb_ctx : NULL;
}
#else
-static const cli_ctx *current_ctx = NULL;
-void cli_logg_setup(const cli_ctx *ctx)
+static const cli_ctx* current_ctx = NULL;
+void cli_logg_setup(const cli_ctx* ctx)
{
current_ctx = ctx;
}
-static inline void *cli_getctx(void)
+static inline void* cli_getctx(void)
{
return current_ctx ? current_ctx->cb_ctx : NULL;
}
@@ -117,10 +118,10 @@
}
#endif
-uint8_t cli_debug_flag = 0;
+uint8_t cli_debug_flag = 0;
uint8_t cli_always_gen_section_hash = 0;
-static void fputs_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *context)
+static void fputs_callback(enum cl_msg severity, const char* fullmsg, const char* msg, void* context)
{
UNUSEDPARAM(severity);
UNUSEDPARAM(msg);
@@ -135,138 +136,136 @@
msg_callback = callback;
}
-#define MSGCODE(buff, len, x) \
- va_list args; \
- size_t len = sizeof(x) - 1; \
- char buff[BUFSIZ]; \
- strncpy(buff, x, len); \
- va_start(args, str); \
- vsnprintf(buff + len, sizeof(buff) - len, str, args); \
- buff[sizeof(buff) - 1] = '\0'; \
+#define MSGCODE(buff, len, x) \
+ va_list args; \
+ size_t len = sizeof(x) - 1; \
+ char buff[BUFSIZ]; \
+ strncpy(buff, x, len); \
+ va_start(args, str); \
+ vsnprintf(buff + len, sizeof(buff) - len, str, args); \
+ buff[sizeof(buff) - 1] = '\0'; \
va_end(args)
-void cli_warnmsg(const char *str, ...)
+void cli_warnmsg(const char* str, ...)
{
MSGCODE(buff, len, "LibClamAV Warning: ");
- msg_callback(CL_MSG_WARN, buff, buff+len, cli_getctx());
+ msg_callback(CL_MSG_WARN, buff, buff + len, cli_getctx());
}
-void cli_errmsg(const char *str, ...)
+void cli_errmsg(const char* str, ...)
{
MSGCODE(buff, len, "LibClamAV Error: ");
- msg_callback(CL_MSG_ERROR, buff, buff+len, cli_getctx());
+ msg_callback(CL_MSG_ERROR, buff, buff + len, cli_getctx());
}
-void cli_infomsg(const cli_ctx* ctx, const char *str, ...)
+void cli_infomsg(const cli_ctx* ctx, const char* str, ...)
{
MSGCODE(buff, len, "LibClamAV info: ");
- msg_callback(CL_MSG_INFO_VERBOSE, buff, buff+len, ctx ? ctx->cb_ctx : NULL);
+ msg_callback(CL_MSG_INFO_VERBOSE, buff, buff + len, ctx ? ctx->cb_ctx : NULL);
}
-void cli_dbgmsg_internal(const char *str, ...)
+void cli_dbgmsg_internal(const char* str, ...)
{
MSGCODE(buff, len, "LibClamAV debug: ");
fputs(buff, stderr);
}
-int cli_matchregex(const char *str, const char *regex)
+int cli_matchregex(const char* str, const char* regex)
{
- regex_t reg;
- int match, flags = REG_EXTENDED | REG_NOSUB;
+ regex_t reg;
+ int match, flags = REG_EXTENDED | REG_NOSUB;
#ifdef _WIN32
flags |= REG_ICASE;
#endif
if(cli_regcomp(®, regex, flags) == 0) {
- match = (cli_regexec(®, str, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
- cli_regfree(®);
- return match;
+ match = (cli_regexec(®, str, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
+ cli_regfree(®);
+ return match;
}
return 0;
}
-void *cli_malloc(size_t size)
+void* cli_malloc(size_t size)
{
- void *alloc;
-
+ void* alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
- cli_errmsg("cli_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
- return NULL;
+ cli_errmsg("cli_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+ return NULL;
}
alloc = malloc(size);
if(!alloc) {
- perror("malloc_problem");
- cli_errmsg("cli_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) size);
- return NULL;
- } else return alloc;
+ perror("malloc_problem");
+ cli_errmsg("cli_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int)size);
+ return NULL;
+ } else
+ return alloc;
}
-void *cli_calloc(size_t nmemb, size_t size)
+void* cli_calloc(size_t nmemb, size_t size)
{
- void *alloc;
-
+ void* alloc;
- 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 https://bugzilla.clamav.net\n", (unsigned long int) nmemb*size);
- return NULL;
+ 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 https://bugzilla.clamav.net\n", (unsigned long int)nmemb * size);
+ return NULL;
}
alloc = calloc(nmemb, size);
if(!alloc) {
- perror("calloc_problem");
- cli_errmsg("cli_calloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) (nmemb * size));
- return NULL;
- } else return alloc;
+ perror("calloc_problem");
+ cli_errmsg("cli_calloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int)(nmemb * size));
+ return NULL;
+ } else
+ return alloc;
}
-void *cli_realloc(void *ptr, size_t size)
+void* cli_realloc(void* ptr, size_t size)
{
- void *alloc;
-
+ void* alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
- cli_errmsg("cli_realloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
- return NULL;
+ cli_errmsg("cli_realloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+ return NULL;
}
alloc = realloc(ptr, size);
if(!alloc) {
- perror("realloc_problem");
- cli_errmsg("cli_realloc(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
- return NULL;
- } else return alloc;
+ perror("realloc_problem");
+ cli_errmsg("cli_realloc(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int)size);
+ return NULL;
+ } else
+ return alloc;
}
-void *cli_realloc2(void *ptr, size_t size)
+void* cli_realloc2(void* ptr, size_t size)
{
- void *alloc;
-
+ void* alloc;
if(!size || size > CLI_MAX_ALLOCATION) {
- cli_errmsg("cli_realloc2(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
- return NULL;
+ cli_errmsg("cli_realloc2(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+ return NULL;
}
alloc = realloc(ptr, size);
if(!alloc) {
- perror("realloc_problem");
- cli_errmsg("cli_realloc2(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
- if(ptr)
- free(ptr);
- return NULL;
- } else return alloc;
+ perror("realloc_problem");
+ cli_errmsg("cli_realloc2(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int)size);
+ if(ptr)
+ free(ptr);
+ return NULL;
+ } else
+ return alloc;
}
-char *cli_strdup(const char *s)
+char* cli_strdup(const char* s)
{
- char *alloc;
-
+ char* alloc;
if(s == NULL) {
cli_errmsg("cli_strdup(): s == NULL. Please report to https://bugzilla.clamav.net\n");
@@ -277,7 +276,7 @@
if(!alloc) {
perror("strdup_problem");
- cli_errmsg("cli_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int) strlen(s));
+ cli_errmsg("cli_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int)strlen(s));
return NULL;
}
@@ -285,142 +284,137 @@
}
/* returns converted timestamp, in case of error the returned string contains at least one character */
-const char* cli_ctime(const time_t *timep, char *buf, const size_t bufsize)
+const char* cli_ctime(const time_t* timep, char* buf, const size_t bufsize)
{
- const char *ret;
- if(bufsize < 26) {
- /* standard says we must have at least 26 bytes buffer */
- cli_warnmsg("buffer too small for ctime\n");
- return " ";
- }
- if((uint32_t)(*timep) > 0x7fffffff) {
- /* some systems can consider these timestamps invalid */
- strncpy(buf, "invalid timestamp", bufsize-1);
- buf[bufsize-1] = '\0';
- return buf;
- }
-
-#ifdef HAVE_CTIME_R
-# ifdef HAVE_CTIME_R_2
- ret = ctime_r(timep, buf);
-# else
- ret = ctime_r(timep, buf, bufsize);
-# endif
+ const char* ret;
+ if(bufsize < 26) {
+ /* standard says we must have at least 26 bytes buffer */
+ cli_warnmsg("buffer too small for ctime\n");
+ return " ";
+ }
+ if((uint32_t)(*timep) > 0x7fffffff) {
+ /* some systems can consider these timestamps invalid */
+ strncpy(buf, "invalid timestamp", bufsize - 1);
+ buf[bufsize - 1] = '\0';
+ return buf;
+ }
+
+#ifdef HAVE_CTIME_R
+#ifdef HAVE_CTIME_R_2
+ ret = ctime_r(timep, buf);
+#else
+ ret = ctime_r(timep, buf, bufsize);
+#endif
#else /* no ctime_r */
-# ifdef CL_THREAD_SAFE
- pthread_mutex_lock(&cli_ctime_mutex);
-# endif
- ret = ctime(timep);
- if(ret) {
- strncpy(buf, ret, bufsize-1);
- buf[bufsize-1] = '\0';
- ret = buf;
- }
-# ifdef CL_THREAD_SAFE
- pthread_mutex_unlock(&cli_ctime_mutex);
-# endif
-#endif
- /* common */
- if(!ret) {
- buf[0] = ' ';
- buf[1] = '\0';
- return buf;
- }
- return ret;
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_lock(&cli_ctime_mutex);
+#endif
+ ret = ctime(timep);
+ if(ret) {
+ strncpy(buf, ret, bufsize - 1);
+ buf[bufsize - 1] = '\0';
+ ret = buf;
+ }
+#ifdef CL_THREAD_SAFE
+ pthread_mutex_unlock(&cli_ctime_mutex);
+#endif
+#endif
+ /* common */
+ if(!ret) {
+ buf[0] = ' ';
+ buf[1] = '\0';
+ return buf;
+ }
+ return ret;
}
/* Function: readn
Try hard to read the requested number of bytes
*/
-int cli_readn(int fd, void *buff, unsigned int count)
+int cli_readn(int fd, void* buff, unsigned int count)
{
- int retval;
- unsigned int todo;
- unsigned char *current;
-
-
- todo = count;
- current = (unsigned char *) buff;
-
- do {
- retval = read(fd, current, todo);
- if (retval == 0) {
- return (count - todo);
- }
- if (retval < 0) {
- char err[128];
- if (errno == EINTR) {
- continue;
- }
- cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err)));
- return -1;
- }
- todo -= retval;
- current += retval;
- } while (todo > 0);
-
+ int retval;
+ unsigned int todo;
+ unsigned char* current;
+
+ todo = count;
+ current = (unsigned char*)buff;
+
+ do {
+ retval = read(fd, current, todo);
+ if(retval == 0) {
+ return (count - todo);
+ }
+ if(retval < 0) {
+ char err[128];
+ if(errno == EINTR) {
+ continue;
+ }
+ cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err)));
+ return -1;
+ }
+ todo -= retval;
+ current += retval;
+ } while(todo > 0);
- return count;
+ return count;
}
/* Function: writen
Try hard to write the specified number of bytes
*/
-int cli_writen(int fd, const void *buff, unsigned int count)
+int cli_writen(int fd, const void* buff, unsigned int count)
{
- int retval;
- unsigned int todo;
- const unsigned char *current;
-
-
- todo = count;
- current = (const unsigned char *) buff;
-
- do {
- retval = write(fd, current, todo);
- if (retval < 0) {
- char err[128];
- if (errno == EINTR) {
- continue;
- }
- cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err)));
- return -1;
- }
- todo -= retval;
- current += retval;
- } while (todo > 0);
-
+ int retval;
+ unsigned int todo;
+ const unsigned char* current;
+
+ todo = count;
+ current = (const unsigned char*)buff;
+
+ do {
+ retval = write(fd, current, todo);
+ if(retval < 0) {
+ char err[128];
+ if(errno == EINTR) {
+ continue;
+ }
+ cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err)));
+ return -1;
+ }
+ todo -= retval;
+ current += retval;
+ } while(todo > 0);
- return count;
+ return count;
}
-int cli_filecopy(const char *src, const char *dest)
+int cli_filecopy(const char* src, const char* dest)
{
#ifdef _WIN32
return CopyFileA(src, dest, 0) ? 0 : -1;
#else
- char *buffer;
- int s, d, bytes;
+ char* buffer;
+ int s, d, bytes;
+ if((s = open(src, O_RDONLY | O_BINARY)) == -1)
+ return -1;
- if((s = open(src, O_RDONLY|O_BINARY)) == -1)
- return -1;
-
- if((d = open(dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRWXU)) == -1) {
- close(s);
- return -1;
+ if((d = open(dest, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, S_IRWXU)) == -1) {
+ close(s);
+ return -1;
}
if(!(buffer = cli_malloc(FILEBUFF))) {
- close(s);
- close(d);
- return -1;
+ close(s);
+ close(d);
+ return -1;
}
while((bytes = cli_readn(s, buffer, FILEBUFF)) > 0)
- cli_writen(d, buffer, bytes);
+ cli_writen(d, buffer, bytes);
free(buffer);
close(s);
@@ -437,39 +431,40 @@
#endif /* _WIN32 */
#endif /* P_tmpdir */
-const char *cli_gettmpdir(void) {
- const char *tmpdir;
+const char* cli_gettmpdir(void)
+{
+ const char* tmpdir;
unsigned int i;
#ifdef _WIN32
- char *envs[] = { "TEMP", "TMP", NULL };
+ char* envs[] = {"TEMP", "TMP", NULL};
#else
- char *envs[] = { "TMPDIR", NULL };
+ char* envs[] = {"TMPDIR", NULL};
#endif
- for (i=0; envs[i] != NULL; i++)
- if ((tmpdir = getenv(envs[i])))
+ for(i = 0; envs[i] != NULL; i++)
+ if((tmpdir = getenv(envs[i])))
return tmpdir;
return P_tmpdir;
}
struct dirent_data {
- char *filename;
- const char *dirname;
- STATBUF *statbuf;
- long ino; /* -1: inode not available */
- int is_dir;/* 0 - no, 1 - yes */
+ char* filename;
+ const char* dirname;
+ STATBUF* statbuf;
+ long ino; /* -1: inode not available */
+ int is_dir; /* 0 - no, 1 - yes */
};
/* sort files before directories, and lower inodes before higher inodes */
-static int ftw_compare(const void *a, const void *b)
+static int ftw_compare(const void* a, const void* b)
{
- const struct dirent_data *da = a;
- const struct dirent_data *db = b;
- long diff = da->is_dir - db->is_dir;
- if (!diff) {
- diff = da->ino - db->ino;
+ const struct dirent_data* da = a;
+ const struct dirent_data* db = b;
+ long diff = da->is_dir - db->is_dir;
+ if(!diff) {
+ diff = da->ino - db->ino;
}
return diff;
}
@@ -489,100 +484,98 @@
}
#define FOLLOW_SYMLINK_MASK (CLI_FTW_FOLLOW_FILE_SYMLINK | CLI_FTW_FOLLOW_DIR_SYMLINK)
-static int get_filetype(const char *fname, int flags, int need_stat,
- STATBUF *statbuf, enum filetype *ft)
+static int get_filetype(const char* fname, int flags, int need_stat,
+ STATBUF* statbuf, enum filetype* ft)
{
int stated = 0;
- if (*ft == ft_unknown || *ft == ft_link) {
- need_stat = 1;
+ if(*ft == ft_unknown || *ft == ft_link) {
+ need_stat = 1;
- if ((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
- /* Following only one of directory/file symlinks, or none, may
+ if((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
+ /* Following only one of directory/file symlinks, or none, may
* need to lstat.
* If we're following both file and directory symlinks, we don't need
* to lstat(), we can just stat() directly.*/
- if (*ft != ft_link) {
- /* need to lstat to determine if it is a symlink */
- if (LSTAT(fname, statbuf) == -1)
- return -1;
- if (S_ISLNK(statbuf->st_mode)) {
- *ft = ft_link;
- } else {
- /* It was not a symlink, stat() not needed */
- need_stat = 0;
- stated = 1;
- }
- }
- if (*ft == ft_link && !(flags & FOLLOW_SYMLINK_MASK)) {
- /* This is a symlink, but we don't follow any symlinks */
- *ft = ft_skipped_link;
- return 0;
- }
- }
- }
-
- if (need_stat) {
- if (CLAMSTAT(fname, statbuf) == -1)
- return -1;
- stated = 1;
- }
-
- if (*ft == ft_unknown || *ft == ft_link) {
- if (S_ISDIR(statbuf->st_mode) &&
- (*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
- /* A directory, or (a symlink to a directory and we're following dir
+ if(*ft != ft_link) {
+ /* need to lstat to determine if it is a symlink */
+ if(LSTAT(fname, statbuf) == -1)
+ return -1;
+ if(S_ISLNK(statbuf->st_mode)) {
+ *ft = ft_link;
+ } else {
+ /* It was not a symlink, stat() not needed */
+ need_stat = 0;
+ stated = 1;
+ }
+ }
+ if(*ft == ft_link && !(flags & FOLLOW_SYMLINK_MASK)) {
+ /* This is a symlink, but we don't follow any symlinks */
+ *ft = ft_skipped_link;
+ return 0;
+ }
+ }
+ }
+
+ if(need_stat) {
+ if(CLAMSTAT(fname, statbuf) == -1)
+ return -1;
+ stated = 1;
+ }
+
+ if(*ft == ft_unknown || *ft == ft_link) {
+ if(S_ISDIR(statbuf->st_mode) &&
+ (*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
+ /* A directory, or (a symlink to a directory and we're following dir
* symlinks) */
- *ft = ft_directory;
- } else if (S_ISREG(statbuf->st_mode) &&
- (*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
- /* A file, or (a symlink to a file and we're following file symlinks) */
- *ft = ft_regular;
- } else {
- /* default: skipped */
- *ft = S_ISLNK(statbuf->st_mode) ?
- ft_skipped_link : ft_skipped_special;
- }
+ *ft = ft_directory;
+ } else if(S_ISREG(statbuf->st_mode) &&
+ (*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
+ /* A file, or (a symlink to a file and we're following file symlinks) */
+ *ft = ft_regular;
+ } else {
+ /* default: skipped */
+ *ft = S_ISLNK(statbuf->st_mode) ? ft_skipped_link : ft_skipped_special;
+ }
}
return stated;
}
-static int handle_filetype(const char *fname, int flags,
- STATBUF *statbuf, int *stated, enum filetype *ft,
- cli_ftw_cb callback, struct cli_ftw_cbdata *data)
+static int handle_filetype(const char* fname, int flags,
+ STATBUF* statbuf, int* stated, enum filetype* ft,
+ cli_ftw_cb callback, struct cli_ftw_cbdata* data)
{
int ret;
- *stated = get_filetype(fname, flags, flags & CLI_FTW_NEED_STAT , statbuf, ft);
+ *stated = get_filetype(fname, flags, flags & CLI_FTW_NEED_STAT, statbuf, ft);
- if (*stated == -1) {
- /* we failed a stat() or lstat() */
- ret = callback(NULL, NULL, fname, error_stat, data);
- if (ret != CL_SUCCESS)
- return ret;
- *ft = ft_unknown;
- } else if (*ft == ft_skipped_link || *ft == ft_skipped_special) {
- /* skipped filetype */
- ret = callback(stated ? statbuf : NULL, NULL, fname,
- *ft == ft_skipped_link ?
- warning_skipped_link : warning_skipped_special, data);
- if (ret != CL_SUCCESS)
- return ret;
+ if(*stated == -1) {
+ /* we failed a stat() or lstat() */
+ ret = callback(NULL, NULL, fname, error_stat, data);
+ if(ret != CL_SUCCESS)
+ return ret;
+ *ft = ft_unknown;
+ } else if(*ft == ft_skipped_link || *ft == ft_skipped_special) {
+ /* skipped filetype */
+ ret = callback(stated ? statbuf : NULL, NULL, fname,
+ *ft == ft_skipped_link ? warning_skipped_link : warning_skipped_special, data);
+ if(ret != CL_SUCCESS)
+ return ret;
}
return CL_SUCCESS;
}
-static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk);
-static int handle_entry(struct dirent_data *entry, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+static int cli_ftw_dir(const char* dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk);
+static int handle_entry(struct dirent_data* entry, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
{
- if (!entry->is_dir) {
- return callback(entry->statbuf, entry->filename, entry->filename, visit_file, data);
+ if(!entry->is_dir) {
+ return callback(entry->statbuf, entry->filename, entry->filename, visit_file, data);
} else {
- return cli_ftw_dir(entry->dirname, flags, maxdepth, callback, data, pathchk);
+ return cli_ftw_dir(entry->dirname, flags, maxdepth, callback, data, pathchk);
}
}
-int cli_ftw(char *path, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+int cli_ftw(char* path, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
{
STATBUF statbuf;
enum filetype ft = ft_unknown;
@@ -590,215 +583,215 @@
int stated = 0;
int ret;
- if (((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
- char *pathend;
- /* trim slashes so that dir and dir/ behave the same when
+ if(((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
+ char* pathend;
+ /* trim slashes so that dir and dir/ behave the same when
* they are symlinks, and we are not following symlinks */
#ifndef _WIN32
- while (path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
+ while(path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
#endif
- pathend = path + strlen(path);
- while (pathend > path && pathend[-1] == *PATHSEP) --pathend;
- *pathend = '\0';
+ pathend = path + strlen(path);
+ while(pathend > path && pathend[-1] == *PATHSEP) --pathend;
+ *pathend = '\0';
}
if(pathchk && pathchk(path, data) == 1)
- return CL_SUCCESS;
+ return CL_SUCCESS;
ret = handle_filetype(path, flags, &statbuf, &stated, &ft, callback, data);
- if (ret != CL_SUCCESS)
- return ret;
- if (ft_skipped(ft))
- return CL_SUCCESS;
- entry.statbuf = stated ? &statbuf : NULL;
- entry.is_dir = ft == ft_directory;
+ if(ret != CL_SUCCESS)
+ return ret;
+ if(ft_skipped(ft))
+ return CL_SUCCESS;
+ entry.statbuf = stated ? &statbuf : NULL;
+ entry.is_dir = ft == ft_directory;
entry.filename = entry.is_dir ? NULL : strdup(path);
- entry.dirname = entry.is_dir ? path : NULL;
- if (entry.is_dir) {
- ret = callback(entry.statbuf, NULL, path, visit_directory_toplev, data);
- if (ret != CL_SUCCESS)
- return ret;
+ entry.dirname = entry.is_dir ? path : NULL;
+ if(entry.is_dir) {
+ ret = callback(entry.statbuf, NULL, path, visit_directory_toplev, data);
+ if(ret != CL_SUCCESS)
+ return ret;
}
return handle_entry(&entry, flags, maxdepth, callback, data, pathchk);
}
-static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+static int cli_ftw_dir(const char* dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
{
- DIR *dd;
+ DIR* dd;
#if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
union {
- struct dirent d;
- char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+ struct dirent d;
+ char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
} result;
#endif
- struct dirent_data *entries = NULL;
+ struct dirent_data* entries = NULL;
size_t i, entries_cnt = 0;
int ret;
- if (maxdepth < 0) {
- /* exceeded recursion limit */
- ret = callback(NULL, NULL, dirname, warning_skipped_dir, data);
- return ret;
+ if(maxdepth < 0) {
+ /* exceeded recursion limit */
+ ret = callback(NULL, NULL, dirname, warning_skipped_dir, data);
+ return ret;
}
if((dd = opendir(dirname)) != NULL) {
- struct dirent *dent;
- int err;
- errno = 0;
- ret = CL_SUCCESS;
+ struct dirent* dent;
+ int err;
+ errno = 0;
+ ret = CL_SUCCESS;
#ifdef HAVE_READDIR_R_3
- while(!(err = readdir_r(dd, &result.d, &dent)) && dent) {
+ while(!(err = readdir_r(dd, &result.d, &dent)) && dent) {
#elif defined(HAVE_READDIR_R_2)
- while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+ while((dent = (struct dirent*)readdir_r(dd, &result.d))) {
#else
- while((dent = readdir(dd))) {
+ while((dent = readdir(dd))) {
#endif
- int stated = 0;
- enum filetype ft;
- char *fname;
- STATBUF statbuf;
- STATBUF *statbufp;
+ int stated = 0;
+ enum filetype ft;
+ char* fname;
+ STATBUF statbuf;
+ STATBUF* statbufp;
- if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
- continue;
+ if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+ continue;
#ifdef _DIRENT_HAVE_D_TYPE
- switch (dent->d_type) {
- case DT_DIR:
- ft = ft_directory;
- break;
- case DT_LNK:
- if (!(flags & FOLLOW_SYMLINK_MASK)) {
- /* we don't follow symlinks, don't bother
+ switch(dent->d_type) {
+ case DT_DIR:
+ ft = ft_directory;
+ break;
+ case DT_LNK:
+ if(!(flags & FOLLOW_SYMLINK_MASK)) {
+ /* we don't follow symlinks, don't bother
* stating it */
- errno = 0;
- continue;
- }
- ft = ft_link;
- break;
- case DT_REG:
- ft = ft_regular;
- break;
- case DT_UNKNOWN:
- ft = ft_unknown;
- break;
- default:
- ft = ft_skipped_special;
- break;
- }
+ errno = 0;
+ continue;
+ }
+ ft = ft_link;
+ break;
+ case DT_REG:
+ ft = ft_regular;
+ break;
+ case DT_UNKNOWN:
+ ft = ft_unknown;
+ break;
+ default:
+ ft = ft_skipped_special;
+ break;
+ }
#else
- ft = ft_unknown;
+ ft = ft_unknown;
#endif
- fname = (char *) cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
- if(!fname) {
- ret = callback(NULL, NULL, dirname, error_mem, data);
- if (ret != CL_SUCCESS)
- break;
- continue; /* have to skip this one if continuing after error */
- }
+ fname = (char*)cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+ if(!fname) {
+ ret = callback(NULL, NULL, dirname, error_mem, data);
+ if(ret != CL_SUCCESS)
+ break;
+ continue; /* have to skip this one if continuing after error */
+ }
if(!strcmp(dirname, PATHSEP))
- sprintf(fname, PATHSEP"%s", dent->d_name);
- else
- sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
-
- if(pathchk && pathchk(fname, data) == 1) {
- free(fname);
- continue;
- }
-
- ret = handle_filetype(fname, flags, &statbuf, &stated, &ft, callback, data);
- if (ret != CL_SUCCESS) {
- free(fname);
- break;
- }
-
- if (ft_skipped(ft)) { /* skip */
- free(fname);
- errno = 0;
- continue;
- }
-
- if (stated && (flags & CLI_FTW_NEED_STAT)) {
- statbufp = cli_malloc(sizeof(*statbufp));
- if (!statbufp) {
- ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
- free(fname);
- if (ret != CL_SUCCESS)
- break;
- else {
- errno = 0;
- continue;
- }
- }
- memcpy(statbufp, &statbuf, sizeof(statbuf));
- } else {
- statbufp = 0;
- }
-
- entries_cnt++;
- entries = cli_realloc(entries, entries_cnt*sizeof(*entries));
- if (!entries) {
- ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
- free(fname);
- if (statbufp)
- free(statbufp);
- break;
- } else {
- struct dirent_data *entry = &entries[entries_cnt-1];
- entry->filename = fname;
- entry->statbuf = statbufp;
- entry->is_dir = ft == ft_directory;
- entry->dirname = entry->is_dir ? fname : NULL;
+ sprintf(fname, PATHSEP "%s", dent->d_name);
+ else
+ sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name);
+
+ if(pathchk && pathchk(fname, data) == 1) {
+ free(fname);
+ continue;
+ }
+
+ ret = handle_filetype(fname, flags, &statbuf, &stated, &ft, callback, data);
+ if(ret != CL_SUCCESS) {
+ free(fname);
+ break;
+ }
+
+ if(ft_skipped(ft)) { /* skip */
+ free(fname);
+ errno = 0;
+ continue;
+ }
+
+ if(stated && (flags & CLI_FTW_NEED_STAT)) {
+ statbufp = cli_malloc(sizeof(*statbufp));
+ if(!statbufp) {
+ ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
+ free(fname);
+ if(ret != CL_SUCCESS)
+ break;
+ else {
+ errno = 0;
+ continue;
+ }
+ }
+ memcpy(statbufp, &statbuf, sizeof(statbuf));
+ } else {
+ statbufp = 0;
+ }
+
+ entries_cnt++;
+ entries = cli_realloc(entries, entries_cnt * sizeof(*entries));
+ if(!entries) {
+ ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
+ free(fname);
+ if(statbufp)
+ free(statbufp);
+ break;
+ } else {
+ struct dirent_data* entry = &entries[entries_cnt - 1];
+ entry->filename = fname;
+ entry->statbuf = statbufp;
+ entry->is_dir = ft == ft_directory;
+ entry->dirname = entry->is_dir ? fname : NULL;
#ifdef _XOPEN_UNIX
- entry->ino = dent->d_ino;
+ entry->ino = dent->d_ino;
#else
- entry->ino = -1;
+ entry->ino = -1;
#endif
- }
- errno = 0;
- }
+ }
+ errno = 0;
+ }
#ifndef HAVE_READDIR_R_3
- err = errno;
+ 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 (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) {
- cli_qsort(entries, entries_cnt, sizeof(*entries), ftw_compare);
- for (i = 0; i < entries_cnt; i++) {
- struct dirent_data *entry = &entries[i];
- ret = handle_entry(entry, flags, maxdepth-1, callback, data, pathchk);
- if (entry->is_dir)
- free(entry->filename);
- if (entry->statbuf)
- free(entry->statbuf);
- if (ret != CL_SUCCESS)
- break;
- }
- for (i++;i<entries_cnt;i++) {
- struct dirent_data *entry = &entries[i];
- free(entry->filename);
- free(entry->statbuf);
- }
- free(entries);
- }
+ 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(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) {
+ cli_qsort(entries, entries_cnt, sizeof(*entries), ftw_compare);
+ for(i = 0; i < entries_cnt; i++) {
+ struct dirent_data* entry = &entries[i];
+ ret = handle_entry(entry, flags, maxdepth - 1, callback, data, pathchk);
+ if(entry->is_dir)
+ free(entry->filename);
+ if(entry->statbuf)
+ free(entry->statbuf);
+ if(ret != CL_SUCCESS)
+ break;
+ }
+ for(i++; i < entries_cnt; i++) {
+ struct dirent_data* entry = &entries[i];
+ free(entry->filename);
+ free(entry->statbuf);
+ }
+ free(entries);
+ }
} else {
- ret = callback(NULL, NULL, dirname, error_stat, data);
+ ret = callback(NULL, NULL, dirname, error_stat, data);
}
return ret;
}
@@ -806,39 +799,39 @@
/* strerror_r is not available everywhere, (and when it is there are two variants,
* the XSI, and the GNU one, so provide a wrapper to make sure correct one is
* used */
-const char* cli_strerror(int errnum, char *buf, size_t len)
+const char* cli_strerror(int errnum, char* buf, size_t len)
{
- char *err;
-# ifdef CL_THREAD_SAFE
+ char* err;
+#ifdef CL_THREAD_SAFE
pthread_mutex_lock(&cli_strerror_mutex);
#endif
err = strerror(errnum);
strncpy(buf, err, len);
- buf[len-1] = '\0'; /* just in case */
-# ifdef CL_THREAD_SAFE
+ buf[len - 1] = '\0'; /* just in case */
+#ifdef CL_THREAD_SAFE
pthread_mutex_unlock(&cli_strerror_mutex);
#endif
return buf;
}
-static char *cli_md5buff(const unsigned char *buffer, unsigned int len, unsigned char *dig)
+static char* cli_md5buff(const unsigned char* buffer, unsigned int len, unsigned char* dig)
{
- unsigned char digest[16];
- char *md5str, *pt;
- int i;
+ unsigned char digest[16];
+ char *md5str, *pt;
+ int i;
cl_hash_data("md5", buffer, len, digest, NULL);
if(dig)
- memcpy(dig, digest, 16);
+ memcpy(dig, digest, 16);
- if(!(md5str = (char *) cli_calloc(32 + 1, sizeof(char))))
- return NULL;
+ if(!(md5str = (char*)cli_calloc(32 + 1, sizeof(char))))
+ return NULL;
pt = md5str;
for(i = 0; i < 16; i++) {
- sprintf(pt, "%02x", digest[i]);
- pt += 2;
+ sprintf(pt, "%02x", digest[i]);
+ pt += 2;
}
return md5str;
@@ -847,30 +840,148 @@
unsigned int cli_rndnum(unsigned int max)
{
if(name_salt[0] == 16) { /* minimizes re-seeding after the first call to cli_gentemp() */
- struct timeval tv;
- gettimeofday(&tv, (struct timezone *) 0);
- srand(tv.tv_usec+clock()+rand());
+ struct timeval tv;
+ gettimeofday(&tv, (struct timezone*)0);
+ srand(tv.tv_usec + clock() + rand());
}
- return 1 + (unsigned int) (max * (rand() / (1.0 + RAND_MAX)));
+ return 1 + (unsigned int)(max * (rand() / (1.0 + RAND_MAX)));
}
-char* cli_genfname(const char * prefix)
+char* cli_sanitize_filepath(const char* filepath, size_t filepath_len)
{
- char* fname;
+ uint32_t depth = 0;
+ size_t index = 0;
+ size_t sanitized_index = 0;
+ char* sanitized_filepath = NULL;
+
+ if((NULL == filepath) || (0 == filepath_len) || (MAX_PATH < filepath_len)) {
+ goto done;
+ }
+
+ sanitized_filepath = cli_calloc(filepath_len + 1, sizeof(unsigned char));
+ if(NULL == sanitized_filepath) {
+ cli_dbgmsg("cli_sanitize_filepath: out of memory\n");
+ goto done;
+ }
+
+ while(index < filepath_len) {
+ char* next_pathsep = NULL;
+
+ if(0 == strncmp(filepath + index, PATHSEP, strlen(PATHSEP))) {
+ /*
+ * Is "/" (or "\\" on Windows)
+ */
+ /* Skip leading pathsep in absolute path, or extra pathsep) */
+ index += strlen(PATHSEP);
+ continue;
+ } else if(0 == strncmp(filepath + index, "." PATHSEP, strlen("." PATHSEP))) {
+ /*
+ * Is "./" (or ".\\" on Windows)
+ */
+ /* Current directory indicator is meaningless and should not add to the depth. Skip it. */
+ index += strlen("." PATHSEP);
+ continue;
+ } else if(0 == strncmp(filepath + index, ".." PATHSEP, strlen(".." PATHSEP))) {
+ /*
+ * Is "../" (or "..\\" on Windows)
+ */
+ if(depth == 0) {
+ /* Relative path would traverse parent directory. Skip it. */
+ index += strlen(".." PATHSEP);
+ continue;
+ } else {
+ /* Relative path is safe. Allow it. */
+ strncpy(sanitized_filepath + sanitized_index, filepath + index, strlen(".." PATHSEP));
+ sanitized_index += strlen(".." PATHSEP);
+ index += strlen(".." PATHSEP);
+ depth--;
+ }
+ }
+#ifdef _WIN32
+ /*
+ * Windows' POSIX style API's accept both "/" and "\\" style path separators.
+ * The following checks using POSIX style path separators on Windows.
+ */
+ else if(0 == strncmp(filepath + index, "/", strlen("/"))) {
+ /*
+ * Is "/".
+ */
+ /* Skip leading pathsep in absolute path, or extra pathsep) */
+ index += strlen("/");
+ continue;
+ } else if(0 == strncmp(filepath + index, "./", strlen("./"))) {
+ /*
+ * Is "./"
+ */
+ /* Current directory indicator is meaningless and should not add to the depth. Skip it. */
+ index += strlen("./");
+ continue;
+ } else if(0 == strncmp(filepath + index, "../", strlen("../"))) {
+ /*
+ * Is "../"
+ */
+ if(depth == 0) {
+ /* Relative path would traverse parent directory. Skip it. */
+ index += strlen("../");
+ continue;
+ } else {
+ /* Relative path is safe. Allow it. */
+ strncpy(sanitized_filepath + sanitized_index, filepath + index, strlen("../"));
+ sanitized_index += strlen("../");
+ index += strlen("../");
+ depth--;
+ }
+ }
+#endif
+ else {
+ /*
+ * Is not "/", "./", or "../".
+ */
+ /* Find the next path separator. */
+ next_pathsep = cli_strnstr(filepath + index, PATHSEP, filepath_len - index);
+ if(NULL == next_pathsep) {
+ /* No more path separators, copy the rest (filename) into the sanitized path */
+ strncpy(sanitized_filepath + sanitized_index, filepath + index, filepath_len - index);
+ break;
+ }
+ next_pathsep += strlen(PATHSEP); /* Include the path separator in the copy */
+
+ /* Copy next directory name into the sanitized path */
+ strncpy(sanitized_filepath + sanitized_index, filepath + index, next_pathsep - (filepath + index));
+ sanitized_index += next_pathsep - (filepath + index);
+ index += next_pathsep - (filepath + index);
+ depth++;
+ }
+ }
+
+done:
+ if((NULL != sanitized_filepath) && (0 == strlen(sanitized_filepath))) {
+ free(sanitized_filepath);
+ sanitized_filepath = NULL;
+ }
+
+ return sanitized_filepath;
+}
+
+char* cli_genfname(const char* prefix)
+{
+ char* sanitized_prefix = NULL;
+ char* fname = NULL;
unsigned char salt[16 + 32];
char* tmp;
int i;
- size_t len;
+ size_t len;
- if (prefix && (strlen(prefix) > 0)) {
- len = strlen(prefix) + 1 + 5 + 1; /* {prefix}.{5}\0 */
- } else {
- len = 6 + 1 + 48 + 4 + 1; /* clamav-{48}.tmp\0 */
- }
+ if(prefix && (strlen(prefix) > 0)) {
+ sanitized_prefix = cli_sanitize_filepath(prefix, strlen(prefix));
+ len = strlen(sanitized_prefix) + 1 + 5 + 1; /* {prefix}.{5}\0 */
+ } else {
+ len = 6 + 1 + 48 + 4 + 1; /* clamav-{48}.tmp\0 */
+ }
fname = (char*)cli_calloc(len, sizeof(char));
- if (!fname) {
+ if(!fname) {
cli_dbgmsg("cli_genfname: out of memory\n");
return NULL;
}
@@ -881,7 +992,7 @@
memcpy(salt, name_salt, 16);
- for (i = 16; i < 48; i++)
+ for(i = 16; i < 48; i++)
salt[i] = cli_rndnum(255);
tmp = cli_md5buff(salt, 48, name_salt);
@@ -890,18 +1001,19 @@
pthread_mutex_unlock(&cli_gentemp_mutex);
#endif
- if (!tmp) {
+ if(!tmp) {
free(fname);
cli_dbgmsg("cli_genfname: out of memory\n");
return NULL;
}
- if (prefix && (strlen(prefix) > 0)) {
- fname[5] = '\0';
- snprintf(fname, len, "%s.%s", prefix, tmp);
- } else {
- snprintf(fname, len, "clamav-%s.tmp", tmp);
- }
+ if(sanitized_prefix && (strlen(sanitized_prefix) > 0)) {
+ fname[5] = '\0';
+ snprintf(fname, len, "%s.%s", sanitized_prefix, tmp);
+ free(sanitized_prefix);
+ } else {
+ snprintf(fname, len, "clamav-%s.tmp", tmp);
+ }
free(tmp);
@@ -910,7 +1022,7 @@
char* cli_gentemp_with_prefix(const char* dir, const char* prefix)
{
- char* fname;
+ char* fname;
char* fullpath;
const char* mdir;
int i;
@@ -918,32 +1030,32 @@
mdir = dir ? dir : cli_gettmpdir();
- fname = cli_genfname(prefix);
- if (!fname) {
+ fname = cli_genfname(prefix);
+ if(!fname) {
cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
return NULL;
}
- len = strlen(mdir) + strlen(PATHSEP) + strlen(fname) + 1; /* mdir/fname\0 */
+ len = strlen(mdir) + strlen(PATHSEP) + strlen(fname) + 1; /* mdir/fname\0 */
fullpath = (char*)cli_calloc(len, sizeof(char));
- if (!fullpath) {
+ if(!fullpath) {
free(fname);
cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
return NULL;
}
snprintf(fullpath, len, "%s" PATHSEP "%s", mdir, fname);
- free(fname);
+ free(fname);
return (fullpath);
}
char* cli_gentemp(const char* dir)
{
- return cli_gentemp_with_prefix(dir, NULL);
+ return cli_gentemp_with_prefix(dir, NULL);
}
-cl_error_t cli_gentempfd(const char *dir, char **name, int *fd)
+cl_error_t cli_gentempfd(const char* dir, char** name, int* fd)
{
return cli_gentempfd_with_prefix(dir, NULL, name, fd);
}
@@ -951,7 +1063,7 @@
cl_error_t cli_gentempfd_with_prefix(const char* dir, char* prefix, char** name, int* fd)
{
*name = cli_gentemp_with_prefix(dir, prefix);
- if (!*name)
+ if(!*name)
return CL_EMEM;
*fd = open(*name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, S_IRWXU);
@@ -959,15 +1071,15 @@
* EEXIST is almost impossible to occur, so we just treat it as other
* errors
*/
- if (*fd == -1) {
- if ((EILSEQ == errno) || (EINVAL == errno) || (ENAMETOOLONG == errno)) {
+ if(*fd == -1) {
+ if((EILSEQ == errno) || (EINVAL == errno) || (ENAMETOOLONG == errno)) {
cli_dbgmsg("cli_gentempfd_with_prefix: Can't create temp file using prefix. Using a randomly generated name instead.\n");
free(*name);
*name = cli_gentemp(dir);
- if (!*name)
+ if(!*name)
return CL_EMEM;
*fd = open(*name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, S_IRWXU);
- if (*fd == -1) {
+ if(*fd == -1) {
cli_errmsg("cli_gentempfd_with_prefix: Can't create temporary file %s: %s\n", *name, strerror(errno));
free(*name);
*name = NULL;
@@ -984,11 +1096,11 @@
return CL_SUCCESS;
}
-int cli_regcomp(regex_t *preg, const char *pattern, int cflags)
+int cli_regcomp(regex_t* preg, const char* pattern, int cflags)
{
- if (!strncmp(pattern, "(?i)", 4)) {
- pattern += 4;
- cflags |= REG_ICASE;
+ if(!strncmp(pattern, "(?i)", 4)) {
+ pattern += 4;
+ cflags |= REG_ICASE;
}
return cli_regcomp_real(preg, pattern, cflags);
}
@@ -997,7 +1109,7 @@
{
cl_error_t status = CL_EARG;
- if (NULL == filepath) {
+ if(NULL == filepath) {
cli_errmsg("cli_get_filepath_from_filedesc: Invalid args.\n");
goto done;
}
@@ -1013,77 +1125,77 @@
snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
link[sizeof(link) - 1] = '\0';
- if (-1 == (linksz = readlink(link, fname, PATH_MAX - 1))) {
+ if(-1 == (linksz = readlink(link, fname, PATH_MAX - 1))) {
cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d (%s)\n", desc, link);
status = CL_EOPEN;
goto done;
}
- /* Success. Add null terminator */
- fname[linksz] = '\0';
+ /* Success. Add null terminator */
+ fname[linksz] = '\0';
*filepath = cli_strndup(fname, cli_strnlen(fname, PATH_MAX));
- if (NULL == *filepath) {
- cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
- status = CL_EMEM;
- goto done;
- }
+ if(NULL == *filepath) {
+ cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
+ status = CL_EMEM;
+ goto done;
+ }
#elif __APPLE__
char fname[PATH_MAX];
memset(&fname, 0, PATH_MAX);
- if (fcntl(desc, F_GETPATH, &fname) < 0) {
+ if(fcntl(desc, F_GETPATH, &fname) < 0) {
printf("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
status = CL_EOPEN;
goto done;
}
*filepath = cli_strndup(fname, cli_strnlen(fname, PATH_MAX));
- if (NULL == *filepath) {
- cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
- status = CL_EMEM;
- goto done;
- }
+ if(NULL == *filepath) {
+ cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
+ status = CL_EMEM;
+ goto done;
+ }
#elif _WIN32
DWORD dwRet = 0;
intptr_t hFile = _get_osfhandle(desc);
dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, NULL, 0, VOLUME_NAME_NT);
- if (dwRet == 0) {
+ if(dwRet == 0) {
cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
- status = CL_EOPEN;
- goto done;
+ status = CL_EOPEN;
+ goto done;
}
- *filepath = calloc(dwRet + 1, 1);
- if (NULL == *filepath) {
- cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate %u bytes to store filename\n", dwRet + 1);
- status = CL_EMEM;
- goto done;
- }
-
- dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, *filepath, dwRet + 1, VOLUME_NAME_NT);
- if (dwRet == 0) {
- cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
- free(*filepath);
- *filepath = NULL;
- status = CL_EOPEN;
- goto done;
- }
+ *filepath = calloc(dwRet + 1, 1);
+ if(NULL == *filepath) {
+ cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate %u bytes to store filename\n", dwRet + 1);
+ status = CL_EMEM;
+ goto done;
+ }
+
+ dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, *filepath, dwRet + 1, VOLUME_NAME_NT);
+ if(dwRet == 0) {
+ cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
+ free(*filepath);
+ *filepath = NULL;
+ status = CL_EOPEN;
+ goto done;
+ }
#else
- cli_dbgmsg("cli_get_filepath_from_filedesc: No mechanism implemented to determine filename from file descriptor.\n");
- *filepath = NULL;
- status = CL_BREAK;
- goto done;
+ cli_dbgmsg("cli_get_filepath_from_filedesc: No mechanism implemented to determine filename from file descriptor.\n");
+ *filepath = NULL;
+ status = CL_BREAK;
+ goto done;
#endif
- cli_dbgmsg("cli_get_filepath_from_filedesc: File path for fd [%d] is: %s\n", desc, *filepath);
- status = CL_SUCCESS;
+ cli_dbgmsg("cli_get_filepath_from_filedesc: File path for fd [%d] is: %s\n", desc, *filepath);
+ status = CL_SUCCESS;
done:
diff -Nru clamav-0.101.1+dfsg/libclamav/others.h clamav-0.101.2+dfsg/libclamav/others.h
--- clamav-0.101.1+dfsg/libclamav/others.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/others.h 2019-03-13 22:13:01.000000000 +0100
@@ -496,6 +496,7 @@
#define SCAN_COLLECT_METADATA (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
#define SCAN_HEURISTICS (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
#define SCAN_HEURISTIC_PRECEDENCE (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
+#define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
#define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
#define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
@@ -538,7 +539,7 @@
(((v) & 0x00ff000000000000ULL) >> 40) | \
(((v) & 0xff00000000000000ULL) >> 56))
-#ifndef HAVE_ATTRIB_PACKED
+#ifndef HAVE_ATTRIB_PACKED
#define __attribute__(x)
#endif
#ifdef HAVE_PRAGMA_PACK
@@ -750,19 +751,28 @@
const char *cli_gettmpdir(void);
/**
+ * @brief Sanitize a relative path, so it cannot have a negative depth.
+ *
+ * Caller is responsible for freeing the filename.
+ *
+ * @return char* filename or NULL.
+ */
+char *cli_sanitize_filepath(const char *filepath, size_t filepath_len);
+
+/**
* @brief Generate tempfile filename (no path) with a random MD5 hash.
- *
+ *
* Caller is responsible for freeing the filename.
- *
+ *
* @return char* filename or NULL.
*/
char *cli_genfname(const char *prefix);
/**
* @brief Generate a full tempfile filepath with a random MD5 hash and prefix the name, if provided.
- *
+ *
* Caller is responsible for freeing the filename.
- *
+ *
* @param dir Alternative temp directory. (optional)
* @return char* filename or NULL.
*/
diff -Nru clamav-0.101.1+dfsg/libclamav/pdf.c clamav-0.101.2+dfsg/libclamav/pdf.c
--- clamav-0.101.1+dfsg/libclamav/pdf.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/pdf.c 2019-03-13 22:13:01.000000000 +0100
@@ -134,14 +134,14 @@
if (xref + 4 >= eof)
return -1;
- if (!memcmp(xref, "xref", 4)) {
+ if (!memcmp(xref, "xref", strlen("xref"))) {
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)) {
+ if (!memcmp(q,"/XRef", strlen("/XRef"))) {
cli_dbgmsg("cli_pdf: found /XRef\n");
return 0;
}
@@ -163,10 +163,10 @@
/**
* @brief Searching BACKwards, find the next character that is not a whitespace.
- *
+ *
* @param q Index to start from (at the end of the search space)
- * @param start Beginning of the search space.
- *
+ * @param start Beginning of the search space.
+ *
* @return const char* Address of the final non-whitespace character OR the same address as the start.
*/
static const char *findNextNonWSBack(const char *q, const char *start)
@@ -195,101 +195,116 @@
/**
* @brief Find bounds of stream.
- *
+ *
* PDF streams are prefixed with "stream" and suffixed with "endstream".
* Return value indicates success or failure.
- *
+ *
* @param start start address of search space.
- * @param bytesleft size of search space for "stream"
- * @param bytesleft2 size of search space for "endstream"
+ * @param size size of search space
* @param[out] stream output param, address of start of stream data
- * @param[out] endstream output param, address of end of stream data
+ * @param[out] stream_size output param, size of stream data
* @param newline_hack hack to support newlines that are \r\n, and not just \n or just \r.
- *
- * @return int 1 if stream bounds were found.
- * @return int 0 if stream bounds could not be found.
+ *
+ * @return cl_error_t CL_SUCCESS if stream bounds were found.
+ * @return cl_error_t CL_BREAK if stream bounds could not be found.
+ * @return cl_error_t CL_EFORMAT if stream start was found, but not end. (truncated)
+ * @return cl_error_t CL_EARG if invalid args were provided.
*/
-static int find_stream_bounds(
- const char *start,
- off_t bytesleft,
- off_t bytesleft2,
- off_t *stream,
- off_t *endstream,
+static cl_error_t find_stream_bounds(
+ const char *start,
+ size_t size,
+ const char **stream,
+ size_t *stream_size,
int newline_hack)
{
- const char *q2, *q;
+ cl_error_t status = CL_BREAK;
+
+ const char *idx;
+ const char *stream_begin;
+ const char *endstream_begin;
+ size_t bytesleft = size;
+
+ if ((NULL == start) || (0 == bytesleft) || (NULL == stream) || (NULL == stream_size)) {
+ status = CL_EARG;
+ return status;
+ }
+
+ *stream = NULL;
+ *stream_size = 0;
/* Begin by finding the "stream" string that prefixes stream data. */
- if ((q2 = cli_memstr(start, bytesleft, "stream", 6))) {
- q2 += 6;
- bytesleft -= q2 - start;
+ if ((stream_begin = cli_memstr(start, bytesleft, "stream", strlen("stream")))) {
+ idx = stream_begin + strlen("stream");
+ bytesleft -= idx - start;
if (bytesleft < 0)
- return 0;
+ goto done;
/* Skip any new line charcters. */
- if (bytesleft >= 2 && q2[0] == '\xd' && q2[1] == '\xa') {
- q2 += 2;
- if (newline_hack && (bytesleft > 2) && q2[0] == '\xa')
- q2++;
- } else if (bytesleft && q2[0] == '\xa') {
- q2++;
+ if (bytesleft >= 2 && idx[0] == '\xd' && idx[1] == '\xa') {
+ idx += 2;
+ if (newline_hack && (bytesleft > 2) && idx[0] == '\xa')
+ idx++;
+ } else if (bytesleft && idx[0] == '\xa') {
+ idx++;
}
- *stream = q2 - start;
+ /* Pass back start of the stream data. */
+ *stream = idx;
- bytesleft2 -= q2 - start;
- if (bytesleft2 <= 0)
- return 0;
+ bytesleft = size - (idx - start);
+ if (bytesleft <= 0)
+ goto done;
- /* Now find the "endstream" string that suffixes stream data */
- q = q2;
- q2 = cli_memstr(q, bytesleft2, "endstream", 9);
- if (!q2) {
+ /* Now find the "endstream" string that suffixes stream data. */
+ endstream_begin = cli_memstr(idx, bytesleft, "endstream", strlen("endstream"));
+ if (!endstream_begin) {
/* Couldn't find "endstream", but that's ok --
- * -- we'll just count the data we have until EOF. */
- q2 = q + bytesleft2-9; /* till EOF */
+ * -- we'll just count the rest of the provided buffer. */
+ cli_dbgmsg("find_stream_bounds: Truncated stream found!\n");
+ endstream_begin = start + size;
+ status = CL_EFORMAT;
}
- *endstream = q2 - start;
+ /* Pass back end of the stream data, as offset from start. */
+ *stream_size = endstream_begin - *stream;
- /* Double-check that endstream >= stream */
- if (*endstream < *stream)
- *endstream = *stream;
-
- return 1;
+ if (CL_EFORMAT != status)
+ status = CL_SUCCESS;
}
- return 0;
+done:
+
+ return status;
}
/**
- * @brief Find the next *indirect* object in an object stream, adds it to our list of
+ * @brief Find the next *indirect* object in an object stream, adds it to our list of
* objects, and increments nobj.
- *
+ *
* Indirect objects in a stream DON'T begin with "obj" and end with "endobj".
* Instead, they have an obj ID and an offset from the first object to point you
* right at them.
- *
+ *
* If found, objstm->current will be updated to the next obj id.
- *
- * All objects in an object stream are indirect and thus do not begin or start
- * with "obj" or "endobj". Instead, the object stream takes the following
+ *
+ * All objects in an object stream are indirect and thus do not begin or start
+ * with "obj" or "endobj". Instead, the object stream takes the following
* format.
- *
+ *
* <dictionary describing stream> objstm content endobjstm
- *
+ *
* where content looks something like the following:
- *
+ *
* 15 0 16 3 17 46 (ab)<</IDS 8 0 R/JavaScript 27 0 R/URLS 9 0 R>><</Names[(Test)28 0 R]>>
- *
- * In the above example, the literal string (ab) is indirect object # 15, and
- * begins at offset 0 of the set of objects. The next object, # 16 begis at
- * offset 3 is a dictionary. The final object is also a dictionary, beginning
+ *
+ * In the above example, the literal string (ab) is indirect object # 15, and
+ * begins at offset 0 of the set of objects. The next object, # 16 begis at
+ * offset 3 is a dictionary. The final object is also a dictionary, beginning
* at offset 46.
- *
- * @param pdf Pdf struct that keeps track of all information found in the PDF.
+ *
+ * @param pdf Pdf struct that keeps track of all information found in the PDF.
* @param objstm
- *
+ *
* @return CL_SUCCESS if success
* @return CL_EPARSE if parsing error
* @return CL_EMEM if error allocating memory
@@ -299,7 +314,8 @@
{
cl_error_t status = CL_EPARSE;
struct pdf_obj *obj = NULL;
- unsigned long objid = 0, objsize = 0, objoff = 0;
+ unsigned long objid = 0, objoff = 0;
+ long temp_long = 0;
const char *index = NULL;
size_t bytes_remaining = 0;
@@ -324,12 +340,17 @@
obj->objstm = objstm;
/* objstm->current_pair points directly to the obj id */
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
/* Failed to find objid */
cli_dbgmsg("pdf_findobj_in_objstm: Failed to find objid for obj in object stream\n");
status = CL_EPARSE;
goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative objid (%ld).\n", temp_long);
+ status = CL_EPARSE;
+ goto done;
}
+ objid = (unsigned long)temp_long;
/* Find the obj offset that appears just after the obj id*/
while ((index < objstm->streambuf + objstm->streambuf_len) && isdigit(*index)) {
@@ -339,11 +360,23 @@
index = findNextNonWS(index, objstm->streambuf + objstm->first);
bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &objoff)) {
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
/* Failed to find obj offset */
cli_dbgmsg("pdf_findobj_in_objstm: Failed to find obj offset for obj in object stream\n");
status = CL_EPARSE;
goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative obj offset (%ld).\n", temp_long);
+ status = CL_EPARSE;
+ goto done;
+ }
+ objoff = (unsigned long)temp_long;
+
+ if ((size_t)objstm->first + (size_t)objoff > objstm->streambuf_len) {
+ /* Alleged obj location is further than the length of the stream */
+ cli_dbgmsg("pdf_findobj_in_objstm: obj offset found is greater than the length of the stream.\n");
+ status = CL_EPARSE;
+ goto done;
}
objstm->current = objstm->first + objoff;
@@ -366,22 +399,27 @@
{
unsigned long next_objid = 0, next_objoff = 0;
- /*
- * While we're at it,
+ /*
+ * While we're at it,
* lets record the size as running up to the next object offset.
- *
+ *
* To do so, we will need to parse the next obj pair.
*/
/* objstm->current_pair points directly to the obj id */
index = objstm->streambuf + objstm->current_pair;
bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &next_objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
/* Failed to find objid for next obj */
cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next objid for obj in object stream though there should be {%u} more.\n", objstm->n - objstm->nobjs_found);
status = CL_EPARSE;
goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative objid (%ld).\n", temp_long);
+ status = CL_EPARSE;
+ goto done;
}
+ next_objid = (unsigned long)temp_long;
/* Find the obj offset that appears just after the obj id*/
while ((index < objstm->streambuf + objstm->streambuf_len) && isdigit(*index)) {
@@ -391,13 +429,19 @@
index = findNextNonWS(index, objstm->streambuf + objstm->first);
bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &next_objoff)) {
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
/* Failed to find obj offset for next obj */
cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next obj offset for obj in object stream though there should be {%u} more.\n", objstm->n - objstm->nobjs_found);
status = CL_EPARSE;
goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative obj offset (%ld).\n", temp_long);
+ status = CL_EPARSE;
+ goto done;
}
- else if (next_objoff <= objoff) {
+ next_objoff = (unsigned long)temp_long;
+
+ if (next_objoff <= objoff) {
/* Failed to find obj offset for next obj */
cli_dbgmsg("pdf_findobj_in_objstm: Found next obj offset for obj in object stream but it's less than or equal to the current one!\n");
status = CL_EPARSE;
@@ -411,14 +455,14 @@
}
obj->size = next_objoff - objoff;
- }
- else
+ }
+ else
{
/*
* Should be no more objects. We should verify.
- *
+ *
* Either way...
- * obj->size should be the rest of the buffer.
+ * obj->size should be the rest of the buffer.
*/
if (objstm->nobjs_found < objstm->n) {
cli_warnmsg("pdf_findobj_in_objstm: Fewer objects found in object stream than expected!\n");
@@ -471,10 +523,15 @@
cl_error_t pdf_findobj(struct pdf_struct *pdf)
{
cl_error_t status = CL_EPARSE;
- const char *start, *q, *q2, *q3, *eof;
+ const char *start, *idx, *genid_search_index, *objid_search_index;
+
+ const char *obj_begin = NULL, *obj_end = NULL;
+ const char *endobj_begin = NULL, *endobj_end = NULL;
+
struct pdf_obj *obj = NULL;
- off_t bytesleft;
+ size_t bytesleft;
unsigned long genid, objid;
+ long temp_long;
pdf->nobjs++;
pdf->objs = cli_realloc2(pdf->objs, sizeof(struct pdf_obj*) * pdf->nobjs);
@@ -495,169 +552,166 @@
start = pdf->map + pdf->offset;
bytesleft = pdf->size - pdf->offset;
- /* Indirect objects located outside of an object stream are prefaced with "obj"
- * and suffixed with "endobj". Find the "obj" preface. */
- while (bytesleft > 0)
- {
- q2 = cli_memstr(start, bytesleft, "obj", 3);
- if (!q2) {
- status = CL_BREAK; /* no more objs */
- goto done;
- }
-
- /* verify that "obj" has a whitespace before it, and is not the end of
- * a previous string like... "globj" */
- q2--;
- bytesleft -= q2 - start;
+ /*
+ * Start by searching for "obj"
+ */
+ idx = start + 1;
+ while (bytesleft > 1 + strlen("obj")) {
+ /* `- 1` accounts for size of white space before obj */
+ idx = cli_memstr(idx, bytesleft - 1, "obj", strlen("obj"));
+ if (NULL == idx) {
+ status = CL_BREAK;
+ goto done; /* No more objs. */
+ }
+
+ /* verify that the word has a whitespace before it, and is not the end of
+ * a previous word */
+ idx--;
+ bytesleft = (pdf->size - pdf->offset) - (size_t)(idx - start);
- if (*q2 != 0 && *q2 != 9 && *q2 != 0xa && *q2 != 0xc && *q2 != 0xd && *q2 != 0x20) {
- /* This instance of the "obj" string appears to be part of another string.
+ if (*idx != 0 && *idx != 9 && *idx != 0xa && *idx != 0xc && *idx != 0xd && *idx != 0x20) {
+ /* This instance of "obj" appears to be part of a longer string.
* Skip it, and keep searching for an object. */
- start = q2+4;
- bytesleft -= 4;
+ idx += 1 + strlen("obj");
+ bytesleft -= 1 + strlen("obj");
continue;
}
- break; /* Found it. q2 should point to the whitespace before the "obj" string */
- }
+ /* Found the beginning of the word */
+ obj_begin = idx;
+ obj_end = idx + 1 + strlen("obj");
- if (bytesleft <= 0) {
- status = CL_BREAK; /* No "obj" found. */
- goto done;
+ break;
}
- /* "obj" found! */
+ if ((NULL == obj_begin) || (NULL == obj_end)) {
+ status = CL_BREAK;
+ goto done; /* No more objs. */
+ }
/* Find the generation id (genid) that appears before the "obj" */
- q = findNextNonWSBack(q2-1, start);
- while (q > start && isdigit(*q))
- q--;
+ genid_search_index = findNextNonWSBack(obj_begin - 1, start);
+ while (genid_search_index > start && isdigit(*genid_search_index))
+ genid_search_index--;
- if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &genid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(genid_search_index, (size_t)((obj_begin) - genid_search_index), 0, 10, &temp_long)) {
cli_dbgmsg("pdf_findobj: Failed to parse object genid (# objects found: %u)\n", pdf->nobjs);
/* Failed to parse, probably not a real object. Skip past the "obj" thing, and continue. */
- pdf->offset = q2 + 4 - pdf->map;
+ pdf->offset = obj_end - pdf->map;
status = CL_EPARSE;
goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj: Encountered invalid negative obj genid (%ld).\n", temp_long);
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
+ goto done;
}
+ genid = (unsigned long)temp_long;
- /* Find the object id (objid) that appers before the genid */
- q = findNextNonWSBack(q-1,start);
- while (q > start && isdigit(*q))
- q--;
+ /* Find the object id (objid) that appears before the genid */
+ objid_search_index = findNextNonWSBack(genid_search_index - 1, start);
+ while (objid_search_index > start && isdigit(*objid_search_index))
+ objid_search_index--;
- if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(objid_search_index, (size_t)((genid_search_index) - objid_search_index), 0, 10, &temp_long)) {
/*
- * PDFs with multiple revisions will have %%EOF before the end of the file,
- * followed by the next revision of the PDF. If this is the case, we can
- * detect it and continue parsing after the %%EOF.
+ * Edge case:
+ *
+ * PDFs with multiple revisions will have %%EOF before the end of the file,
+ * followed by the next revision of the PDF, which will probably be an immediate objid.
+ *
+ * Example:
+ * %%EOF1 1 obj <blah> endobj
+ *
+ * If this is the case, we can detect it and continue parsing after the %%EOF.
*/
- if (q - 4 > start) {
- const char* lastfile = q - 4;
+ if (objid_search_index - strlen("\%\%EO") > start) {
+ const char* lastfile = objid_search_index - strlen("\%\%EO");
if (0 != strncmp(lastfile, "\%\%EOF", 5)) {
/* Nope, wasn't %%EOF */
cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
/* Skip past the "obj" thing, and continue. */
- pdf->offset = q2 + 4 - pdf->map;
- status = CL_EPARSE;
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
goto done;
}
- /* Yup, Looks, like the file continues after %%EOF.
+ /* Yup, Looks, like the file continues after %%EOF.
* Probably another revision. Keep parsing... */
- q++;
- cli_dbgmsg("pdf_findobj: \%\%EOF detected before end of file, at %zu\n", (size_t)q);
+ objid_search_index++;
+ cli_dbgmsg("pdf_findobj: \%\%EOF detected before end of file, at offset: %zu\n", (size_t)(objid_search_index - pdf->map));
} else {
/* Failed parsing at the very beginning */
cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
/* Probably not a real object. Skip past the "obj" thing, and continue. */
- pdf->offset = q2 + 4 - pdf->map;
- status = CL_EPARSE;
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
goto done;
}
/* Try again, with offset slightly adjusted */
- if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(objid_search_index, (size_t)((genid_search_index - 1) - objid_search_index), 0, 10, &temp_long)) {
cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
/* Still failed... Probably not a real object. Skip past the "obj" thing, and continue. */
- pdf->offset = q2 + 4 - pdf->map;
- status = CL_EPARSE;
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
+ goto done;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj: Encountered invalid negative objid (%ld).\n", temp_long);
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
goto done;
}
+
cli_dbgmsg("pdf_findobj: There appears to be an additional revision. Continuing to parse...\n");
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_findobj: Encountered invalid negative objid (%ld).\n", temp_long);
+ pdf->offset = obj_end - pdf->map;
+ status = CL_EPARSE;
+ goto done;
}
+ objid = (unsigned long)temp_long;
- /*
- * Ok so we have the objid, genid, and "obj" string.
- * Time to store that information and then ...
- * ... investigate what kind of object this is.
- */
obj->id = (objid << 8) | (genid & 0xff);
- obj->start = q2+4 - pdf->map; /* obj start begins just after the "obj" string */
+ obj->start = obj_end - pdf->map; /* obj start begins just after the "obj" string */
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; /* No interesting objects found, fast-forward to eof */
-
- bytesleft -= q2 - q;
- if (find_stream_bounds(q-1, q2-q, bytesleft + (q2-q), &p_stream, &p_endstream, 1)) {
- /*
- * Found obj that contains a stream.
- */
- obj->flags |= 1 << OBJ_STREAM;
- q2 = q-1 + p_endstream + 9;
- bytesleft -= q2 - q + 1;
-
- if (bytesleft < 0) {
- /* ... and the stream is truncated. Hmm... */
- obj->flags |= 1 << OBJ_TRUNCATED;
- pdf->offset = pdf->size;
-
- status = CL_SUCCESS;
- goto done; /* Truncated file, no end to obj/stream.
- * The next call to pdf_findobj() will return no more objects. */
- }
- } else if ((q3 = cli_memstr(q-1, q2-q+1, "endobj", 6))) {
- /*
- * obj found and offset positioned. ideal return case
- */
- q2 = q3 + 6;
- pdf->offset = q2 - pdf->map; /* update the offset to just after the endobj */
-
- status = CL_SUCCESS;
- goto done;
- } else {
- q2++;
- bytesleft--;
- }
+ /*
+ * We now have the objid, genid, and object start.
+ * Find the object end ("endobj").
+ */
+ /* `- 1` accounts for size of white space before obj */
+ endobj_begin = cli_memstr(obj_end, pdf->map + pdf->size - obj_end, "endobj", strlen("endobj"));
+ if (NULL == endobj_begin) {
+ /* No end to object.
+ * PDF appears to be malformed or truncated.
+ * Will record the object size as going ot the end of the file.
+ * Will record that the object is truncated.
+ * Will position the pdf offset to the end of the PDF.
+ * The next iteration of this function will find no more objects. */
+ obj->flags |= 1 << OBJ_TRUNCATED;
+ obj->size = (pdf->map + pdf->size) - obj_end;
+ pdf->offset = pdf->size;
- q = q2;
+ /* Truncated "object" found! */
+ status = CL_SUCCESS;
+ goto done;
}
+ endobj_end = endobj_begin + strlen("endobj");
- obj->flags |= 1 << OBJ_TRUNCATED;
- pdf->offset = pdf->size;
+ /* Size of the object goes from "obj" <-> "endobject". */
+ obj->size = endobj_begin - obj_end;
+ pdf->offset = endobj_end - pdf->map;
+ /*
+ * Object found!
+ */
status = CL_SUCCESS; /* truncated file, no end to obj. */
done:
if (status == CL_SUCCESS) {
- cli_dbgmsg("pdf_findobj: found %d %d obj @%lld\n", obj->id >> 8, obj->id&0xff, (long long)(obj->start + pdf->startoff));
+ cli_dbgmsg("pdf_findobj: found %d %d obj @%lld, size: %zu bytes.\n", obj->id >> 8, obj->id&0xff, (long long)(obj->start + pdf->startoff), obj->size);
}
else
{
- if(status == CL_BREAK) {
- cli_dbgmsg("pdf_findobj: No more objects (# objects found: %u)\n", pdf->nobjs);
- } else if(status == CL_EMEM) {
- cli_warnmsg("pdf_findobj: Error allocating memory (# objects found: %u)\n", pdf->nobjs);
- } else {
- cli_dbgmsg("pdf_findobj: Unexpected status code %d.\n", status);
- }
/* Remove the unused obj reference from our list of objects found */
/* No need to realloc pdf->objs back down. It won't leak. */
pdf->objs[pdf->nobjs-1] = NULL;
@@ -666,9 +720,17 @@
/* Free up the obj struct. */
if (NULL != obj)
free(obj);
+
+ if(status == CL_BREAK) {
+ cli_dbgmsg("pdf_findobj: No more objects (# objects found: %u)\n", pdf->nobjs);
+ } else if(status == CL_EMEM) {
+ cli_warnmsg("pdf_findobj: Error allocating memory (# objects found: %u)\n", pdf->nobjs);
+ } else {
+ cli_dbgmsg("pdf_findobj: Unexpected status code %d.\n", status);
+ }
}
- return status;
+ return status;
}
static size_t filter_writen(struct pdf_struct *pdf, struct pdf_obj *obj, int fout, const char *buf, size_t len, size_t *sum)
@@ -789,14 +851,14 @@
/**
* @brief Find and interpret the "/Length" dictionary key value.
- *
+ *
* The value may be:
- * - a direct object (i.e. just a number)
+ * - a direct object (i.e. just a number)
* - an indirect object, where the value is somewhere else in the document and we have to look it up.
* indirect objects are referenced using an object id (objid), generation id (genid) genid, and the letter 'R'.
- *
+ *
* Example dictionary with a single key "/Length" that relies direct object for the value.
- *
+ *
* 1 0 obj
* << /Length 534
* /Filter [ /ASCII85Decode /LZWDecode ]
@@ -810,9 +872,9 @@
* JD?M$0QP)lKn06l1apKDC@\qJ4B!!(5m+j.7F790m(Vj88l8Q:_CZ(Gm1%X\N1&u!FKHMB~>
* endstream
* endobj
- *
+ *
* Example dictionary with a single key "/Length" that relies on an indirect object for the value.
- *
+ *
* 7 0 obj
* << /Length 8 0 R >> % An indirect reference to object 8, with generation id 0.
* stream
@@ -823,11 +885,11 @@
* ET
* endstream
* endobj
- *
+ *
* 8 0 obj
* 77 % The length of the preceding stream
* endobj
- *
+ *
* @param pdf Pdf context structure.
* @param obj Pdf object context structure.
* @param start Pointer start of the dictionary string.
@@ -839,7 +901,7 @@
size_t length = 0;
const char *obj_start = dict_start;
size_t bytes_remaining = dict_len;
- unsigned long length_ul = 0;
+ long temp_long = 0;
const char *index;
if (bytes_remaining < 8) {
@@ -867,24 +929,27 @@
if (!obj_start)
return 0;
- if (bytes_remaining < obj_start - index) {
+ if (bytes_remaining < (size_t)(obj_start - index)) {
return 0;
}
bytes_remaining -= obj_start - index;
index = obj_start;
-
+
/* Read the value. This could either be the direct length value,
or the object id of the indirect object that has the length */
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &length_ul)) {
- cli_dbgmsg("find_length: failed to parse object length\n");
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
+ cli_dbgmsg("find_length: failed to parse object length or objid\n");
+ return 0;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("find_length: Encountered invalid negative object length or objid (%ld).\n", temp_long);
return 0;
}
- length = length_ul; /* length or maybe object id */
+ length = (size_t)temp_long; /* length or maybe object id */
- /*
- * Keep parsing, skipping past the first integer that might have been what we wanted.
- * If it's an indirect object, we'll find a Generation ID followed by the letter 'R'
- * I.e. something like " 0 R"
+ /*
+ * Keep parsing, skipping past the first integer that might have been what we wanted.
+ * If it's an indirect object, we'll find a Generation ID followed by the letter 'R'
+ * I.e. something like " 0 R"
*/
while ((bytes_remaining > 0) && isdigit(*index)) {
index++;
@@ -897,10 +962,14 @@
index++;
bytes_remaining--;
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &genid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
cli_dbgmsg("find_length: failed to parse object genid\n");
return 0;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("find_length: Encountered invalid negative object genid (%ld).\n", temp_long);
+ return 0;
}
+ genid = (unsigned long)temp_long;
while((bytes_remaining > 0) && isdigit(*index)) {
index++;
@@ -912,14 +981,14 @@
}
if (index[0] == ' ' && index[1] == 'R') {
- /*
- * Ok so we found a genid and that 'R'. Which means that first value
+ /*
+ * Ok so we found a genid and that 'R'. Which means that first value
* was actually the objid.
* We can look up the indirect object using this information.
*/
unsigned long objid = length;
const char* indirect_obj_start = NULL;
-
+
cli_dbgmsg("find_length: length is in indirect object %lu %lu\n", objid, genid);
obj = find_obj(pdf, obj, (length << 8) | (genid&0xff));
@@ -930,29 +999,33 @@
indirect_obj_start = pdf->map + obj->start;
bytes_remaining = pdf->size - obj->start;
-
+
/* Ok so we found the indirect object, lets read the value. */
index = pdf_nextobject(indirect_obj_start, bytes_remaining);
if (!index) {
cli_dbgmsg("find_length: next object not found\n");
return 0;
}
-
- if (bytes_remaining < index - indirect_obj_start) {
+
+ if (bytes_remaining < (size_t)(index - indirect_obj_start)) {
return 0;
}
bytes_remaining -= index - indirect_obj_start;
- /* Found the value, so lets parse it as an unsigned long */
- if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &length)) {
+ /* Found the value, so lets parse it as a long, but prohibit negative lengths. */
+ if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
cli_dbgmsg("find_length: failed to parse object length from indirect object\n");
return 0;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("find_length: Encountered invalid negative obj length (%ld).\n", temp_long);
+ return 0;
}
+ length = (size_t)temp_long;
}
}
/* limit length */
- if (obj_start - pdf->map + length + 5 > pdf->size)
+ if ((size_t)(obj_start - pdf->map) + length + 5 > pdf->size)
length = pdf->size - (obj_start - pdf->map) - 5;
return length;
@@ -960,102 +1033,6 @@
#define DUMP_MASK ((1 << OBJ_CONTENTS) | (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) | (1 << OBJ_LAUNCHACTION))
-static int obj_size(struct pdf_struct *pdf, struct pdf_obj *obj, int binary)
-{
- if (0 == obj->size)
- {
- /*
- * Programmatically determine size if not already known.
- */
- unsigned i = 0;
-
- /* Find the index of the current object */
- for (i = 0; i < pdf->nobjs; i++) {
- if (pdf->objs[i] == obj)
- break;
- }
-
- /* Find the next object that exists in the same buffer (pdf fmap, or object stream) */
- if (i < pdf->nobjs) {
- i++;
- }
-
- if (obj->objstm == NULL) {
- /* Current object isn't in an object stream, we want to find
- * the next object that also isn't in an object stream. */
- for ( ; i < pdf->nobjs; i++) {
- if (pdf->objs[i]->objstm == NULL)
- break;
- }
- } else {
- /* Current object is in an object stream, we want to find
- * the next object that is in the same object stream.
- *
- * This really shouldn't happen, so throw a warning and
- * then see if we can solve it anyhow */
- cli_warnmsg("obj_size: Encountered pdf object in an object stream that has an unknown size!!\n");
-
- for ( ; i < pdf->nobjs; i++) {
- if (pdf->objs[i]->objstm == obj->objstm)
- break;
- }
- }
-
- /* Step backwards from the "next" object to find the end of the current object */
- if (i < pdf->nobjs) {
- int s = pdf->objs[i]->start - obj->start - 4;
- if (s > 0) {
- if (!binary) {
- const char *p = NULL;
- const char *q = NULL;
-
- if (obj->objstm == NULL) {
- p = pdf->map + obj->start;
- } else {
- p = obj->objstm->streambuf + obj->start;
- }
- 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++;
-
- obj->size = q - p;
- goto done;
- }
-
- obj->size = s;
- goto done;
- }
- }
-
- /* If we've gotten this far, we didn't find a "next" object... so our
- * current object must be at the end of the pdf fmap or the end of the
- * object stream. */
- if (obj->objstm == NULL) {
- /* Current object isn't in an object stream, so we can determine object
- * size based on the remaining size of the file (in theory). */
- if (binary)
- obj->size = pdf->size - obj->start;
- else
- obj->size = pdf->offset - obj->start - 6; /* This hack I think assumes that we reached the end of the file when finding objects. */
- } else {
- /* Current object is in an object stream, we want to find
- * the next object that is in the same object stream. */
- obj->size = obj->objstm->streambuf_len - obj->start;
- }
- }
-
-done:
-
- return obj->size;
-}
-
static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, int dumpid)
{
int ret;
@@ -1424,330 +1401,328 @@
if (!(flags & PDF_EXTRACT_OBJ_SCAN))
obj->path = strdup(fullname);
- 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;
+ if ((NULL == obj->objstm) &&
+ (obj->flags & (1 << OBJ_STREAM))) {
+ /*
+ * Object contains a stream. Parse this now.
+ */
+ cli_dbgmsg("pdf_extract_obj: parsing a stream in obj %u %u\n", obj->id>>8, obj->id&0xff);
- if (NULL != obj->objstm) {
- cli_warnmsg("pdf_extract_obj: Object found in object stream claims to be an object stream! Skipping.\n");
- break;
+ const char *start = pdf->map + obj->start;
+
+ size_t length;
+ size_t orig_length;
+ int dict_len = obj->stream - start; /* Dictionary should end where the stream begins */
+
+ const char *pstr;
+ struct pdf_dict *dparams = NULL;
+ struct objstm_struct *objstm = NULL;
+ int xref = 0;
+
+ /* Find and interpret the length dictionary value */
+ length = find_length(pdf, obj, start, dict_len);
+ if (length < 0)
+ length = 0;
+
+ orig_length = length;
+
+ if (length > obj->stream_size) {
+ cli_dbgmsg("cli_pdf: Stream length exceeds object length by %zu bytes. Length truncated to %zu bytes\n", length - obj->stream_size, obj->stream_size);
+ noisy_warnmsg("Stream length exceeds object length by %zu bytes. Length truncated to %zu bytes\n", length - obj->stream_size, obj->stream_size);
+
+ length = obj->stream_size;
+ }
+
+ if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && (length <= 0)) {
+ /*
+ * If the length is unknown and this doesn't contain a FLATE encoded filter...
+ * Calculate the length using the stream size, and trimming
+ * off any newline/carriage returns from the end of the stream.
+ */
+ const char *q = start + obj->stream_size;
+ length = obj->stream_size;
+ q--;
+
+ if (*q == '\n') {
+ q--;
+ length--;
+
+ if (*q == '\r')
+ length--;
+ } else if (*q == '\r') {
+ length--;
}
- find_stream_bounds(start, pdf->size - obj->start,
- pdf->size - obj->start,
- &p_stream, &p_endstream,
- pdf->enc_method_stream <= ENC_IDENTITY &&
- pdf->enc_method_embeddedfile <= ENC_IDENTITY);
-
- if (p_stream && p_endstream) {
- size_t size = p_endstream - p_stream;
- off_t orig_length;
- int len = p_stream;
- const char *pstr;
- struct pdf_dict *dparams = NULL;
- struct objstm_struct *objstm = NULL;
- int xref = 0;
-
- 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: %lld + %lld > %lld\n",
- (long long)p_stream, (long long)length, (long long)pdf->size);
- noisy_warnmsg("length out of file, truncated: %lld + %lld > %lld\n",
- (long long)p_stream, (long long)length, (long long)pdf->size);
- length = pdf->size - (obj->start + p_stream);
- }
+ if (length < 0)
+ length = 0;
- if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && length <= 0) {
- const char *q = start + p_endstream;
- length = size;
- q--;
+ cli_dbgmsg("pdf_extract_obj: calculated length %lld\n", (long long)length);
+ } else {
+ if (obj->stream_size > (size_t)length + 2) {
+ cli_dbgmsg("cli_pdf: calculated length %zu < %zu\n",
+ (size_t)length, obj->stream_size);
+ length = obj->stream_size;
+ }
+ }
- if (*q == '\n') {
- q--;
- length--;
+ if ((0 != orig_length) && (obj->stream_size > (size_t)orig_length + 20)) {
+ cli_dbgmsg("pdf_extract_obj: orig length: %lld, length: %lld, size: %zu\n",
+ (long long)orig_length, (long long)length, obj->stream_size);
+ pdfobj_flag(pdf, obj, BAD_STREAMLEN);
+ }
- if (*q == '\r')
- length--;
- } else if (*q == '\r') {
- length--;
- }
+ if (0 == length) {
+ length = obj->stream_size;
+ if (0 == length) {
+ cli_dbgmsg("pdf_extract_obj: Alleged or calculated stream length and stream buffer size both 0\n");
+ goto done; /* Empty stream, nothing to scan */
+ }
+ }
- if (length < 0)
- length = 0;
+ /* Check if XRef is enabled */
+ if (cli_memstr(start, dict_len, "/XRef", strlen("/XRef"))) {
+ xref = 1;
+ }
- cli_dbgmsg("pdf_extract_obj: calculated length %lld\n", (long long)length);
- } else {
- if (size > (size_t)length+2) {
- cli_dbgmsg("cli_pdf: calculated length %zu < %zu\n",
- (size_t)length, size);
- length = size;
- }
- }
+ cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
- if (orig_length && size > (size_t)orig_length + 20) {
- cli_dbgmsg("pdf_extract_obj: orig length: %lld, length: %lld, size: %zu\n",
- (long long)orig_length, (long long)length, size);
- pdfobj_flag(pdf, obj, BAD_STREAMLEN);
- }
+ /*
+ * Identify the DecodeParms, if available.
+ */
+ if (NULL != (pstr = pdf_getdict(start, &dict_len, "/DecodeParms")))
+ {
+ cli_dbgmsg("pdf_extract_obj: Found /DecodeParms\n");
+ }
+ else if (NULL != (pstr = pdf_getdict(start, &dict_len, "/DP")))
+ {
+ cli_dbgmsg("pdf_extract_obj: Found /DP\n");
+ }
- if (!length) {
- length = size;
- if (!length) {
- cli_dbgmsg("pdf_extract_obj: length and size both 0\n");
- break; /* Empty stream, nothing to scan */
- }
- }
+ if (pstr) {
+ /* shift pstr left to "<<" for pdf_parse_dict */
+ while ((*pstr == '<') && (pstr > start)) {
+ pstr--;
+ dict_len++;
+ }
- if (cli_memstr(start, p_stream, "/XRef", 5))
- xref = 1;
+ /* shift pstr right to "<<" for pdf_parse_dict */
+ while ((*pstr != '<') && (dict_len > 0)) {
+ pstr++;
+ dict_len--;
+ }
- cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
+ if (dict_len > 4)
+ dparams = pdf_parse_dict(pdf, obj, obj->size, (char *)pstr, NULL);
+ else
+ cli_dbgmsg("pdf_extract_obj: failed to locate DecodeParms dictionary start\n");
+ }
- /*
- * Identify the DecodeParms, if available.
- */
- if (NULL != (pstr = pdf_getdict(start, &len, "/DecodeParms")))
- {
- cli_dbgmsg("pdf_extract_obj: Found /DecodeParms\n");
+ /*
+ * Go back to the start of the dictionary and check to see if the stream
+ * is an object stream. If so, collect the relevant info.
+ */
+ dict_len = obj->stream - start;
+ if (NULL != (pstr = pdf_getdict(start, &dict_len, "/Type/ObjStm")))
+ {
+ int32_t objstm_first = -1;
+ int32_t objstm_length = -1;
+ int32_t objstm_n = -1;
+
+ cli_dbgmsg("pdf_extract_obj: Found /Type/ObjStm\n");
+
+ dict_len = obj->stream - start;
+ if ((-1 == (objstm_first = pdf_readint(start, dict_len, "/First"))))
+ {
+ cli_warnmsg("pdf_extract_obj: Failed to find offset of first object in object stream\n");
+ }
+ else if ((-1 == (objstm_length = pdf_readint(start, dict_len, "/Length"))))
+ {
+ cli_warnmsg("pdf_extract_obj: Failed to find length of object stream\n");
+ }
+ else if ((-1 == (objstm_n = pdf_readint(start, dict_len, "/N"))))
+ {
+ cli_warnmsg("pdf_extract_obj: Failed to find num objects in object stream\n");
+ }
+ else
+ {
+ /* Add objstm to pdf struct, so it can be freed eventually */
+ pdf->nobjstms++;
+ pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
+ if (!pdf->objstms) {
+ cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
+ pdf_free_dict(dparams);
+ return CL_EMEM;
}
- else if (NULL != (pstr = pdf_getdict(start, &len, "/DP")))
- {
- cli_dbgmsg("pdf_extract_obj: Found /DP\n");
+
+ objstm = malloc(sizeof(struct objstm_struct));
+ if (!objstm) {
+ cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
+ pdf_free_dict(dparams);
+ return CL_EMEM;
}
+ pdf->objstms[pdf->nobjstms-1] = objstm;
- if (pstr) {
- unsigned int objsize = obj_size(pdf, obj, 1);
+ memset(objstm, 0, sizeof(*objstm));
- /* shift pstr left to "<<" for pdf_parse_dict */
- while ((*pstr == '<') && (pstr > start)) {
- pstr--;
- len++;
- }
+ objstm->first = (uint32_t)objstm_first;
+ objstm->current = (uint32_t)objstm_first;
+ objstm->current_pair = 0;
+ objstm->length = (uint32_t)objstm_length;
+ objstm->n = (uint32_t)objstm_n;
- /* shift pstr right to "<<" for pdf_parse_dict */
- while ((*pstr != '<') && (len > 0)) {
- pstr++;
- len--;
- }
+ cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %d\n", objstm->first);
+ cli_dbgmsg("pdf_extract_obj: ObjStm length is %d bytes\n", objstm->length);
+ cli_dbgmsg("pdf_extract_obj: ObjStm should contain %d objects\n", objstm->n);
+ }
+ }
- if (len > 4)
- dparams = pdf_parse_dict(pdf, obj, objsize, (char *)pstr, NULL);
- else
- cli_dbgmsg("pdf_extract_obj: failed to locate DecodeParms dictionary start\n");
- }
+ sum = pdf_decodestream(pdf, obj, dparams, obj->stream, (uint32_t)length, xref, fout, &rc, objstm);
+ if ((CL_SUCCESS != rc) && (CL_VIRUS != rc)) {
+ cli_dbgmsg("Error decoding stream! Error code: %d\n", rc);
+
+ /* It's ok if we couldn't decode the stream,
+ * make a best effort to keep parsing. */
+ if (CL_EPARSE == rc)
+ rc = CL_SUCCESS;
+ if (NULL != objstm) {
/*
- * Identify if the stream is an object stream. If so, collect the relevant info.
+ * If we were expecting an objstm and there was a failure...
+ * discard the memory for last object stream.
*/
- len = p_stream;
- if (NULL != (pstr = pdf_getdict(start, &len, "/Type/ObjStm")))
- {
- int32_t objstm_first = -1;
- int32_t objstm_length = -1;
- int32_t objstm_n = -1;
-
- cli_dbgmsg("pdf_extract_obj: Found /Type/ObjStm\n");
-
- len = p_stream;
- if ((-1 == (objstm_first = pdf_readint(start, len, "/First"))))
- {
- cli_warnmsg("pdf_extract_obj: Failed to find offset of first object in object stream\n");
- }
- else if ((-1 == (objstm_length = pdf_readint(start, len, "/Length"))))
- {
- cli_warnmsg("pdf_extract_obj: Failed to find length of object stream\n");
- }
- else if ((-1 == (objstm_n = pdf_readint(start, len, "/N"))))
- {
- cli_warnmsg("pdf_extract_obj: Failed to find num objects in object stream\n");
- }
- else
- {
- /* Add objstm to pdf struct, so it can be freed eventually */
- pdf->nobjstms++;
- pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
- if (!pdf->objstms) {
- cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
- pdf_free_dict(dparams);
- return CL_EMEM;
+ if (NULL != pdf->objstms) {
+ if (NULL != pdf->objstms[pdf->nobjstms - 1]) {
+ if (NULL != pdf->objstms[pdf->nobjstms - 1]->streambuf) {
+ free(pdf->objstms[pdf->nobjstms - 1]->streambuf);
+ pdf->objstms[pdf->nobjstms - 1]->streambuf = NULL;
}
-
- objstm = malloc(sizeof(struct objstm_struct));
- if (!objstm) {
- cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
- pdf_free_dict(dparams);
- return CL_EMEM;
- }
- pdf->objstms[pdf->nobjstms-1] = objstm;
-
- memset(objstm, 0, sizeof(*objstm));
-
- objstm->first = (uint32_t)objstm_first;
- objstm->current = (uint32_t)objstm_first;
- objstm->current_pair = 0;
- objstm->length = (uint32_t)objstm_length;
- objstm->n = (uint32_t)objstm_n;
-
- cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %d\n", objstm->first);
- cli_dbgmsg("pdf_extract_obj: ObjStm length is %d bytes\n", objstm->length);
- cli_dbgmsg("pdf_extract_obj: ObjStm should contain %d objects\n", objstm->n);
+ free(pdf->objstms[pdf->nobjstms - 1]);
+ pdf->objstms[pdf->nobjstms - 1] = NULL;
}
- }
- sum = pdf_decodestream(pdf, obj, dparams, start + p_stream, (uint32_t)length, xref, fout, &rc, objstm);
- if ((CL_SUCCESS != rc) && (CL_VIRUS != rc)) {
- cli_dbgmsg("Error decoding stream! Error code: %d\n", rc);
-
- /* It's ok if we couldn't decode the stream,
- * make a best effort to keep parsing. */
- if (CL_EPARSE == rc)
- rc = CL_SUCCESS;
-
- if (NULL != objstm) {
- /*
- * If we were expecting an objstm and there was a failure...
- * discard the memory for last object stream.
- */
- if (NULL != pdf->objstms) {
- if (NULL != pdf->objstms[pdf->nobjstms - 1]) {
- if (NULL != pdf->objstms[pdf->nobjstms - 1]->streambuf) {
- free(pdf->objstms[pdf->nobjstms - 1]->streambuf);
- pdf->objstms[pdf->nobjstms - 1]->streambuf = NULL;
- }
- free(pdf->objstms[pdf->nobjstms - 1]);
- pdf->objstms[pdf->nobjstms - 1] = NULL;
- }
+ /* Pop the objstm off the end of the pdf->objstms array. */
+ if (pdf->nobjstms > 0) {
+ pdf->nobjstms--;
+ if (0 == pdf->nobjstms) {
+ free(pdf->objstms);
+ pdf->objstms = NULL;
+ } else {
+ pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
- /* Pop the objstm off the end of the pdf->objstms array. */
- if (pdf->nobjstms > 0) {
- pdf->nobjstms--;
- if (0 == pdf->nobjstms) {
- free(pdf->objstms);
- pdf->objstms = NULL;
- } else {
- pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
-
- if (!pdf->objstms) {
- cli_warnmsg("pdf_extract_obj: out of memory when shrinking down objstm array\n");
- return CL_EMEM;
- }
- }
- } else {
- /* hm.. this shouldn't happen */
- cli_warnmsg("pdf_extract_obj: Failure counting objstms.\n");
+ if (!pdf->objstms) {
+ cli_warnmsg("pdf_extract_obj: out of memory when shrinking down objstm array\n");
+ return CL_EMEM;
}
}
+ } else {
+ /* hm.. this shouldn't happen */
+ cli_warnmsg("pdf_extract_obj: Failure counting objstms.\n");
}
}
+ }
+ }
- if (dparams)
- pdf_free_dict(dparams);
+ if (dparams)
+ pdf_free_dict(dparams);
- if ((rc == CL_VIRUS) && !SCAN_ALLMATCHES) {
- sum = 0; /* prevents post-filter scan */
- break;
- }
+ if ((rc == CL_VIRUS) && !SCAN_ALLMATCHES) {
+ sum = 0; /* prevents post-filter scan */
+ goto done;
+ }
- cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
- } else {
- noisy_warnmsg("pdf_extract_obj: cannot find stream bounds for obj %u %u\n", obj->id>>8, obj->id&0xff);
- }
+ cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
- } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
- const char *q2;
- const char *q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
- : (const char *)(obj->start + pdf->map);
+ } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
+ const char *q2;
+ const char *q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
+ : (const char *)(obj->start + pdf->map);
- /* TODO: get obj-endobj size */
- off_t bytesleft = obj_size(pdf, obj, 0);
+ /* TODO: get obj-endobj size */
+ off_t bytesleft = obj->size;
- if (bytesleft < 0)
- break;
+ if (bytesleft < 0) {
+ goto done;
+ }
- do {
- char *js = NULL;
- size_t js_len = 0;
- const char *q3;
+ do {
+ char *js = NULL;
+ size_t js_len = 0;
+ const char *q3;
- q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
- if (!q2)
- break;
+ q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
+ if (!q2)
+ break;
- bytesleft -= q2 - q + 11;
- q = q2 + 11;
+ bytesleft -= q2 - q + 11;
+ q = q2 + 11;
- js = pdf_readstring(q, bytesleft, "/JS", NULL, &q2, !(pdf->flags & (1<<DECRYPTABLE_PDF)));
- bytesleft -= q2 - q;
- q = q2;
-
- if (js) {
- char *decrypted = NULL;
- const char *out = js;
- js_len = strlen(js);
- if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
- cli_dbgmsg("pdf_extract_obj: encrypted string\n");
- decrypted = decrypt_any(pdf, obj->id, js, &js_len, pdf->enc_method_string);
-
- if (decrypted) {
- noisy_msg(pdf, "pdf_extract_obj: decrypted Javascript string from obj %u %u\n", obj->id>>8,obj->id&0xff);
- out = decrypted;
- }
+ js = pdf_readstring(q, bytesleft, "/JS", NULL, &q2, !(pdf->flags & (1<<DECRYPTABLE_PDF)));
+ bytesleft -= q2 - q;
+ q = q2;
+
+ if (js) {
+ char *decrypted = NULL;
+ const char *out = js;
+ js_len = strlen(js);
+ if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
+ cli_dbgmsg("pdf_extract_obj: encrypted string\n");
+ decrypted = decrypt_any(pdf, obj->id, js, &js_len, pdf->enc_method_string);
+
+ if (decrypted) {
+ noisy_msg(pdf, "pdf_extract_obj: decrypted Javascript string from obj %u %u\n", obj->id>>8,obj->id&0xff);
+ out = decrypted;
}
+ }
- if (filter_writen(pdf, obj, fout, out, js_len, (size_t*)&sum) != js_len) {
- rc = CL_EWRITE;
- free(js);
- break;
- }
+ if (filter_writen(pdf, obj, fout, out, js_len, (size_t*)&sum) != js_len) {
+ rc = CL_EWRITE;
+ free(js);
+ break;
+ }
- free(decrypted);
- free(js);
- cli_dbgmsg("pdf_extract_obj: bytesleft: %d\n", (int)bytesleft);
-
- if (bytesleft > 0) {
- q2 = pdf_nextobject(q, bytesleft);
- if (!q2)
- q2 = q + bytesleft - 1;
-
- /* non-conforming PDFs that don't escape ) properly */
- q3 = memchr(q, ')', bytesleft);
- if (q3 && q3 < q2)
- q2 = q3;
-
- while (q2 > q && q2[-1] == ' ')
- q2--;
-
- if (q2 > q) {
- q--;
- filter_writen(pdf, obj, fout, q, q2 - q, (size_t*)&sum);
- q++;
- }
+ free(decrypted);
+ free(js);
+ cli_dbgmsg("pdf_extract_obj: bytesleft: %d\n", (int)bytesleft);
+
+ if (bytesleft > 0) {
+ q2 = pdf_nextobject(q, bytesleft);
+ if (!q2)
+ q2 = q + bytesleft - 1;
+
+ /* non-conforming PDFs that don't escape ) properly */
+ q3 = memchr(q, ')', bytesleft);
+ if (q3 && q3 < q2)
+ q2 = q3;
+
+ while (q2 > q && q2[-1] == ' ')
+ q2--;
+
+ if (q2 > q) {
+ q--;
+ filter_writen(pdf, obj, fout, q, q2 - q, (size_t*)&sum);
+ q++;
}
}
+ }
- } while (bytesleft > 0);
- } else {
- off_t bytesleft = obj_size(pdf, obj, 0);
+ } while (bytesleft > 0);
+ } else {
+ off_t bytesleft = obj->size;
- if (bytesleft < 0)
- rc = CL_EFORMAT;
- else {
- if (obj->objstm) {
- if (filter_writen(pdf, obj, fout , obj->objstm->streambuf + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
- rc = CL_EWRITE;
- } else {
- if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
- rc = CL_EWRITE;
- }
+ if (bytesleft < 0)
+ rc = CL_EFORMAT;
+ else {
+ if (obj->objstm) {
+ if (filter_writen(pdf, obj, fout , obj->objstm->streambuf + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
+ rc = CL_EWRITE;
+ } else {
+ if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
+ rc = CL_EWRITE;
}
}
- } while (0);
+ }
+
+done:
cli_dbgmsg("pdf_extract_obj: extracted %td bytes %u %u obj\n", sum, obj->id>>8, obj->id&0xff);
cli_dbgmsg("pdf_extract_obj: ... to %s\n", fullname);
@@ -1977,6 +1952,7 @@
const char *q, *q2;
unsigned long objid;
unsigned long genid;
+ long temp_long;
if (len >= 16 && !strncmp(enc, "/EncryptMetadata", 16)) {
q = cli_memstr(enc+16, len-16, "/Encrypt", 8);
@@ -1995,10 +1971,15 @@
len -= q2 - q;
q = q2;
- if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)len, 0, 10, &objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)len, 0, 10, &temp_long)) {
cli_dbgmsg("pdf_parse_encrypt: Found Encrypt dictionary but failed to parse objid\n");
return;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_parse_encrypt: Encountered invalid negative objid (%ld).\n", temp_long);
+ return;
}
+ objid = (unsigned long)temp_long;
+
objid = objid << 8;
q2 = pdf_nextobject(q, len);
if (!q2 || !isdigit(*q2))
@@ -2006,11 +1987,16 @@
len -= q2 - q;
q = q2;
- if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)len, 0, 10, &genid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)len, 0, 10, &temp_long)) {
cli_dbgmsg("pdf_parse_encrypt: Found Encrypt dictionary but failed to parse genid\n");
return;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_parse_encrypt: Encountered invalid negative genid (%ld).\n", temp_long);
+ return;
}
- objid |= genid & 0xff;
+ genid = (unsigned long)temp_long;
+
+ objid |= genid & 0xff;
q2 = pdf_nextobject(q, len);
if (!q2 || *q2 != 'R')
return;
@@ -2047,7 +2033,7 @@
const char *nextobj = NULL, *nextopen = NULL, *nextclose = NULL;
const char *q = NULL;
const char *dict = NULL, *enddict = NULL, *start = NULL;
- off_t dict_length = 0, full_dict_length = 0, objsize = 0, bytesleft = 0;
+ off_t dict_length = 0, full_dict_length = 0, bytesleft = 0;
size_t i = 0;
unsigned filters = 0, blockopens = 0;
enum objstate objstate = STATE_NONE;
@@ -2055,16 +2041,63 @@
json_object *pdfobj=NULL, *jsonobj=NULL;
#endif
- q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
- : (const char *)(obj->start + pdf->map);
+ if (NULL == pdf || NULL == obj) {
+ cli_warnmsg("pdf_parseobj: invalid arguments\n");
+ return;
+ }
+
+ cli_dbgmsg("pdf_parseobj: Parsing object %u %u\n", obj->id >> 8, obj->id & 0xff);
- objsize = obj_size(pdf, obj, 1);
+ if (obj->objstm) {
+ if ((size_t)obj->start > obj->objstm->streambuf_len) {
+ cli_dbgmsg("pdf_parseobj: %u %u obj: obj start (%u) is greater than size of object stream (%zu).\n",
+ obj->id >> 8, obj->id & 0xff, obj->start, obj->objstm->streambuf_len);
+ return;
+ }
+ q = (const char *)(obj->start + obj->objstm->streambuf);
+ } else {
+ if ((size_t)obj->start > pdf->size) {
+ cli_dbgmsg("pdf_parseobj: %u %u obj: obj start (%u) is greater than size of PDF (%lld).\n",
+ obj->id >> 8, obj->id & 0xff, obj->start, (long long)pdf->size);
+ return;
+ }
+ q = (const char *)(obj->start + pdf->map);
+ }
+ start = q;
- if (objsize < 0)
+ if (obj->size <= 0)
return;
- start = q;
- bytesleft = objsize;
+ if (obj->objstm) {
+ bytesleft = MIN(obj->size, obj->objstm->streambuf_len - obj->start);
+ } else {
+ bytesleft = MIN(obj->size, pdf->size - obj->start);
+ }
+
+ /* For objects that aren't already in an object stream^, check if they contain a stream.
+ * ^Objects in object streams aren't supposed to contain streams, so we don't check them. */
+ if (NULL == obj->objstm) {
+ /* Check if object contains stream */
+ cl_error_t has_stream;
+ const char* stream = NULL;
+ size_t stream_size = 0;
+
+ has_stream = find_stream_bounds(
+ start,
+ obj->size,
+ &stream,
+ &stream_size,
+ (pdf->enc_method_stream <= ENC_IDENTITY) && (pdf->enc_method_embeddedfile <= ENC_IDENTITY));
+
+ if ((CL_SUCCESS == has_stream) ||
+ (CL_EFORMAT == has_stream)) {
+ /* Stream found. Store this fact and the stream bounds. */
+ cli_dbgmsg("pdf_parseobj: %u %u contains stream, size: %zu\n", obj->id>>8, obj->id&0xff, stream_size);
+ obj->flags |= (1 << OBJ_STREAM);
+ obj->stream = stream;
+ obj->stream_size = stream_size;
+ }
+ }
/* find start of dictionary */
do {
@@ -2090,7 +2123,23 @@
return;
}
+ /*
+ * Opening `<` for object's dictionary may be back 1 character,
+ * provided q is not at the start of the buffer (it shouldn't be).
+ */
+ if (obj->objstm) {
+ if (obj->objstm->streambuf == q) {
+ q3 = memchr(q, '<', nextobj - q);
+ } else {
q3 = memchr(q-1, '<', nextobj-q+1);
+ }
+ } else {
+ if (pdf->map == q) {
+ q3 = memchr(q, '<', nextobj - q);
+ } else {
+ q3 = memchr(q - 1, '<', nextobj - q + 1);
+ }
+ }
nextobj++;
bytesleft--;
q = nextobj;
@@ -2098,7 +2147,7 @@
dict = q3+2;
q = dict;
blockopens++;
- bytesleft = objsize - (q - start);
+ bytesleft = obj->size - (q - start);
enddict = q + bytesleft - 1;
/* find end of dictionary block */
@@ -2249,7 +2298,7 @@
pdfobj_flag(pdf, obj, LINEARIZED_PDF);
objstate = STATE_NONE;
trailer_end = pdf_readint(dict, full_dict_length, "/H");
- if (trailer_end > 0 && trailer_end < pdf->size) {
+ if ((trailer_end > 0) && ((size_t)trailer_end < pdf->size)) {
trailer = trailer_end - 1024;
if (trailer < 0)
trailer = 0;
@@ -2275,26 +2324,39 @@
const char * q2_old = NULL;
unsigned long objid;
unsigned long genid;
+ long temp_long;
dict_remaining -= (off_t)(q2 - q);
- if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)dict_remaining, 0, 10, &objid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)dict_remaining, 0, 10, &temp_long)) {
cli_dbgmsg("pdf_parseobj: failed to parse object objid\n");
return;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_parseobj: Encountered invalid negative genid (%ld).\n", temp_long);
+ return;
}
+ objid = (unsigned long)temp_long;
+
objid = objid << 8;
- while (isdigit(*q2))
+ while ((dict_remaining > 0) && isdigit(*q2)) {
q2++;
+ dict_remaining--;
+ }
q2_old = q2;
q2 = pdf_nextobject(q2, dict_remaining);
if (q2 && isdigit(*q2)) {
dict_remaining -= (off_t)(q2 - q2_old);
- if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)dict_remaining, 0, 10, &genid)) {
+ if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)dict_remaining, 0, 10, &temp_long)) {
cli_dbgmsg("pdf_parseobj: failed to parse object genid\n");
return;
+ } else if (temp_long < 0) {
+ cli_dbgmsg("pdf_parseobj: Encountered invalid negative genid (%ld).\n", temp_long);
+ return;
}
+ genid = (unsigned long)temp_long;
+
objid |= genid & 0xff;
q2 = pdf_nextobject(q2, dict_remaining);
@@ -2848,7 +2910,7 @@
return;
}
- len = obj_size(pdf, obj, 1);
+ len = obj->size;
q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
: (const char *)(obj->start + pdf->map);
@@ -3004,30 +3066,32 @@
}
/**
- * @brief Search pdf buffer for objects. Parse each.
- *
+ * @brief Search pdf buffer for objects. Parse each.
+ *
* Newly found objects will be extracted after completion when the extraction for loop continues.
- *
- * @param pdf Pdf struct that keeps track of all information found in the PDF.
+ *
+ * @param pdf Pdf struct that keeps track of all information found in the PDF.
* @param objstm Pointer to an object stream to parse.
- *
+ *
* @return cl_error_t Error code.
*/
cl_error_t pdf_find_and_parse_objs_in_objstm(struct pdf_struct *pdf, struct objstm_struct *objstm)
{
cl_error_t status = CL_EFORMAT;
cl_error_t retval = CL_EPARSE;
- int32_t foundobj = 0, alerts = 0;
+ int32_t alerts = 0;
uint32_t badobjects = 0;
size_t i = 0;
struct pdf_obj* obj = NULL;
- char* current_pair = objstm->streambuf;
- char* current_obj = objstm->streambuf + objstm->first;
+ if ((NULL == objstm) || (NULL == objstm->streambuf)) {
+ status = CL_EARG;
+ goto done;
+ }
- if ((0 == objstm->first) ||
- (0 == objstm->streambuf_len) ||
+ if ((0 == objstm->first) ||
+ (0 == objstm->streambuf_len) ||
(0 == objstm->n))
{
cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Empty object stream.\n");
@@ -3053,7 +3117,7 @@
/* Find object */
retval = pdf_findobj_in_objstm(pdf, objstm, &obj);
-
+
if (retval != CL_SUCCESS)
{
cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Fewer objects in stream than expected: %u found, %u expected.\n",
@@ -3083,7 +3147,7 @@
status = CL_EFORMAT;
goto done;
}
-
+
status = CL_SUCCESS;
done:
@@ -3092,18 +3156,17 @@
/**
* @brief Search pdf buffer for objects. Parse each and then extract each.
- *
+ *
* @param pdf Pdf struct that keeps track of all information found in the PDF.
* @param alerts[in/out] The number of alerts, relevant in ALLMATCH mode.
- *
+ *
* @return cl_error_t Error code.
*/
cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
{
cl_error_t status = CL_SUCCESS;
int32_t rv = 0;
- int foundobj = 0;
- unsigned int i = 0, j = 0;
+ unsigned int i = 0;
uint32_t badobjects = 0;
cli_ctx *ctx = pdf->ctx;
@@ -3145,7 +3208,7 @@
* This doesn't trigger for PDFs that are encrypted but don't need
* a password to decrypt */
status = cli_append_virus(pdf->ctx, "Heuristics.Encrypted.PDF");
- if (status == CL_VIRUS) {
+ if (status == CL_VIRUS) {
alerts++;
if (SCAN_ALLMATCHES)
status = CL_CLEAN;
@@ -3204,11 +3267,11 @@
/**
* @brief Primary function for parsing and scanning a PDF.
- *
+ *
* @param dir Filepath for temp file.
- * @param ctx clam scan context structure.
+ * @param ctx clam scan context structure.
* @param offset offset of pdf in ctx->fmap
- *
+ *
* @return int Returns cl_error_t status value.
*/
int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
@@ -3220,6 +3283,7 @@
off_t versize = size > 1032 ? 1032 : size;
off_t map_off, bytesleft;
unsigned long xref;
+ long temp_long;
const char *pdfver, *tmp, *start, *eofmap, *q, *eof;
unsigned i, alerts = 0;
unsigned int objs_found = 0;
@@ -3361,11 +3425,14 @@
while (q < eof && (*q == ' ' || *q == '\n' || *q == '\r')) { q++; }
- if (CL_SUCCESS != cli_strntoul_wrap(q, q - eofmap + map_off, 0, 10, &xref)) {
+ if (CL_SUCCESS != cli_strntol_wrap(q, q - eofmap + map_off, 0, 10, &temp_long)) {
cli_dbgmsg("cli_pdf: failed to parse PDF trailer xref\n");
pdf.flags |= 1 << BAD_PDF_TRAILER;
- }
- else {
+ } else if (temp_long < 0) {
+ cli_dbgmsg("cli_pdf: Encountered invalid negative PDF trailer xref (%ld).\n", temp_long);
+ pdf.flags |= 1 << BAD_PDF_TRAILER;
+ } else {
+ xref = (unsigned long)temp_long;
bytesleft = map->len - offset - xref;
if (bytesleft > 4096)
bytesleft = 4096;
@@ -3404,7 +3471,7 @@
}
/*
- * Find and extract all objects in the PDF.
+ * Find and extract all objects in the PDF.
* New experimental recursive methodology that adds objects from object streams.
*/
objs_found = pdf.nobjs;
@@ -3505,15 +3572,20 @@
/**
* @brief Skip the rest of the current line, and find the start of the next line.
- *
+ *
* @param ptr Current offset into buffer.
- * @param len Remaining bytes in buffer.
- *
+ * @param len Remaining bytes in buffer.
+ *
* @return const char* Address of next line, or NULL if no next line in buffer.
*/
static const char *
pdf_nextlinestart(const char *ptr, size_t len)
{
+ if (!ptr || (0 == len)) {
+ /* Invalid args */
+ return NULL;
+ }
+
while(strchr("\r\n", *ptr) == NULL) {
if(--len == 0L)
return NULL;
@@ -3533,13 +3605,13 @@
/**
* @brief Return the start of the next PDF object.
- *
+ *
* This assumes that we're not in a stream.
- *
+ *
* @param ptr Current offset into buffer.
- * @param len Remaining bytes in buffer.
- *
- * @return const char* Address of next object in the buffer, or NULL if there is none in the buffer.
+ * @param len Remaining bytes in buffer.
+ *
+ * @return const char* Address of next object in the buffer, or NULL if there is none in the buffer.
*/
static const char *
pdf_nextobject(const char *ptr, size_t len)
@@ -3882,7 +3954,7 @@
pdf->stats.author = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.author))
return;
- pdf->stats.author->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Author", NULL, &(pdf->stats.author->meta));
+ pdf->stats.author->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Author", NULL, &(pdf->stats.author->meta));
}
}
#endif
@@ -3907,7 +3979,7 @@
pdf->stats.creator = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.creator))
return;
- pdf->stats.creator->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Creator", NULL, &(pdf->stats.creator->meta));
+ pdf->stats.creator->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Creator", NULL, &(pdf->stats.creator->meta));
}
}
#endif
@@ -3932,7 +4004,7 @@
pdf->stats.modificationdate = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.modificationdate))
return;
- pdf->stats.modificationdate->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/ModDate", NULL, &(pdf->stats.modificationdate->meta));
+ pdf->stats.modificationdate->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/ModDate", NULL, &(pdf->stats.modificationdate->meta));
}
}
#endif
@@ -3957,7 +4029,7 @@
pdf->stats.creationdate = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.creationdate))
return;
- pdf->stats.creationdate->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/CreationDate", NULL, &(pdf->stats.creationdate->meta));
+ pdf->stats.creationdate->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/CreationDate", NULL, &(pdf->stats.creationdate->meta));
}
}
#endif
@@ -3982,7 +4054,7 @@
pdf->stats.producer = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.producer))
return;
- pdf->stats.producer->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Producer", NULL, &(pdf->stats.producer->meta));
+ pdf->stats.producer->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Producer", NULL, &(pdf->stats.producer->meta));
}
}
#endif
@@ -4007,7 +4079,7 @@
pdf->stats.title = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.title))
return;
- pdf->stats.title->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Title", NULL, &(pdf->stats.title->meta));
+ pdf->stats.title->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Title", NULL, &(pdf->stats.title->meta));
}
}
#endif
@@ -4032,7 +4104,7 @@
pdf->stats.keywords = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.keywords))
return;
- pdf->stats.keywords->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Keywords", NULL, &(pdf->stats.keywords->meta));
+ pdf->stats.keywords->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Keywords", NULL, &(pdf->stats.keywords->meta));
}
}
#endif
@@ -4057,7 +4129,7 @@
pdf->stats.subject = cli_calloc(1, sizeof(struct pdf_stats_entry));
if (!(pdf->stats.subject))
return;
- pdf->stats.subject->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Subject", NULL, &(pdf->stats.subject->meta));
+ pdf->stats.subject->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Subject", NULL, &(pdf->stats.subject->meta));
}
}
#endif
@@ -4109,8 +4181,8 @@
const char *objstart = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
: (const char *)(obj->start + pdf->map);
const char *begin;
- unsigned int objsize;
unsigned long npages=0, count;
+ long temp_long;
struct pdf_array_node *node;
json_object *pdfobj;
size_t countsize = 0;
@@ -4123,19 +4195,17 @@
if (!(SCAN_COLLECT_METADATA))
return;
- objsize = obj_size(pdf, obj, 1);
-
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
if (!(pdfobj))
return;
- begin = cli_memstr(objstart, objsize, "/Kids", 5);
+ begin = cli_memstr(objstart, obj->size, "/Kids", 5);
if (!(begin))
return;
begin += 5;
- array = pdf_parse_array(pdf, obj, objsize, (char *)begin, NULL);
+ array = pdf_parse_array(pdf, obj, obj->size, (char *)begin, NULL);
if (!(array)) {
cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
return;
@@ -4146,27 +4216,33 @@
if (strchr((char *)(node->data), 'R'))
npages++;
- begin = cli_memstr(objstart, objsize, "/Count", 6);
+ begin = cli_memstr(objstart, obj->size, "/Count", 6);
if (!(begin)) {
cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
goto cleanup;
}
begin += 6;
- while (begin - objstart < objsize && isspace(begin[0]))
+ while (((size_t)(begin - objstart) < obj->size) && isspace(begin[0]))
begin++;
- if (begin - objstart >= objsize) {
+ if ((size_t)(begin - objstart) >= obj->size) {
goto cleanup;
}
- countsize = (obj->objstm) ? (size_t)(obj->start + obj->objstm->streambuf + objsize - begin)
- : (size_t)(obj->start + pdf->map + objsize - begin);
+ countsize = (obj->objstm) ? (size_t)(obj->start + obj->objstm->streambuf + obj->size - begin)
+ : (size_t)(obj->start + pdf->map + obj->size - begin);
- if ((CL_SUCCESS != cli_strntoul_wrap(begin, countsize, 0, 10, &count)) ||
- (count != npages)) {
+ if (CL_SUCCESS != cli_strntol_wrap(begin, countsize, 0, 10, &temp_long)) {
+ cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
+ } else if (temp_long < 0) {
+ cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
+ } else {
+ count = (unsigned long)temp_long;
+ if (count != npages) {
cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
}
+ }
cleanup:
pdf_free_array(array);
@@ -4179,10 +4255,10 @@
cli_ctx *ctx = pdf->ctx;
json_object *colorsobj, *pdfobj;
unsigned long ncolors;
+ long temp_long;
char *p1;
const char *objstart = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
: (const char *)(obj->start + pdf->map);
- size_t objsize;
UNUSEDPARAM(act);
@@ -4192,26 +4268,28 @@
if (!(SCAN_COLLECT_METADATA))
return;
- objsize = obj_size(pdf, obj, 1);
-
- p1 = (char *)cli_memstr(objstart, objsize, "/Colors", 7);
+ p1 = (char *)cli_memstr(objstart, obj->size, "/Colors", 7);
if (!(p1))
return;
p1 += 7;
/* Ensure that we have at least one whitespace character plus at least one number */
- if (objsize - (p1 - objstart) < 2)
+ if (obj->size - (size_t)(p1 - objstart) < 2)
return;
- while (p1 - objstart < objsize && isspace(p1[0]))
+ while (((size_t)(p1 - objstart) < obj->size) && isspace(p1[0]))
p1++;
- if ((size_t)(p1 - objstart) == objsize)
+ if ((size_t)(p1 - objstart) == obj->size)
return;
- if (CL_SUCCESS != cli_strntoul_wrap(p1, (size_t)((p1 - objstart) - objsize), 0, 10, &ncolors))
+ if (CL_SUCCESS != cli_strntol_wrap(p1, (size_t)((p1 - objstart) - obj->size), 0, 10, &temp_long)) {
return;
+ } else if (temp_long < 0) {
+ return;
+ }
+ ncolors = (unsigned long)temp_long;
/* We only care if the number of colors > 2**24 */
if (ncolors < 1<<24)
diff -Nru clamav-0.101.1+dfsg/libclamav/pdf.h clamav-0.101.2+dfsg/libclamav/pdf.h
--- clamav-0.101.1+dfsg/libclamav/pdf.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/pdf.h 2019-03-13 22:13:01.000000000 +0100
@@ -37,12 +37,14 @@
struct pdf_obj {
uint32_t start;
- int32_t size;
+ size_t size;
uint32_t id;
uint32_t flags;
uint32_t statsflags;
uint32_t numfilters;
uint32_t filterlist[PDF_FILTERLIST_MAX];
+ const char *stream; // pointer to stream contained in object.
+ size_t stream_size; // size of stream contained in object.
struct objstm_struct *objstm; // Should be NULL unless the obj exists in an object stream (separate buffer)
char *path;
};
@@ -146,7 +148,7 @@
const char *CF;
long CF_n;
const char *map;
- off_t size;
+ size_t size;
off_t offset;
off_t startoff;
cli_ctx *ctx;
diff -Nru clamav-0.101.1+dfsg/libclamav/scanners.c clamav-0.101.2+dfsg/libclamav/scanners.c
--- clamav-0.101.1+dfsg/libclamav/scanners.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/scanners.c 2019-03-13 22:13:01.000000000 +0100
@@ -223,16 +223,15 @@
/**
* @brief Scan the metadata using cli_matchmeta()
- *
+ *
* @param metadata unrar metadata structure
* @param ctx scanning context structure
- * @param files
+ * @param files
* @return cl_error_t Returns CL_CLEAN if nothing found, CL_VIRUS if something found, CL_EUNPACK if encrypted.
*/
static cl_error_t cli_unrar_scanmetadata(unrar_metadata_t* metadata, cli_ctx* ctx, unsigned int files)
{
cl_error_t status = CL_CLEAN;
- int virus_found = 0;
cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
metadata->filename, metadata->crc, metadata->encrypted, (unsigned int)metadata->pack_size,
@@ -246,8 +245,6 @@
status = CL_EUNPACK;
}
-done:
-
return status;
}
@@ -255,9 +252,8 @@
{
cl_error_t status = CL_EPARSE;
cl_unrar_error_t unrar_ret = UNRAR_ERR;
-
+
char* extract_dir = NULL; /* temp dir to write extracted files to */
- char* comment_dir = NULL; /* temp dir to write file comments to */
unsigned int file_count = 0;
unsigned int viruses_found = 0;
@@ -283,7 +279,7 @@
/* Zero out the metadata struct before we read the header */
memset(&metadata, 0, sizeof(unrar_metadata_t));
-
+
/* Determine file basename */
if (CL_SUCCESS != cli_basename(filepath, strlen(filepath), &filename_base)) {
status = CL_EARG;
@@ -313,6 +309,9 @@
if (unrar_ret == UNRAR_EMEM) {
status = CL_EMEM;
goto done;
+ } else if (unrar_ret == UNRAR_EOPEN) {
+ status = CL_EOPEN;
+ goto done;
} else {
status = CL_EFORMAT;
goto done;
@@ -360,7 +359,7 @@
/*
* Read & scan each file header.
* Extract & scan each file.
- *
+ *
* Skip files if they will exceed max filesize or max scansize.
* Count the number of encrypted file headers and encrypted files.
* - Alert if there are encrypted files,
@@ -416,7 +415,7 @@
/* Check if we've already exceeded the scan limit */
if (cli_checklimits("RAR", ctx, 0, 0, 0))
break;
-
+
if (metadata.is_dir) {
/* Entry is a directory. Skip. */
cli_dbgmsg("RAR: Found directory. Skipping to next file.\n");
@@ -427,7 +426,7 @@
break;
}
} else if (cli_checklimits("RAR", ctx, metadata.unpack_size, 0, 0)) {
- /* File size exceeds maxfilesize, must skip extraction.
+ /* File size exceeds maxfilesize, must skip extraction.
* Although we may be able to scan the metadata */
nTooLargeFilesFound += 1;
@@ -450,9 +449,9 @@
}
} else {
/*
- * Extract the file...
- */
- extract_fullpath = cli_gentemp_with_prefix(extract_dir, metadata.filename);
+ * Extract the file...
+ */
+ extract_fullpath = cli_gentemp(extract_dir);
if (NULL == extract_fullpath) {
cli_dbgmsg("RAR: Memory error allocating filename for extracted file.");
status = CL_EMEM;
@@ -462,12 +461,12 @@
unrar_ret = cli_unrar_extract_file(hArchive, extract_fullpath, NULL);
if (unrar_ret != UNRAR_OK) {
- /*
+ /*
* Some other error extracting the file
*/
cli_dbgmsg("RAR: Error extracting file: %s\n", metadata.filename);
- /* TODO:
+ /* TODO:
* may need to manually skip the file depending on what, specifically, cli_unrar_extract_file() returned.
*/
} else {
@@ -1216,7 +1215,8 @@
static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
{
- int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
+ cl_error_t ret = CL_CLEAN;
+ int i, j, fd, data_len, hasmacros = 0;
vba_project_t *vba_project;
DIR *dd;
struct dirent *dent;
@@ -1230,25 +1230,30 @@
char *fullname, vbaname[1024];
unsigned char *data;
char *hash;
- uint32_t hashcnt;
+ uint32_t hashcnt = 0;
unsigned int viruses_found = 0;
cli_dbgmsg("VBADir: %s\n", dirname);
- hashcnt = uniq_get(U, "_vba_project", 12, NULL);
- while (hashcnt--)
- {
- if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt)))
+ if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('_vba_project') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
+ if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) {
+ hashcnt--;
continue;
+ }
for (i = 0; i < vba_project->count; i++)
{
- for (j = 0; (unsigned int)j < vba_project->colls[i]; j++)
+ for (j = 1; (unsigned int)j <= vba_project->colls[i]; j++)
{
snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", vba_project->dir, vba_project->name[i], j);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
- if (fd == -1)
+ if (fd == -1) {
continue;
+ }
cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
close(fd);
@@ -1300,29 +1305,30 @@
}
}
- free(vba_project->name);
- free(vba_project->colls);
- free(vba_project->dir);
- free(vba_project->offset);
- free(vba_project);
+ cli_free_vba_project(vba_project);
+ vba_project = NULL;
+
if (ret == CL_VIRUS && !SCAN_ALLMATCHES)
break;
+
+ hashcnt--;
}
- if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
- (hashcnt = uniq_get(U, "powerpoint document", 19, &hash)))
- {
- while (hashcnt--)
- {
+ if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) {
+ if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('powerpoint document') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
- if (fd == -1)
+ if (fd == -1) {
+ hashcnt--;
continue;
- if ((fullname = cli_ppt_vba_read(fd, ctx)))
- {
- if (cli_scandir(fullname, ctx) == CL_VIRUS)
- {
+ }
+ if ((fullname = cli_ppt_vba_read(fd, ctx))) {
+ if (cli_scandir(fullname, ctx) == CL_VIRUS) {
ret = CL_VIRUS;
viruses_found++;
}
@@ -1331,23 +1337,28 @@
free(fullname);
}
close(fd);
+ hashcnt--;
}
}
- if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
- (hashcnt = uniq_get(U, "worddocument", 12, &hash)))
- {
- while (hashcnt--)
- {
+ if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) {
+ if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('worddocument') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
fd = open(vbaname, O_RDONLY | O_BINARY);
- if (fd == -1)
+ if (fd == -1) {
+ hashcnt--;
continue;
+ }
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd)))
{
close(fd);
+ hashcnt--;
continue;
}
@@ -1380,20 +1391,16 @@
}
close(fd);
- free(vba_project->name);
- free(vba_project->colls);
- free(vba_project->dir);
- free(vba_project->offset);
- free(vba_project->key);
- free(vba_project->length);
- free(vba_project);
- if (ret == CL_VIRUS)
- {
+ cli_free_vba_project(vba_project);
+ vba_project = NULL;
+
+ if (ret == CL_VIRUS) {
if (SCAN_ALLMATCHES)
viruses_found++;
else
break;
}
+ hashcnt--;
}
}
@@ -1402,11 +1409,12 @@
#if HAVE_JSON
/* JSON Output Summary Information */
- if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL))
- {
- hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
- while (hashcnt--)
- {
+ if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
+ if (CL_SUCCESS != (ret = uniq_get(U, "_5_summaryinformation", 21, &hash, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('_5_summaryinformation') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
@@ -1418,11 +1426,14 @@
cli_ole2_summary_json(ctx, fd, 0);
close(fd);
}
+ hashcnt--;
}
- hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
- while (hashcnt--)
- {
+ if (CL_SUCCESS != (ret = uniq_get(U, "_5_documentsummaryinformation", 29, &hash, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('_5_documentsummaryinformation') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
@@ -1434,14 +1445,17 @@
cli_ole2_summary_json(ctx, fd, 1);
close(fd);
}
+ hashcnt--;
}
}
#endif
/* Check directory for embedded OLE objects */
- hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
- while (hashcnt--)
- {
+ if (CL_SUCCESS != (ret = uniq_get(U, "_1_ole10native", 14, &hash, &hashcnt))) {
+ cli_dbgmsg("VBADir: uniq_get('_1_ole10native') failed with ret code (%d)!\n", ret);
+ return ret;
+ }
+ while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname) - 1] = '\0';
@@ -1453,6 +1467,7 @@
if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALLMATCHES))
return ret;
}
+ hashcnt--;
}
/* ACAB: since we now hash filenames and handle collisions we
@@ -2580,7 +2595,6 @@
{
int ret = CL_CLEAN, nret = CL_CLEAN;
struct cli_matched_type *ftoffset = NULL, *fpt;
- uint32_t lastrar;
struct cli_exe_info peinfo;
unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
fmap_t *map = *ctx->fmap;
@@ -2660,7 +2674,11 @@
cli_set_container(ctx, CL_TYPE_RAR, csize);
cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int)fpt->offset);
- if ((ctx->sub_filepath == NULL) || (fpt->offset != 0)) {
+#ifdef _WIN32
+ if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED)|| (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
+#else
+ if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
+#endif
/*
* If map is not file-backed, or offset is not at the start of the file...
* ...have to dump to file for scanrar.
@@ -2683,6 +2701,25 @@
/* scan file */
nret = cli_scanrar(filepath, fd, ctx);
+ if ((NULL == tmpname) && (CL_EOPEN == nret)) {
+ /*
+ * Failed to open the file using the original filename.
+ * Try writing the file descriptor to a temp file and try again.
+ */
+ nret = fmap_dump_to_file(map, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, fpt->offset, fpt->offset + csize);
+ if (nret != CL_SUCCESS) {
+ cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
+ ret = nret;
+ break_loop = 1;
+ break;
+ }
+ filepath = tmpname;
+ fd = tmpfd;
+
+ /* try to scan again */
+ nret = cli_scanrar(filepath, fd, ctx);
+ }
+
if (tmpfd != -1)
{
/* If dumped tempfile, need to cleanup */
@@ -3348,7 +3385,11 @@
char *tmpname = NULL;
int tmpfd = -1;
- if (ctx->sub_filepath == NULL) {
+#ifdef _WIN32
+ if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
+#else
+ if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
+#endif
/* If map is not file-backed have to dump to file for scanrar. */
ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
if (ret != CL_SUCCESS) {
@@ -3366,6 +3407,23 @@
/* scan file */
ret = cli_scanrar(filepath, fd, ctx);
+ if ((NULL == tmpname) && (CL_EOPEN == ret)) {
+ /*
+ * Failed to open the file using the original filename.
+ * Try writing the file descriptor to a temp file and try again.
+ */
+ ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
+ if (ret != CL_SUCCESS) {
+ cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
+ break;
+ }
+ filepath = tmpname;
+ fd = tmpfd;
+
+ /* try to scan again */
+ ret = cli_scanrar(filepath, fd, ctx);
+ }
+
if (tmpfd != -1) {
/* If dumped tempfile, need to cleanup */
close(tmpfd);
@@ -3786,10 +3844,15 @@
}
}
-static int cli_base_scandesc(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type)
+static cl_error_t cli_base_scandesc(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type)
{
STATBUF sb;
- int ret;
+ cl_error_t status = CL_CLEAN;
+ cl_error_t ret = CL_CLEAN;
+
+ if (!ctx) {
+ return CL_EARG;
+ }
const char *parent_filepath = ctx->sub_filepath;
ctx->sub_filepath = filepath;
@@ -3802,12 +3865,18 @@
if (FSTAT(desc, &sb) == -1)
{
cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
- early_ret_from_magicscan(CL_ESTAT);
+
+ status = CL_ESTAT;
+ cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+ goto done;
}
if (sb.st_size <= 5)
{
cli_dbgmsg("Small data (%u bytes)\n", (unsigned int)sb.st_size);
- early_ret_from_magicscan(CL_CLEAN);
+
+ status = CL_CLEAN;
+ cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+ goto done;
}
ctx->fmap++;
@@ -3817,18 +3886,22 @@
cli_errmsg("CRITICAL: fmap() failed\n");
ctx->fmap--;
perf_stop(ctx, PERFT_MAP);
- early_ret_from_magicscan(CL_EMEM);
+
+ status = CL_EMEM;
+ cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+ goto done;
}
perf_stop(ctx, PERFT_MAP);
- ret = magic_scandesc(ctx, type);
+ status = magic_scandesc(ctx, type);
funmap(*ctx->fmap);
ctx->fmap--;
+done:
ctx->sub_filepath = parent_filepath;
- return ret;
+ return status;
}
int cli_magic_scandesc(int desc, const char *filepath, cli_ctx *ctx)
@@ -4015,8 +4088,8 @@
}
/**
- * @brief The main function to initiate a scan, that may be invoked with a file descriptor or a file map.
- *
+ * @brief The main function to initiate a scan, that may be invoked with a file descriptor or a file map.
+ *
* @param desc File descriptor of an open file. The caller must provide this or the map.
* @param map File map. The caller must provide this or the desc.
* @param filepath (optional, recommended) filepath of the open file descriptor or file map.
@@ -4092,23 +4165,13 @@
}
}
- /* Best effort to determine the filename if not provided.
- * May still be NULL if filename could not be determined. */
- if (filepath == NULL)
+ if (filepath != NULL)
{
- char *fpath = NULL;
-
- if (desc >= 0) {
- (void) cli_get_filepath_from_filedesc(desc, &fpath);
- }
-
- ctx.target_filepath = fpath;
- } else {
ctx.target_filepath = strdup(filepath);
}
cli_logg_setup(&ctx);
- rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY)
+ rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY)
: cli_magic_scandesc(desc, ctx.target_filepath, &ctx);
#if HAVE_JSON
@@ -4237,8 +4300,8 @@
if (rc == CL_CLEAN)
{
if ((ctx.found_possibly_unwanted) ||
- ((ctx.num_viruses != 0) &&
- ((ctx.options->general & CL_SCAN_GENERAL_ALLMATCHES) ||
+ ((ctx.num_viruses != 0) &&
+ ((ctx.options->general & CL_SCAN_GENERAL_ALLMATCHES) ||
(ctx.options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX))
))
rc = CL_VIRUS;
@@ -4279,8 +4342,8 @@
return CL_VIRUS;
}
/* heuristic scan isn't taking precedence, keep scanning.
- * If this is part of an archive, and
- * we find a real malware we report that instead of the
+ * If this is part of an archive, and
+ * we find a real malware we report that instead of the
* heuristic match */
ctx->found_possibly_unwanted = 1;
}
diff -Nru clamav-0.101.1+dfsg/libclamav/str.c clamav-0.101.2+dfsg/libclamav/str.c
--- clamav-0.101.1+dfsg/libclamav/str.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/str.c 2019-03-13 22:13:01.000000000 +0100
@@ -268,7 +268,7 @@
return NULL;
for(i = 0, j = 0; i < length; i += 2, j++) {
- decoded[j] = str[i + 1] << 4;
+ decoded[j] = ((unsigned char) str[i + 1]) << 4;
decoded[j] += str[i];
}
@@ -400,9 +400,9 @@
return output;
}
-const char *cli_memstr(const char *haystack, unsigned int hs, const char *needle, unsigned int ns)
+const char *cli_memstr(const char *haystack, size_t hs, const char *needle, size_t ns)
{
- unsigned int i, s1, s2;
+ size_t i, s1, s2;
if(!hs || !ns || hs < ns)
return NULL;
@@ -496,6 +496,48 @@
}
#endif
+#if !defined(HAVE_STRNSTR) || defined(HAVE_STRNI)
+/*
+ * @brief Find the first occurrence of find in s.
+ *
+ * The search is limited to the first slen characters of s.
+ *
+ * Copyright (c) 2001 Mike Barcroft <mike at FreeBSD.org>
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * @param s haystack
+ * @param find needle
+ * @param slen haystack length
+ * @return char* Address of the needle, if found, else NULL.
+ */
+char *cli_strnstr(const char *s, const char *find, size_t slen)
+{
+ char c, sc;
+ size_t len;
+
+ if ((c = *find++) != '\0') {
+ len = strlen(find);
+ do {
+ do {
+ if (slen-- < 1 || (sc = *s++) == '\0')
+ return (NULL);
+ } while (sc != c);
+ if (len > slen)
+ return (NULL);
+ } while (strncmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *)s);
+}
+#endif
+
size_t cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens)
{
size_t tokens_found, i;
@@ -907,12 +949,14 @@
if(k+5 >= len || str[k+1] != 'u' || !isxdigit(str[k+2]) || !isxdigit(str[k+3])
|| !isxdigit(str[k+4]) || !isxdigit(str[k+5])) {
if(k+2 < len && isxdigit(str[k+1]) && isxdigit(str[k+2])) {
- c = (cli_hex2int(str[k+1])<<4) | cli_hex2int(str[k+2]);
+ c = ((cli_hex2int(str[k + 1]) < 0 ? 0 : cli_hex2int(str[k + 1])) << 4) | cli_hex2int(str[k + 2]);
k += 2;
}
} else {
- uint16_t u = (cli_hex2int(str[k+2])<<12) | (cli_hex2int(str[k+3])<<8) |
- (cli_hex2int(str[k+4])<<4) | cli_hex2int(str[k+5]);
+ uint16_t u = ((cli_hex2int(str[k + 2]) < 0 ? 0 : cli_hex2int(str[k + 2])) << 12) |
+ ((cli_hex2int(str[k + 3]) < 0 ? 0 : cli_hex2int(str[k + 3])) << 8) |
+ ((cli_hex2int(str[k + 4]) < 0 ? 0 : cli_hex2int(str[k + 4])) << 4) |
+ cli_hex2int(str[k + 5]);
i += output_utf8(u, (unsigned char*)&R[i]);
k += 5;
continue;
@@ -958,13 +1002,15 @@
break;
case 'x':
if(i+2 < len)
- c = (cli_hex2int(str[i+1])<<4)|cli_hex2int(str[i+2]);
+ c = ((cli_hex2int(str[i + 1]) < 0 ? 0 : cli_hex2int(str[i + 1])) << 4) | cli_hex2int(str[i + 2]);
i += 2;
break;
case 'u':
if(i+4 < len) {
- uint16_t u = (cli_hex2int(str[i+1])<<12) | (cli_hex2int(str[i+2])<<8) |
- (cli_hex2int(str[i+3])<<4) | cli_hex2int(str[i+4]);
+ uint16_t u = ((cli_hex2int(str[i + 1]) < 0 ? 0 : cli_hex2int(str[i + 1])) << 12) |
+ ((cli_hex2int(str[i + 2]) < 0 ? 0 : cli_hex2int(str[i + 2])) << 8) |
+ ((cli_hex2int(str[i + 3]) < 0 ? 0 : cli_hex2int(str[i + 3])) << 4) |
+ cli_hex2int(str[i + 4]);
if(textbuffer_ensure_capacity(buf, 4) == -1)
return -1;
buf->pos += output_utf8(u, (unsigned char*)&buf->data[buf->pos]);
diff -Nru clamav-0.101.1+dfsg/libclamav/str.h clamav-0.101.2+dfsg/libclamav/str.h
--- clamav-0.101.1+dfsg/libclamav/str.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/str.h 2019-03-13 22:13:01.000000000 +0100
@@ -52,6 +52,12 @@
size_t cli_strnlen(const char *s, size_t n);
#endif
+#if defined(HAVE_STRNSTR) && !defined(HAVE_STRNI)
+#define cli_strnstr strnstr
+#else
+char *cli_strnstr(const char *s, const char *find, size_t slen);
+#endif
+
#include <stdio.h>
#define cli_nocase(val) tolower(val)
#define cli_nocasei(val) toupper(val)
@@ -68,7 +74,7 @@
char *cli_str2hex(const char *string, unsigned int len);
char *cli_utf16toascii(const char *str, unsigned int length);
char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output);
-const char *cli_memstr(const char *haystack, unsigned int hs, const char *needle, unsigned int ns);
+const char *cli_memstr(const char *haystack, size_t hs, const char *needle, size_t ns);
char *cli_strrcpy(char *dest, const char *source);
size_t cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens);
size_t cli_ldbtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens, int token_skip);
diff -Nru clamav-0.101.1+dfsg/libclamav/unarj.c clamav-0.101.2+dfsg/libclamav/unarj.c
--- clamav-0.101.1+dfsg/libclamav/unarj.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/unarj.c 2019-03-13 22:13:01.000000000 +0100
@@ -163,7 +163,9 @@
{
if (decode_data->status == CL_EFORMAT)
return CL_EFORMAT;
- decode_data->bit_buf = (decode_data->bit_buf << n) & 0xFFFF;
+ if (((uint64_t) decode_data->bit_buf) * (n > 0 ? 2 << (n - 1) : 0) > UINT32_MAX)
+ return CL_EFORMAT;
+ decode_data->bit_buf = (((uint64_t) decode_data->bit_buf) << n) & 0xFFFF;
while (n > decode_data->bit_count) {
decode_data->bit_buf |= decode_data->sub_bit_buf << (n -= decode_data->bit_count);
if (decode_data->comp_size != 0) {
@@ -623,10 +625,34 @@
return CL_SUCCESS;
}
-#define ARJ_BFIL(dd) {dd->getbuf|=dd->bit_buf>>dd->getlen;fill_buf(dd,CODE_BIT-dd->getlen);dd->getlen=CODE_BIT;}
-#define ARJ_GETBIT(dd,c) {if(dd->getlen<=0)ARJ_BFIL(dd) c=(dd->getbuf&0x8000)!=0;dd->getbuf<<=1;dd->getlen--;}
-#define ARJ_BPUL(dd,l) {dd->getbuf<<=l;dd->getlen-=l;}
-#define ARJ_GETBITS(dd,c,l) {if(dd->getlen<l)ARJ_BFIL(dd) c=(uint16_t)dd->getbuf>>(CODE_BIT-l);ARJ_BPUL(dd,l)}
+#define ARJ_BFIL(dd) \
+ { \
+ dd->getbuf |= dd->bit_buf >> dd->getlen; \
+ fill_buf(dd, CODE_BIT - dd->getlen); \
+ dd->getlen = CODE_BIT; \
+ }
+#define ARJ_GETBIT(dd, c) \
+ { \
+ if (dd->getlen <= 0) ARJ_BFIL(dd) \
+ c = (dd->getbuf & 0x8000) != 0; \
+ dd->getbuf *= 2; \
+ dd->getlen--; \
+ }
+#define ARJ_BPUL(dd, l) \
+ do { \
+ int i; \
+ int j = l; \
+ for (i = 0; i < j; i++) { \
+ dd->getbuf *= 2; \
+ } \
+ dd->getlen -= l; \
+ } while(0)
+#define ARJ_GETBITS(dd, c, l) \
+ { \
+ if (dd->getlen < l) ARJ_BFIL(dd) \
+ c = (uint16_t)dd->getbuf >> (CODE_BIT - l); \
+ ARJ_BPUL(dd, l); \
+ }
static uint16_t decode_ptr(arj_decode_t *decode_data)
{
@@ -689,6 +715,7 @@
decode_data.comp_size = metadata->comp_size;
ret = init_getbits(&decode_data);
if (ret != CL_SUCCESS) {
+ free(decode_data.text);
metadata->offset = decode_data.offset;
return ret;
}
diff -Nru clamav-0.101.1+dfsg/libclamav/uniq.c clamav-0.101.2+dfsg/libclamav/uniq.c
--- clamav-0.101.1+dfsg/libclamav/uniq.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/uniq.c 2019-03-13 22:13:01.000000000 +0100
@@ -46,6 +46,7 @@
uniq_free(U);
return NULL;
}
+ U->max_unique_items = count;
return U;
}
@@ -55,18 +56,39 @@
free(U);
}
-uint32_t uniq_add(struct uniq *U, const char *key, uint32_t key_len, char **rhash) {
+cl_error_t uniq_add(struct uniq *U, const char *item, uint32_t item_len, char **rhash, uint32_t *count)
+{
+ cl_error_t status = CL_EARG;
unsigned int i;
uint8_t digest[16];
struct UNIQMD5 *m = NULL;
- cl_hash_data("md5", key, key_len, digest, NULL);
+ if (!U) {
+ /* Invalid args */
+ goto done;
+ }
+
+ /* Uniq adds are limited by the maximum allocated in uniq_init(). */
+ if (U->cur_unique_items >= U->max_unique_items) {
+ /* Attempted to add more uniq items than may be stored. */
+ status = CL_EMAXSIZE;
+ goto done;
+ }
+
+ /* Make a hash of the item string */
+ if (NULL == cl_hash_data("md5", item, item_len, digest, NULL)) {
+ /* Failed to create hash of item. */
+ status = CL_EFORMAT;
+ goto done;
+ }
+ /* Check for md5 digest match in md5 collection */
if(U->items && U->md5s[U->idx[*digest]].md5[0]==*digest)
for(m=&U->md5s[U->idx[*digest]]; m; m=m->next)
if(!memcmp(&digest[1], &m->md5[1], 15)) break;
if(!m) {
+ /* No match. Add new md5 to list */
const char HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
m = &U->md5s[U->items];
@@ -85,27 +107,85 @@
m->md5[i] = digest[i];
}
m->name[32] = '\0';
+
+ /* Increment # of unique items. */
+ U->cur_unique_items++;
}
+ /* Increment total # of items. */
U->items++;
+
+ /* Increment # items matching this md5 digest (probably just this 1). */
+ m->count++;
+
+ /* Pass back the ascii hash, if requested. */
if(rhash) *rhash = m->name;
- return m->count++;
+
+ /* Pass back the count, if requested. */
+ if (count) *count = m->count;
+
+ status = CL_SUCCESS;
+
+done:
+ return status;
}
-uint32_t uniq_get(struct uniq *U, const char *key, uint32_t key_len, char **rhash) {
+cl_error_t uniq_get(struct uniq *U, const char *item, uint32_t item_len, char **rhash, uint32_t *count)
+{
+ cl_error_t status = CL_EARG;
uint8_t digest[16];
struct UNIQMD5 *m = NULL;
+ uint32_t idx = 0;
- cl_hash_data("md5", key, key_len, digest, NULL);
+ if (!U || !count) {
+ /* Invalid args */
+ goto done;
+ }
- if(!U->items || U->md5s[U->idx[*digest]].md5[0]!=*digest)
- return 0;
+ *count = 0;
- for(m=&U->md5s[U->idx[*digest]]; m; m=m->next) {
- if(memcmp(&digest[1], &m->md5[1], 15)) continue;
- if(rhash) *rhash = m->name;
- return m->count;
+ if (!U->items) {
+ goto not_found;
+ }
+
+ /* Make a hash of the item string */
+ if (NULL == cl_hash_data("md5", item, item_len, digest, NULL)) {
+ /* Failed to create hash of item. */
+ status = CL_EFORMAT;
+ goto done;
+ }
+
+ /* Get the md5s array index for the bucket list head. */
+ idx = U->idx[*digest];
+ m = &U->md5s[idx];
+
+ if (m->md5[0] != *digest) {
+ /*
+ * If the first two bytes in the digest doesn't actually match,
+ * then the item has never been added.
+ * This is a common scenario because the idx table is initialized
+ * to 0's.
+ */
+ goto not_found;
+ }
+
+ do {
+ if (0 == memcmp(&digest[1], &m->md5[1], 15)) {
+ /* The item-hash matched.
+ * Pass back the ascii hash value (if requested).
+ * Return the count of matching items (will be 1+).
+ */
+ if (rhash)
+ *rhash = m->name;
+ *count = m->count;
+ break;
}
+ m = m->next;
+ } while (NULL != m);
+
+not_found:
+ status = CL_SUCCESS;
- return 0;
+done:
+ return status;
}
diff -Nru clamav-0.101.1+dfsg/libclamav/uniq.h clamav-0.101.2+dfsg/libclamav/uniq.h
--- clamav-0.101.1+dfsg/libclamav/uniq.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/uniq.h 2019-03-13 22:13:01.000000000 +0100
@@ -1,11 +1,59 @@
/*
* md5 based hashtab
*
- * Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- * Copyright (C) 2008 Sourcefire, Inc.
+ * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Copyright (C) 2008-2013 Sourcefire, Inc.
*
* Authors: aCaB <acab at clamav.net>
*
+ * Uniq implements a structure that stores the count of duplicate items.
+ * The count can be retrieved by item name (if you know it).
+ * Additionally, you can retrieve the ascii md5 hash at the same time.
+ *
+ * This is essentially a tiny hash table of hashes.
+ * The hashes are in an array instead of dynamically added.
+ * This is faster than alloc'ing for each unique item added, * but means a max # of unique items must be defined at init.
+ *
+ * Example where:
+ * items = 6
+ * max_unique_items = 5
+ * cur_unique_items = 4
+ * md5 #1 has been added 3 times
+ * Two md5's start with the same 2 bytes (#0 and #3)
+ *
+ * idx:
+ * -00--01--02--03--04--05--06--07-...
+ * | 0 | 0 | 0 | 2 | 1 | 0 | 0 | ...
+ * ------------------------------...
+ *
+ * md5s:
+ * ------------------------------
+ * 0 | next: Address of #3
+ * | count: 1
+ * | md5: 0x01,0x98,0x23,0xa8,0xfd,...
+ * | name: "019823a8fd..."
+ * ------------------------------
+ * 1 | next: NULL
+ * | count: 3
+ * | md5: 0x03,0x98,0x23,0xa8,0xfd,...
+ * | name: "019823a8fd..."
+ * ------------------------------
+ * 2 | next: NULL
+ * | count: 1
+ * | md5: 0x01,0x98,0x23,0xa8,0xfd,...
+ * | name: "019823a8fd..."
+ * ------------------------------
+ * 3 | next: NULL
+ * | count: 1
+ * | md5: 0x01,0xdd,0x2f,0x87,0x6a,...
+ * | name: "01dd2f876a..."
+ * ------------------------------
+ * 4 | next: NULL
+ * | count: 0
+ * | md5: 0x00,0x00,0x00,0x00,0x00,...
+ * | name: "\0\0\0\0\0..."
+ * ------------------------------
+ *
* 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.
@@ -24,25 +72,85 @@
#ifndef _UNIQ_H
#define _UNIQ_H
+#include "clamav.h"
#include "clamav-types.h"
+/**
+ * @brief Store the count of each unique item.
+ *
+ * These elements are allocated as an array in struct uniq, but they are also
+ * linked together using the `next` pointers to form impromptu buckets,
+ * categorized using the first two bytes of each md5.
+ */
struct UNIQMD5 {
- struct UNIQMD5 *next;
- uint32_t count;
- uint8_t md5[16];
- char name[33];
+ struct UNIQMD5 *next; /**< Pointer to next UNIQMD5 where the first two bytes are the same. */
+ uint32_t count; /**< Number of times this item has been added. (# duplicates). */
+ uint8_t md5[16]; /**< Binary md5 hash of the item. */
+ char name[33]; /**< Ascii md5 hash of the item. */
};
+/**
+ * @brief The main Uniq store structure.
+ *
+ * Includes array of uniq md5 hashes, and an index table to optimize searches
+ * into the hash array, categorized by the first two bytes of the md5.
+ */
struct uniq {
- struct UNIQMD5 *md5s;
- uint32_t items;
- uint32_t idx[256];
+ struct UNIQMD5 *md5s; /**< Array of UNIQMD5 structs. */
+ uint32_t items; /**< Total # of items added (including duplicates) */
+ uint32_t cur_unique_items; /**< The # of md5s currently stored in the array. */
+ uint32_t max_unique_items; /**< The # of md5s that can be stored the array. */
+ uint32_t idx[256]; /**< Array of indices into the md5s array.
+ Each index represents a linked-list of md5s
+ sharing the common trait that the first two
+ bytes are the same. */
};
+/**
+ * @brief Initialize a Uniq store to count the number of uniq string items.
+ *
+ * The Uniq store must be free'd with uniq_free().
+ * uniq_add()'s will fail if they exceed the number of unique strings initialized with count.
+ *
+ * @param count The max number of unique string items that may be added.
+ * @return struct uniq* A pointer to the Uniq store object. Will return NULL on failure.
+ */
struct uniq *uniq_init(uint32_t);
+
+/**
+ * @brief Free the Uniq store and associated memory.
+ */
void uniq_free(struct uniq *);
-uint32_t uniq_add(struct uniq *, const char *, uint32_t, char **);
-uint32_t uniq_get(struct uniq *, const char *, uint32_t, char **);
+
+/**
+ * @brief Add to the uniq (item md5) count.
+ *
+ * Adds an item to the list of known items.
+ * Increments the count if the item has been seen before.
+ * The optional rhash pointer will be valid until `uniq_free()` is called.
+ *
+ * @param U The Uniq count store.
+ * @param item (optional) The item to hash and count.
+ * @param item_len The length, in bytes, of the item. May be 0.
+ * @param[out] rhash (optional) A pointer to the item's md5 hash (in ascii).
+ * @param[out] count (optional) The number of times this unique item has been added.
+ * @return cl_error_t CL_SUCCESS if successful, else an error code.
+ */
+cl_error_t uniq_add(struct uniq *U, const char *item, uint32_t, char **rhash, uint32_t *count);
+
+/**
+ * @brief Retrieve the number of times an item has been added to the Uniq count store.
+ *
+ * The optional rhash pointer will be valid until `uniq_free()` is called.
+ *
+ * @param U The Uniq count store.
+ * @param item (optional) The item to hash and count.
+ * @param item_len The length, in bytes, of the item. May be 0.
+ * @param[out] rhash (optional) A pointer to the item's md5 hash (in ascii).
+ * @param[out] count The number of times this unique item has been added.
+ * @return cl_error_t CL_SUCCESS if successful, else an error code.
+ */
+cl_error_t uniq_get(struct uniq *U, const char *item, uint32_t, char **rhash, uint32_t *count);
#endif
diff -Nru clamav-0.101.1+dfsg/libclamav/upx.c clamav-0.101.2+dfsg/libclamav/upx.c
--- clamav-0.101.1+dfsg/libclamav/upx.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/upx.c 2019-03-13 22:13:01.000000000 +0100
@@ -311,12 +311,14 @@
if ( oob == -1 )
return -1;
-
+
backbytes = 1;
while (1) {
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+ return -1;
backbytes = backbytes*2+oob;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
@@ -325,11 +327,13 @@
}
backbytes-=3;
-
+
if ( backbytes >= 0 ) {
if (scur>=ssize)
return -1;
+ if (backbytes & 0xff000000)
+ return -1;
backbytes<<=8;
backbytes+=(unsigned char)(src[scur++]);
backbytes^=0xffffffff;
@@ -343,16 +347,22 @@
return -1;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = backsize*2 + oob;
if (!backsize) {
backsize++;
do {
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = backsize*2 + oob;
} while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
if ( oob == -1 )
return -1;
+ if (backsize + 2 > UINT32_MAX)
+ return -1;
backsize+=2;
}
@@ -392,6 +402,8 @@
while (1) {
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+ return -1;
backbytes = backbytes*2+oob;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
@@ -400,16 +412,20 @@
backbytes--;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+ return -1;
backbytes=backbytes*2+oob;
}
backsize = 0;
backbytes-=3;
-
+
if ( backbytes >= 0 ) {
if (scur>=ssize)
return -1;
+ if (backbytes & 0xff000000)
+ return -1;
backbytes<<=8;
backbytes+=(unsigned char)(src[scur++]);
backbytes^=0xffffffff;
@@ -423,23 +439,29 @@
if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
return -1;
}
-
+
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = backsize*2 + oob;
if (!backsize) {
backsize++;
do {
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = backsize*2 + oob;
} while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
if ( oob == -1 )
return -1;
+ if (backsize + 2 > UINT32_MAX)
+ return -1;
backsize+=2;
}
- if ( (uint32_t)unp_offset < 0xfffffb00 )
+ if ( (uint32_t)unp_offset < 0xfffffb00 )
backsize++;
backsize++;
@@ -473,6 +495,8 @@
for(;;) {
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+ return -1;
backbytes = backbytes*2+oob;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
@@ -481,15 +505,19 @@
backbytes--;
if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
return -1;
+ if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+ return -1;
backbytes=backbytes*2+oob;
}
backbytes-=3;
-
+
if ( backbytes >= 0 ) {
if (scur>=ssize)
return -1;
+ if (backbytes & 0xff000000)
+ return -1;
backbytes<<=8;
backbytes+=(unsigned char)(src[scur++]);
backbytes^=0xffffffff;
@@ -514,22 +542,30 @@
if (oob) {
if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = 2 + oob;
} else {
do {
if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
return -1;
+ if (backsize + oob > UINT32_MAX / 2)
+ return -1;
backsize = backsize * 2 + oob;
} while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
if (oob == -1)
return -1;
+ if (backsize + 2 > UINT32_MAX)
+ return -1;
backsize+=2;
}
}
-
- if ( (uint32_t)unp_offset < 0xfffffb00 )
+
+ if ( (uint32_t)unp_offset < 0xfffffb00 )
backsize++;
+ if (backsize + 2 > UINT32_MAX)
+ return -1;
backsize+=2;
if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
@@ -551,7 +587,7 @@
cli_writeint32(fake_lzmahdr + 1, *dsize);
uint8_t lc = properties & 0xff;
uint8_t lp = (properties >> 8) & 0xff;
- uint8_t pb = (properties >> 16) & 0xff;
+ uint8_t pb = (properties >> 16) & 0xff;
if (lc >= 9 || lp >= 5 || pb >= 5)
return -1;
diff -Nru clamav-0.101.1+dfsg/libclamav/vba_extract.c clamav-0.101.2+dfsg/libclamav/vba_extract.c
--- clamav-0.101.1+dfsg/libclamav/vba_extract.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/vba_extract.c 2019-03-13 22:13:01.000000000 +0100
@@ -294,6 +294,7 @@
struct vba56_header v56h;
off_t seekback;
char fullname[1024], *hash;
+ uint32_t hashcnt = 0;
cli_dbgmsg("in cli_vba_readdir()\n");
@@ -304,8 +305,13 @@
* _VBA_PROJECT files are embedded within office documents (OLE2)
*/
- if (!uniq_get(U, "_vba_project", 12, &hash))
+ if (CL_SUCCESS != uniq_get(U, "_vba_project", 12, &hash, &hashcnt)) {
+ cli_dbgmsg("vba_readdir: uniq_get('_vba_project') failed. Unable to check # of embedded vba proj files\n");
return NULL;
+ }
+ if (hashcnt == 0) {
+ return NULL;
+ }
snprintf(fullname, sizeof(fullname), "%s"PATHSEP"%s_%u", dir, hash, which);
fullname[sizeof(fullname)-1] = '\0';
fd = open(fullname, O_RDONLY|O_BINARY);
@@ -448,7 +454,13 @@
}
ptr = get_unicode_name((const char *)buf, length, big_endian);
if(ptr == NULL) break;
- if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
+ if (CL_SUCCESS != uniq_get(U, ptr, strlen(ptr), &hash, &hashcnt)) {
+ cli_dbgmsg("vba_readdir: uniq_get('%s') failed.\n", ptr);
+ free(ptr);
+ break;
+ }
+ vba_project->colls[i] = hashcnt;
+ if (0 == vba_project->colls[i]) {
cli_dbgmsg("vba_readdir: cannot find project %s (%s)\n", ptr, hash);
free(ptr);
break;
@@ -1308,7 +1320,7 @@
{
vba_project_t *ret;
- ret = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+ ret = (vba_project_t *)cli_calloc(1, sizeof(struct vba_project_tag));
if(ret == NULL) {
cli_errmsg("create_vba_project: Unable to allocate memory for vba project structure\n");
@@ -1320,16 +1332,8 @@
ret->dir = cli_strdup(dir);
ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
- if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
- if(ret->dir)
- free(ret->dir);
- if(ret->colls)
- free(ret->colls);
- if(ret->name)
- free(ret->name);
- if(ret->offset)
- free(ret->offset);
- free(ret);
+ if ((ret->colls == NULL) || (ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
+ cli_free_vba_project(ret);
cli_errmsg("create_vba_project: Unable to allocate memory for vba project elements\n");
return NULL;
}
@@ -1338,3 +1342,32 @@
return ret;
}
+
+/**
+ * @brief Free up the memory associated with the vba_project_t type.
+ *
+ * @param project A vba_project_t type allocated by one of these:
+ * - create_vba_project()
+ * - cli_wm_readdir()
+ * - cli_vba_readdir()
+ */
+void cli_free_vba_project(vba_project_t *vba_project)
+{
+ if (vba_project) {
+ if (vba_project->dir)
+ free(vba_project->dir);
+ if (vba_project->colls)
+ free(vba_project->colls);
+ if (vba_project->name)
+ free(vba_project->name);
+ if (vba_project->offset)
+ free(vba_project->offset);
+ if (vba_project->length)
+ free(vba_project->length);
+ if (vba_project->key)
+ free(vba_project->key);
+ free(vba_project);
+ }
+
+ return;
+}
\ No newline at end of file
diff -Nru clamav-0.101.1+dfsg/libclamav/vba_extract.h clamav-0.101.2+dfsg/libclamav/vba_extract.h
--- clamav-0.101.1+dfsg/libclamav/vba_extract.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/vba_extract.h 2019-03-13 22:13:01.000000000 +0100
@@ -41,6 +41,8 @@
vba_project_t *cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which);
vba_project_t *cli_wm_readdir(int fd);
+void cli_free_vba_project(vba_project_t *vba_project);
+
unsigned char *cli_vba_inflate(int fd, off_t offset, int *size);
int cli_scan_ole10(int fd, cli_ctx *ctx);
char *cli_ppt_vba_read(int fd, cli_ctx *ctx);
diff -Nru clamav-0.101.1+dfsg/libclamav/version.h clamav-0.101.2+dfsg/libclamav/version.h
--- clamav-0.101.1+dfsg/libclamav/version.h 2018-12-19 21:48:59.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/version.h 2019-03-13 22:13:33.000000000 +0100
@@ -1 +1 @@
-#define REPO_VERSION "devel-clamav-0.101.0-rc-10-g5ee212a7b"
+#define REPO_VERSION "devel-clamav-0.101.1-30-g5e0e479ad"
diff -Nru clamav-0.101.1+dfsg/libclamav/xz_iface.c clamav-0.101.2+dfsg/libclamav/xz_iface.c
--- clamav-0.101.1+dfsg/libclamav/xz_iface.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/xz_iface.c 2019-03-13 22:13:01.000000000 +0100
@@ -57,6 +57,8 @@
}
void cli_XzShutdown(struct CLI_XZ *XZ) {
+ if (!XZ)
+ return;
XzUnpacker_Free(&XZ->state);
}
diff -Nru clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.cpp clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.cpp
--- clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.cpp 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.cpp 2019-03-13 22:13:01.000000000 +0100
@@ -133,6 +135,7 @@
}
case ERAR_EOPEN: {
unrar_dbgmsg("unrar_retcode: Volume open error.\n");
+ status = UNRAR_EOPEN;
break;
}
case ERAR_ECREATE: {
diff -Nru clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.h clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.h
--- clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.h 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.h 2019-03-13 22:13:01.000000000 +0100
@@ -48,7 +50,8 @@
UNRAR_BREAK,
UNRAR_ENCRYPTED,
UNRAR_EMEM,
- UNRAR_ERR
+ UNRAR_ERR,
+ UNRAR_EOPEN
} cl_unrar_error_t;
typedef struct unrar_metadata_tag
diff -Nru clamav-0.101.1+dfsg/m4/reorganization/code_checks/fuzz.m4 clamav-0.101.2+dfsg/m4/reorganization/code_checks/fuzz.m4
--- clamav-0.101.1+dfsg/m4/reorganization/code_checks/fuzz.m4 1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/m4/reorganization/code_checks/fuzz.m4 2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,11 @@
+AC_ARG_ENABLE(fuzz,
+ AC_HELP_STRING([--enable-fuzz],
+ [enable building standalone fuzz targets
+ @<:@default=no@:>@]),
+[enable_cov=$enableval],[enable_cov="no"])
+
+if test "x$enable_fuzz" = "xyes"; then
+ CXXFLAGS="-std=c++11 -stdlib=libc++ $CXXFLAGS"
+fi
+
+AM_CONDITIONAL(ENABLE_FUZZ, test "x$enable_fuzz" = "xyes")
diff -Nru clamav-0.101.1+dfsg/m4/reorganization/version.m4 clamav-0.101.2+dfsg/m4/reorganization/version.m4
--- clamav-0.101.1+dfsg/m4/reorganization/version.m4 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/m4/reorganization/version.m4 2019-03-13 22:13:01.000000000 +0100
@@ -1,9 +1,9 @@
dnl change this on a release
dnl VERSION="devel-`date +%Y%m%d`"
-VERSION="0.101.1"
+VERSION="0.101.2"
LC_CURRENT=9
-LC_REVISION=1
+LC_REVISION=2
LC_AGE=0
LIBCLAMAV_VERSION="$LC_CURRENT":"$LC_REVISION":"$LC_AGE"
AC_SUBST([LIBCLAMAV_VERSION])
diff -Nru clamav-0.101.1+dfsg/Makefile.am clamav-0.101.2+dfsg/Makefile.am
--- clamav-0.101.1+dfsg/Makefile.am 2019-01-07 22:16:54.000000000 +0100
+++ clamav-0.101.2+dfsg/Makefile.am 2019-03-30 14:57:20.000000000 +0100
@@ -31,6 +33,10 @@
SUBDIRS += libfreshclam
endif
+if ENABLE_FUZZ
+SUBDIRS += fuzz
+endif
+
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libclamav.pc
@@ -39,11 +45,15 @@
# don't complain that configuration files and databases are not removed, this is intended
distuninstallcheck_listfiles = find . -type f ! -name clamd.conf ! -name freshclam.conf ! -name daily.cvd ! -name main.cvd -print
DISTCLEANFILES = target.h
-DISTCHECK_CONFIGURE_FLAGS=--enable-milter --disable-clamav --enable-all-jit-targets --enable-llvm=yes --with-system-llvm=no --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
+DISTCHECK_CONFIGURE_FLAGS=--enable-milter --disable-clamav --enable-all-jit-targets --enable-llvm=yes --with-system-llvm=no --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) CC="$(CC)" CXX="$(CXX)" YACC="$(YACC)" LEX="$(LEX)" AR="$(AR)" AS="$(AS)"
lcov:
($(MAKE); cd unit_tests; $(MAKE) lcov)
quick-check:
($(MAKE); cd unit_tests; $(MAKE) quick-check)
+fuzz-all:
+ ($(MAKE); cd fuzz; $(MAKE) all)
+fuzz-check:
+ ($(MAKE); cd fuzz; $(MAKE) check)
dist-hook:
rm -rf $(distdir)/win32/clamav-for-windows $(distdir)/win32/build
diff -Nru clamav-0.101.1+dfsg/NEWS.md clamav-0.101.2+dfsg/NEWS.md
--- clamav-0.101.1+dfsg/NEWS.md 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/NEWS.md 2019-03-13 22:13:01.000000000 +0100
@@ -3,6 +3,77 @@
Note: This file refers to the source tarball. Things described here may differ
slightly from the binary packages.
+## 0.101.2
+
+ClamAV 0.101.2 is a patch release to address a handful of security related bugs.
+
+This patch release is being released alongside the 0.100.3 patch so that users
+who are unable to upgrade to 0.101 due to libclamav API changes are protected.
+
+This release includes 3 extra security related bug fixes that do not apply to
+prior versions. In addition, it includes a number of minor bug fixes and
+improvements.
+
+- Fixes for the following vulnerabilities affecting 0.101.1 and prior:
+ - [CVE-2019-1787](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1787):
+ An out-of-bounds heap read condition may occur when scanning PDF
+ documents. The defect is a failure to correctly keep track of the number
+ of bytes remaining in a buffer when indexing file data.
+ - [CVE-2019-1789](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1789):
+ An out-of-bounds heap read condition may occur when scanning PE files
+ (i.e. Windows EXE and DLL files) that have been packed using Aspack as a
+ result of inadequate bound-checking.
+ - [CVE-2019-1788](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1788):
+ An out-of-bounds heap write condition may occur when scanning OLE2 files
+ such as Microsoft Office 97-2003 documents. The invalid write happens when
+ an invalid pointer is mistakenly used to initialize a 32bit integer to
+ zero. This is likely to crash the application.
+
+- Fixes for the following vulnerabilities affecting 0.101.1 and 0.101.0 only:
+ - [CVE-2019-1786](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1786):
+ An out-of-bounds heap read condition may occur when scanning malformed PDF
+ documents as a result of improper bounds-checking.
+ - [CVE-2019-1785](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1785):
+ A path-traversal write condition may occur as a result of improper input
+ validation when scanning RAR archives. Issue reported by aCaB.
+ - [CVE-2019-1798](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1798):
+ A use-after-free condition may occur as a result of improper error
+ handling when scanning nested RAR archives. Issue reported by David L.
+
+- Fixes for the following assorted bugs:
+ - Added checks to prevent shifts from causing undefined behavior in HTML
+ normalizer, UPX unpacker, ARJ extractor, CPIO extractor, OLE2 parser,
+ LZW decompressor used in the PDF parser, Xz decompressor, and UTF-16 to
+ ASCII transcoder.
+ - Added checks to prevent integer overflow in UPX unpacker.
+ - Fix for minor memory leak in OLE2 parser.
+ - Fix to speed up PDF parser when handling truncated (or malformed) PDFs.
+ - Fix for memory leak in ARJ decoder failure condition.
+ - Fix for potential memory and file descriptor leak in HTML normalization code.
+
+- Removed use of problematic feature that converted file descriptors to
+ file paths. The feature was intended to improve performance when scanning
+ file types, notably RAR archives, for which the API requires a file path.
+ This feature caused issues in environments where the ClamAV engine is run
+ in a low-permissions or sandboxed process. RAR archives are still supported
+ with this change, but performance may suffer slightly if the file path is not
+ provided in calls to `cl_scandesc_callback()`.
+ - Added filename and tempfile names to scandesc calls in clamd.
+ - Added general scan option `CL_SCAN_GENERAL_UNPRIVILEGED` to treat the scan
+ engine as unprivileged, meaning that the scan engine will not have read
+ access to the file. Provided file paths are for logging purposes only.
+ - Added ability to create a temp file when scanning RAR archives when the
+ process does not have read access to the file path provided (i.e.
+ unprivileged is set, or an access check fails).
+
+Thank you to the Google OSS-Fuzz project for identifying and reporting many of
+the bugs patched in this release.
+
+Additional thanks to the following community members for submitting bug reports:
+
+- aCaB
+- David L.
+
## 0.101.1
ClamAV 0.101.1 is an urgent patch release to address an issue in 0.101.0
@@ -99,18 +170,18 @@
| | `AlertEncryptedArchive` |
| | `AlertEncryptedDoc` |
- | Old `clamscan` option | *New* `clamscan` option |
- | ---------------------------- | -------------------------------- |
- | `--algorithmic-detection` | `--heuristic-alerts` |
- | `--detect-broken` | `--alert-broken` |
- | `--phishing-cloak` | `--alert-phishing-cloak` |
- | `--phishing-ssl` | `--alert-phishing-ssl` |
- | `--partition-intersection` | `--alert-partition-intersection` |
- | `--block-max` | `--alert-exceeds-max` |
- | `--block-macros` | `--alert-macros` |
- | `--block-encrypted` | `--alert-encrypted` |
- | | `--alert-encrypted-archive` |
- | | `--alert-encrypted-doc` |
+ | Old `clamscan` option | *New* `clamscan` option |
+ | -------------------------- | -------------------------------- |
+ | `--algorithmic-detection` | `--heuristic-alerts` |
+ | `--detect-broken` | `--alert-broken` |
+ | `--phishing-cloak` | `--alert-phishing-cloak` |
+ | `--phishing-ssl` | `--alert-phishing-ssl` |
+ | `--partition-intersection` | `--alert-partition-intersection` |
+ | `--block-max` | `--alert-exceeds-max` |
+ | `--block-macros` | `--alert-macros` |
+ | `--block-encrypted` | `--alert-encrypted` |
+ | | `--alert-encrypted-archive` |
+ | | `--alert-encrypted-doc` |
### Some more subtle improvements
diff -Nru clamav-0.101.1+dfsg/sigtool/vba.c clamav-0.101.2+dfsg/sigtool/vba.c
--- clamav-0.101.1+dfsg/sigtool/vba.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/sigtool/vba.c 2019-03-13 22:13:01.000000000 +0100
@@ -1107,8 +1107,10 @@
int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U)
{
- int ret = CL_CLEAN, i, fd, data_len;
- vba_project_t *vba_project;
+ cl_error_t status = CL_CLEAN;
+ cl_error_t ret;
+ int i, fd, data_len;
+ vba_project_t *vba_project = NULL;
DIR *dd;
struct dirent *dent;
STATBUF statbuf;
@@ -1117,14 +1119,22 @@
uint32_t hashcnt;
unsigned int j;
- hashcnt = uniq_get(U, "_vba_project", 12, NULL);
- while(hashcnt--) {
- if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
+ if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) {
+ logg("!ScanDir -> uniq_get('_vba_project') failed.\n");
+ return ret;
+ }
+
+ while (hashcnt) {
+ if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) {
+ hashcnt--;
+ continue;
+ }
for(i = 0; i < vba_project->count; i++) {
for(j = 0; j < vba_project->colls[i]; j++) {
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
vbaname[sizeof(vbaname)-1] = '\0';
+
fd = open(vbaname, O_RDONLY|O_BINARY);
if(fd == -1) continue;
data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
@@ -1139,39 +1149,53 @@
}
}
- free(vba_project->name);
- free(vba_project->colls);
- free(vba_project->dir);
- free(vba_project->offset);
- free(vba_project);
+ cli_free_vba_project(vba_project);
+ vba_project = NULL;
+
+ hashcnt--;
}
+ if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) {
+ logg("!ScanDir -> uniq_get('powerpoint document') failed.\n");
+ return ret;
+ }
- if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
- while(hashcnt--) {
+ while (hashcnt) {
snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname)-1] = '\0';
+
fd = open(vbaname, O_RDONLY|O_BINARY);
- if (fd == -1) continue;
+ if (fd == -1) {
+ hashcnt--;
+ continue;
+ }
if ((fullname = cli_ppt_vba_read(fd, NULL))) {
sigtool_scandir(fullname, hex_output);
cli_rmdirs(fullname);
free(fullname);
}
close(fd);
+ hashcnt--;
}
- }
+ if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) {
+ logg("!ScanDir -> uniq_get('worddocument') failed.\n");
+ return ret;
+ }
- if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
- while(hashcnt--) {
+ while (hashcnt) {
snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
vbaname[sizeof(vbaname)-1] = '\0';
+
fd = open(vbaname, O_RDONLY|O_BINARY);
- if (fd == -1) continue;
+ if (fd == -1) {
+ hashcnt--;
+ continue;
+ }
if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
close(fd);
+ hashcnt--;
continue;
}
@@ -1187,14 +1211,9 @@
}
close(fd);
- free(vba_project->name);
- free(vba_project->colls);
- free(vba_project->dir);
- free(vba_project->offset);
- free(vba_project->key);
- free(vba_project->length);
- free(vba_project);
- }
+ cli_free_vba_project(vba_project);
+ vba_project = NULL;
+ hashcnt--;
}
if ((dd = opendir (dirname)) != NULL) {
@@ -1221,5 +1240,5 @@
closedir (dd);
- return ret;
+ return status;
}
diff -Nru clamav-0.101.1+dfsg/unit_tests/check_clamav.c clamav-0.101.2+dfsg/unit_tests/check_clamav.c
--- clamav-0.101.1+dfsg/unit_tests/check_clamav.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/unit_tests/check_clamav.c 2019-03-13 22:13:01.000000000 +0100
@@ -23,15 +23,16 @@
#include "../libclamav/version.h"
#include "../libclamav/dsig.h"
#include "../libclamav/fpu.h"
+#include "../platform.h"
#include "checks.h"
-static int fpu_words = FPU_ENDIAN_INITME;
+static int fpu_words = FPU_ENDIAN_INITME;
#define NO_FPU_ENDIAN (fpu_words == FPU_ENDIAN_UNKNOWN)
#define EA06_SCAN strstr(file, "clam.ea06.exe")
#define FALSE_NEGATIVE (EA06_SCAN && NO_FPU_ENDIAN)
/* extern void cl_free(struct cl_engine *engine); */
-START_TEST (test_cl_free)
+START_TEST(test_cl_free)
/*
struct cl_engine *engine = NULL;
cl_free(NULL);
@@ -39,16 +40,16 @@
END_TEST
/* extern struct cl_engine *cl_dup(struct cl_engine *engine); */
-START_TEST (test_cl_dup)
- /*
+START_TEST(test_cl_dup)
+/*
struct cl_engine *engine;
fail_unless(NULL == cl_dup(NULL), "cl_dup null pointer");
*/
END_TEST
/* extern int cl_build(struct cl_engine *engine); */
-START_TEST (test_cl_build)
- /*
+START_TEST(test_cl_build)
+/*
struct cl_engine *engine;
fail_unless(CL_ENULLARG == cl_build(NULL), "cl_build null pointer");
engine = calloc(sizeof(struct cl_engine),1);
@@ -59,7 +60,7 @@
END_TEST
/* extern void cl_debug(void); */
-START_TEST (test_cl_debug)
+START_TEST(test_cl_debug)
{
int old_status = cli_debug_flag;
cli_debug_flag = 0;
@@ -74,8 +75,8 @@
END_TEST
/* extern const char *cl_retdbdir(void); */
-START_TEST (test_cl_retdbdir)
- fail_unless(!strcmp(DATADIR, cl_retdbdir()), "cl_retdbdir");
+START_TEST(test_cl_retdbdir)
+fail_unless(!strcmp(DATADIR, cl_retdbdir()), "cl_retdbdir");
END_TEST
#ifndef REPO_VERSION
@@ -83,17 +84,17 @@
#endif
/* extern const char *cl_retver(void); */
-START_TEST (test_cl_retver)
+START_TEST(test_cl_retver)
{
- const char *ver = cl_retver();
- fail_unless(!strcmp(REPO_VERSION""VERSION_SUFFIX, ver),"cl_retver");
- fail_unless(strcspn(ver,"012345789") < strlen(ver),
- "cl_retver must have a number");
+ const char* ver = cl_retver();
+ fail_unless(!strcmp(REPO_VERSION "" VERSION_SUFFIX, ver), "cl_retver");
+ fail_unless(strcspn(ver, "012345789") < strlen(ver),
+ "cl_retver must have a number");
}
END_TEST
/* extern void cl_cvdfree(struct cl_cvd *cvd); */
-START_TEST (test_cl_cvdfree)
+START_TEST(test_cl_cvdfree)
/*
struct cl_cvd *cvd1, *cvd2;
@@ -117,15 +118,15 @@
END_TEST
/* extern int cl_statfree(struct cl_stat *dbstat); */
-START_TEST (test_cl_statfree)
+START_TEST(test_cl_statfree)
/*
struct cl_stat *stat;
fail_unless(CL_ENULLARG == cl_statfree(NULL), "cl_statfree(NULL)");
-
+
stat = malloc(sizeof(struct cl_stat));
fail_unless(NULL != stat, "malloc");
fail_unless(CL_SUCCESS == cl_statfree(stat), "cl_statfree(empty_struct)");
-
+
stat = malloc(sizeof(struct cl_stat));
fail_unless(NULL != stat, "malloc");
stat->stattab = strdup("test");
@@ -140,30 +141,30 @@
END_TEST
/* extern unsigned int cl_retflevel(void); */
-START_TEST (test_cl_retflevel)
-END_TEST
+START_TEST(test_cl_retflevel)
+END_TEST
/* extern struct cl_cvd *cl_cvdhead(const char *file); */
-START_TEST (test_cl_cvdhead)
+START_TEST(test_cl_cvdhead)
/*
fail_unless(NULL == cl_cvdhead(NULL), "cl_cvdhead(null)");
fail_unless(NULL == cl_cvdhead("input/cl_cvdhead/1.txt"), "cl_cvdhead(515 byte file, all nulls)");
*/
- /* the data read from the file is passed to cl_cvdparse, test cases for that are separate */
+/* the data read from the file is passed to cl_cvdparse, test cases for that are separate */
END_TEST
/* extern struct cl_cvd *cl_cvdparse(const char *head); */
-START_TEST (test_cl_cvdparse)
+START_TEST(test_cl_cvdparse)
END_TEST
-static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size);
-static struct cl_engine *g_engine;
+static int get_test_file(int i, char* file, unsigned fsize, unsigned long* size);
+static struct cl_engine* g_engine;
#ifdef CHECK_HAVE_LOOPS
/* int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, struct cl_scan_options* options) */
-START_TEST (test_cl_scandesc)
+START_TEST(test_cl_scandesc)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -178,17 +179,17 @@
ret = cl_scandesc(fd, file, &virname, &scanned, g_engine, &options);
cli_dbgmsg("scan end (scandesc) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
END_TEST
-START_TEST (test_cl_scandesc_allscan)
+START_TEST(test_cl_scandesc_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -205,18 +206,18 @@
cli_dbgmsg("scan end (scandesc) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
END_TEST
//* int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
-START_TEST (test_cl_scanfile)
+START_TEST(test_cl_scanfile)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -233,16 +234,16 @@
ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
cli_dbgmsg("scan end (scanfile) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS , "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
}
END_TEST
-START_TEST (test_cl_scanfile_allscan)
+START_TEST(test_cl_scanfile_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -260,16 +261,16 @@
ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
cli_dbgmsg("scan end (scanfile_allscan) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
}
END_TEST
-START_TEST (test_cl_scanfile_callback)
+START_TEST(test_cl_scanfile_callback)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -287,16 +288,16 @@
ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (scanfile_cb) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
}
END_TEST
-START_TEST (test_cl_scanfile_callback_allscan)
+START_TEST(test_cl_scanfile_callback_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -315,16 +316,16 @@
ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
}
END_TEST
-START_TEST (test_cl_scandesc_callback)
+START_TEST(test_cl_scandesc_callback)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -341,17 +342,17 @@
ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (scandesc_cb) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
END_TEST
-START_TEST (test_cl_scandesc_callback_allscan)
+START_TEST(test_cl_scandesc_callback_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
char file[256];
unsigned long size;
unsigned long int scanned = 0;
@@ -369,9 +370,9 @@
ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (scandesc_cb_allscan) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
@@ -380,30 +381,30 @@
#endif
/* int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options) */
-START_TEST (test_cl_load)
+START_TEST(test_cl_load)
END_TEST
/* int cl_cvdverify(const char *file) */
-START_TEST (test_cl_cvdverify)
+START_TEST(test_cl_cvdverify)
END_TEST
/* int cl_statinidir(const char *dirname, struct cl_stat *dbstat) */
-START_TEST (test_cl_statinidir)
+START_TEST(test_cl_statinidir)
END_TEST
/* int cl_statchkdir(const struct cl_stat *dbstat) */
-START_TEST (test_cl_statchkdir)
+START_TEST(test_cl_statchkdir)
END_TEST
/* void cl_settempdir(const char *dir, short leavetemps) */
-START_TEST (test_cl_settempdir)
+START_TEST(test_cl_settempdir)
END_TEST
/* const char *cl_strerror(int clerror) */
-START_TEST (test_cl_strerror)
+START_TEST(test_cl_strerror)
END_TEST
-static char **testfiles = NULL;
+static char** testfiles = NULL;
static unsigned testfiles_n = 0;
static const int expected_testfiles = 48;
@@ -413,8 +414,8 @@
unsigned skipped = 0;
/* skip .rar files if unrar is disabled */
- const char *s = getenv("unrar_disabled");
- if (s && !strcmp(s, "1")) {
+ const char* s = getenv("unrar_disabled");
+ if(s && !strcmp(s, "1")) {
skipped += 2;
}
@@ -435,26 +436,26 @@
static void init_testfiles(void)
{
- struct dirent *dirent;
+ struct dirent* dirent;
unsigned i = 0;
int expect = expected_testfiles;
- DIR *d = opendir(OBJDIR"/../test");
+ DIR* d = opendir(OBJDIR "/../test");
fail_unless(!!d, "opendir");
- if (!d)
- return;
- testfiles = NULL;
+ if(!d)
+ return;
+ testfiles = NULL;
testfiles_n = 0;
- while ((dirent = readdir(d))) {
- if (strncmp(dirent->d_name, "clam", 4))
- continue;
+ while((dirent = readdir(d))) {
+ if(strncmp(dirent->d_name, "clam", 4))
+ continue;
i++;
- testfiles = cli_realloc(testfiles, i*sizeof(*testfiles));
- fail_unless(!!testfiles, "cli_realloc");
- testfiles[i-1] = strdup(dirent->d_name);
+ testfiles = cli_realloc(testfiles, i * sizeof(*testfiles));
+ fail_unless(!!testfiles, "cli_realloc");
+ testfiles[i - 1] = strdup(dirent->d_name);
}
testfiles_n = i;
- if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
+ if(get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
expect--;
expect -= skip_files();
fail_unless_fmt(testfiles_n == expect, "testfiles: %d != %d", testfiles_n, expect);
@@ -465,11 +466,11 @@
static void free_testfiles(void)
{
unsigned i;
- for (i=0;i<testfiles_n;i++) {
- free(testfiles[i]);
+ for(i = 0; i < testfiles_n; i++) {
+ free(testfiles[i]);
}
free(testfiles);
- testfiles = NULL;
+ testfiles = NULL;
testfiles_n = 0;
}
@@ -478,12 +479,12 @@
static void engine_setup(void)
{
unsigned int sigs = 0;
- const char *hdb = OBJDIR"/clamav.hdb";
+ const char* hdb = OBJDIR "/clamav.hdb";
init_testfiles();
- if (!inited)
- fail_unless(cl_init(CL_INIT_DEFAULT) == 0, "cl_init");
- inited = 1;
+ if(!inited)
+ fail_unless(cl_init(CL_INIT_DEFAULT) == 0, "cl_init");
+ inited = 1;
g_engine = cl_engine_new();
fail_unless(!!g_engine, "engine");
fail_unless_fmt(cl_load(hdb, g_engine, &sigs, CL_DB_STDOPT) == 0, "cl_load %s", hdb);
@@ -497,13 +498,13 @@
cl_engine_free(g_engine);
}
-static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size)
+static int get_test_file(int i, char* file, unsigned fsize, unsigned long* size)
{
int fd;
STATBUF st;
fail_unless(i < testfiles_n, "%i < %i %s", i, testfiles_n, file);
- snprintf(file, fsize, OBJDIR"/../test/%s", testfiles[i]);
+ snprintf(file, fsize, OBJDIR "/../test/%s", testfiles[i]);
fd = open(file, O_RDONLY);
fail_unless(fd > 0, "open");
@@ -513,16 +514,16 @@
}
#ifdef CHECK_HAVE_LOOPS
-static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
+static off_t pread_cb(void* handle, void* buf, size_t count, off_t offset)
{
return pread(*((int*)handle), buf, count, offset);
}
-START_TEST (test_cl_scanmap_callback_handle)
+START_TEST(test_cl_scanmap_callback_handle)
{
- const char *virname = NULL;
+ const char* virname = NULL;
unsigned long int scanned = 0;
- cl_fmap_t *map;
+ cl_fmap_t* map;
int ret;
char file[256];
unsigned long size;
@@ -540,19 +541,19 @@
ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (handle) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
END_TEST
-START_TEST (test_cl_scanmap_callback_handle_allscan)
+START_TEST(test_cl_scanmap_callback_handle_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
unsigned long int scanned = 0;
- cl_fmap_t *map;
+ cl_fmap_t* map;
int ret;
char file[256];
unsigned long size;
@@ -571,21 +572,21 @@
ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (handle) allscan %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
}
close(fd);
}
END_TEST
-START_TEST (test_cl_scanmap_callback_mem)
+START_TEST(test_cl_scanmap_callback_mem)
{
- const char *virname = NULL;
+ const char* virname = NULL;
unsigned long int scanned = 0;
- cl_fmap_t *map;
+ cl_fmap_t* map;
int ret;
- void *mem;
+ void* mem;
unsigned long size;
char file[256];
struct cl_scan_options options;
@@ -605,9 +606,9 @@
cli_dbgmsg("scanning (mem) %s\n", file);
ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (mem) %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
}
close(fd);
cl_fmap_close(map);
@@ -616,13 +617,13 @@
}
END_TEST
-START_TEST (test_cl_scanmap_callback_mem_allscan)
+START_TEST(test_cl_scanmap_callback_mem_allscan)
{
- const char *virname = NULL;
+ const char* virname = NULL;
unsigned long int scanned = 0;
- cl_fmap_t *map;
+ cl_fmap_t* map;
int ret;
- void *mem;
+ void* mem;
unsigned long size;
char file[256];
struct cl_scan_options options;
@@ -643,9 +644,9 @@
cli_dbgmsg("scanning (mem) allscan %s\n", file);
ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
cli_dbgmsg("scan end (mem) allscan %s\n", file);
- if (!FALSE_NEGATIVE) {
- fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
- fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
+ if(!FALSE_NEGATIVE) {
+ fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
+ fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
}
close(fd);
cl_fmap_close(map);
@@ -654,14 +655,14 @@
END_TEST
#endif
-static Suite *test_cl_suite(void)
+static Suite* test_cl_suite(void)
{
- Suite *s = suite_create("cl_api");
- TCase *tc_cl = tcase_create("cl_dup");
- TCase *tc_cl_scan = tcase_create("cl_scan");
- char *user_timeout = NULL;
- int expect = expected_testfiles;
- suite_add_tcase (s, tc_cl);
+ Suite* s = suite_create("cl_api");
+ TCase* tc_cl = tcase_create("cl_dup");
+ TCase* tc_cl_scan = tcase_create("cl_scan");
+ char* user_timeout = NULL;
+ int expect = expected_testfiles;
+ suite_add_tcase(s, tc_cl);
tcase_add_test(tc_cl, test_cl_free);
tcase_add_test(tc_cl, test_cl_dup);
tcase_add_test(tc_cl, test_cl_build);
@@ -681,9 +682,9 @@
tcase_add_test(tc_cl, test_cl_strerror);
suite_add_tcase(s, tc_cl_scan);
- tcase_add_checked_fixture (tc_cl_scan, engine_setup, engine_teardown);
+ tcase_add_checked_fixture(tc_cl_scan, engine_setup, engine_teardown);
#ifdef CHECK_HAVE_LOOPS
- if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
+ if(get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
expect--;
expect -= skip_files();
tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expect);
@@ -700,307 +701,402 @@
tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect);
user_timeout = getenv("T");
- if (user_timeout) {
+ if(user_timeout) {
int timeout = atoi(user_timeout);
tcase_set_timeout(tc_cl_scan, timeout);
- printf("Using test case timeout of %d seconds set by user\n", timeout);
+ printf("Using test case timeout of %d seconds set by user\n", timeout);
} else {
- printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
+ printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
}
#endif
return s;
}
-static uint8_t le_data[4] = {0x67,0x45,0x23,0x01};
-static int32_t le_expected[4] = { 0x01234567, 0x67012345, 0x45670123, 0x23456701};
-uint8_t *data = NULL;
-uint8_t *data2 = NULL;
+static uint8_t le_data[4] = {0x67, 0x45, 0x23, 0x01};
+static int32_t le_expected[4] = {0x01234567, 0x67012345, 0x45670123, 0x23456701};
+uint8_t* data = NULL;
+uint8_t* data2 = NULL;
#define DATA_REP 100
static void data_setup(void)
{
- uint8_t *p;
- size_t i;
+ uint8_t* p;
+ size_t i;
- data = malloc(sizeof(le_data)*DATA_REP);
- data2 = malloc(sizeof(le_data)*DATA_REP);
- fail_unless(!!data, "unable to allocate memory for fixture");
- fail_unless(!!data2, "unable to allocate memory for fixture");
- p = data;
- /* make multiple copies of le_data, we need to run readint tests in a loop, so we need
+ data = malloc(sizeof(le_data) * DATA_REP);
+ data2 = malloc(sizeof(le_data) * DATA_REP);
+ fail_unless(!!data, "unable to allocate memory for fixture");
+ fail_unless(!!data2, "unable to allocate memory for fixture");
+ p = data;
+ /* make multiple copies of le_data, we need to run readint tests in a loop, so we need
* to give it some data to run it on */
- for(i=0; i<DATA_REP;i++) {
- memcpy(p, le_data, sizeof(le_data));
- p += sizeof(le_data);
- }
- memset(data2, 0, DATA_REP*sizeof(le_data));
+ for(i = 0; i < DATA_REP; i++) {
+ memcpy(p, le_data, sizeof(le_data));
+ p += sizeof(le_data);
+ }
+ memset(data2, 0, DATA_REP * sizeof(le_data));
}
static void data_teardown(void)
{
- free(data);
- free(data2);
+ free(data);
+ free(data2);
}
#ifdef CHECK_HAVE_LOOPS
/* test reading with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_readint16)
+START_TEST(test_cli_readint16)
{
size_t j;
int16_t value;
/* read 2 bytes apart, start is not always aligned*/
- for(j=_i;j <= DATA_REP*sizeof(le_data)-2;j += 2) {
- value = le_expected[j&3];
+ for(j = _i; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
+ value = le_expected[j & 3];
fail_unless(cli_readint16(&data[j]) == value, "(1) data read must be little endian");
}
/* read 2 bytes apart, always aligned*/
- for(j=0;j <= DATA_REP*sizeof(le_data)-2;j += 2) {
- value = le_expected[j&3];
+ for(j = 0; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
+ value = le_expected[j & 3];
fail_unless(cli_readint16(&data[j]) == value, "(2) data read must be little endian");
}
}
END_TEST
/* test reading with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_readint32)
+START_TEST(test_cli_readint32)
{
size_t j;
- int32_t value = le_expected[_i&3];
+ int32_t value = le_expected[_i & 3];
/* read 4 bytes apart, start is not always aligned*/
- for(j=_i;j < DATA_REP*sizeof(le_data)-4;j += 4) {
+ for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
fail_unless(cli_readint32(&data[j]) == value, "(1) data read must be little endian");
}
value = le_expected[0];
/* read 4 bytes apart, always aligned*/
- for(j=0;j < DATA_REP*sizeof(le_data)-4;j += 4) {
+ for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
fail_unless(cli_readint32(&data[j]) == value, "(2) data read must be little endian");
}
}
END_TEST
/* test writing with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_writeint32)
+START_TEST(test_cli_writeint32)
{
size_t j;
/* write 4 bytes apart, start is not always aligned*/
- for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+ for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
cli_writeint32(&data2[j], 0x12345678);
}
- for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+ for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
}
/* write 4 bytes apart, always aligned*/
- for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+ for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
cli_writeint32(&data2[j], 0x12345678);
}
- for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+ for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
}
}
END_TEST
static struct dsig_test {
- const char *md5;
- const char *dsig;
+ const char* md5;
+ const char* dsig;
int result;
-} dsig_tests [] = {
- {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
- CL_SUCCESS},
+} dsig_tests[] = {
+ {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
+ CL_SUCCESS},
{"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
- CL_SUCCESS},
+ CL_SUCCESS},
{"ae307614434715274c60854c931a26de", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
- CL_EVERIFY},
+ CL_EVERIFY},
{"96b7feb3b2a863846438809fe481906f", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
- CL_EVERIFY},
+ CL_EVERIFY},
{"ae307614434715274060854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
- CL_EVERIFY},
+ CL_EVERIFY},
{"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaatinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
- CL_EVERIFY},
+ CL_EVERIFY},
{"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MYYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
- CL_EVERIFY},
- {"ge307614434715274c60854c931a26dee","60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
- CL_EVERIFY},
- {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGee",
- CL_EVERIFY},
- {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+",
- CL_EVERIFY}
-};
+ CL_EVERIFY},
+ {"ge307614434715274c60854c931a26dee", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
+ CL_EVERIFY},
+ {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGee",
+ CL_EVERIFY},
+ {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+",
+ CL_EVERIFY}};
-static const size_t dsig_tests_cnt = sizeof(dsig_tests)/sizeof(dsig_tests[0]);
+static const size_t dsig_tests_cnt = sizeof(dsig_tests) / sizeof(dsig_tests[0]);
-START_TEST (test_cli_dsig)
+START_TEST(test_cli_dsig)
{
fail_unless(cli_versig(dsig_tests[_i].md5, dsig_tests[_i].dsig) == dsig_tests[_i].result,
- "digital signature verification test failed");
+ "digital signature verification test failed");
}
END_TEST
static uint8_t tv1[3] = {
- 0x61, 0x62, 0x63
-};
+ 0x61, 0x62, 0x63};
static uint8_t tv2[56] = {
- 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
- 0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
- 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
- 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b,
- 0x69, 0x6a, 0x6b, 0x6c, 0x6a, 0x6b, 0x6c, 0x6d,
- 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71
-};
+ 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
+ 0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
+ 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
+ 0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6a, 0x6b, 0x6c, 0x6d,
+ 0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71};
static uint8_t res256[3][SHA256_HASH_SIZE] = {
- { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
- 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
- 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad },
- { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
- 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
- 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 },
- { 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2,
- 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
- 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 }
-};
+ {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+ 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
+ {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
+ 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
+ {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2,
+ 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
+ 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
-START_TEST (test_sha256)
+START_TEST(test_sha256)
{
- void *sha256;
+ void* sha256;
uint8_t hsha256[SHA256_HASH_SIZE];
uint8_t buf[1000];
int i;
- memset (buf, 0x61, sizeof (buf));
+ memset(buf, 0x61, sizeof(buf));
cl_sha256(tv1, sizeof(tv1), hsha256, NULL);
- fail_unless(!memcmp (hsha256, res256[0], sizeof (hsha256)), "sha256 test vector #1 failed");
+ fail_unless(!memcmp(hsha256, res256[0], sizeof(hsha256)), "sha256 test vector #1 failed");
cl_sha256(tv2, sizeof(tv2), hsha256, NULL);
- fail_unless(!memcmp (hsha256, res256[1], sizeof (hsha256)), "sha256 test vector #2 failed");
+ fail_unless(!memcmp(hsha256, res256[1], sizeof(hsha256)), "sha256 test vector #2 failed");
sha256 = cl_hash_init("sha256");
fail_unless(sha256 != NULL, "Could not create EVP_MD_CTX for sha256");
- for (i = 0; i < 1000; i++)
- cl_update_hash (sha256, buf, sizeof (buf));
+ for(i = 0; i < 1000; i++)
+ cl_update_hash(sha256, buf, sizeof(buf));
cl_finish_hash(sha256, hsha256);
- fail_unless(!memcmp (hsha256, res256[2], sizeof (hsha256)), "sha256 test vector #3 failed");
+ fail_unless(!memcmp(hsha256, res256[2], sizeof(hsha256)), "sha256 test vector #3 failed");
}
END_TEST
-static Suite *test_cli_suite(void)
+START_TEST(test_sanitize_path)
{
- Suite *s = suite_create("cli");
- TCase *tc_cli_others = tcase_create("byteorder_macros");
- TCase *tc_cli_dsig = tcase_create("digital signatures");
+ char* sanitized = NULL;
+ const char* unsanitized = NULL;
+
+ unsanitized = "";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL != sanitized, "sanitize_path: Empty path test failed");
+
+ unsanitized = NULL;
+ sanitized = cli_sanitize_filepath(unsanitized, 0);
+ fail_if(NULL != sanitized, "sanitize_path: NULL path #1 test failed");
+
+ unsanitized = NULL;
+ sanitized = cli_sanitize_filepath(unsanitized, 50);
+ fail_if(NULL != sanitized, "sanitize_path: NULL path #2 test failed");
+
+ unsanitized = "badlen";
+ sanitized = cli_sanitize_filepath(unsanitized, 0);
+ fail_if(NULL != sanitized, "sanitize_path: Zero/bad path length test failed");
+
+ unsanitized = ".." PATHSEP;
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL");
+
+ unsanitized = "." PATHSEP;
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (2)");
+
+ unsanitized = PATHSEP;
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (3)");
+
+ unsanitized = ".." PATHSEP "relative_bad_1";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative_bad_1"), "sanitize_path: bad relative path test #1 failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP ".." PATHSEP "good";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "good"), "sanitize_path: good relative path test failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP ".." PATHSEP ".." PATHSEP "bad_2";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_2"), "sanitize_path: bad relative path test failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP "." PATHSEP ".." PATHSEP ".." PATHSEP "bad_current";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_current"), "sanitize_path: bad relative current path test failed");
+ free(sanitized);
+
+ unsanitized = "relative/../../bad_win_posix_path";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative/../bad_win_posix_path"), "sanitize_path: bad relative win posix path test failed");
+ free(sanitized);
+
+ unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP ".." PATHSEP "bad";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "bad"), "sanitize_path: bad absolute path test failed");
+ free(sanitized);
+
+ unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP "good";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "good"), "sanitize_path: good absolute path test failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP "normal";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP "normal"), "sanitize_path: relative normal path test failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP PATHSEP "doublesep";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP "doublesep"), "sanitize_path: relative double sep path test failed");
+ free(sanitized);
+
+ unsanitized = "relative" PATHSEP "shortname" PATHSEP "1";
+ sanitized = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+ fail_if(NULL == sanitized);
+ fail_unless(!strcmp(sanitized, "relative" PATHSEP "shortname" PATHSEP "1"), "sanitize_path: relative short name path test failed");
+ free(sanitized);
+}
+END_TEST
+
+static Suite* test_cli_suite(void)
+{
+ Suite* s = suite_create("cli");
+ TCase* tc_cli_others = tcase_create("byteorder_macros");
+ TCase* tc_cli_dsig = tcase_create("digital signatures");
+ TCase* tc_cli_assorted = tcase_create("assorted functions");
- suite_add_tcase (s, tc_cli_others);
- tcase_add_checked_fixture (tc_cli_others, data_setup, data_teardown);
+ suite_add_tcase(s, tc_cli_others);
+ tcase_add_checked_fixture(tc_cli_others, data_setup, data_teardown);
tcase_add_loop_test(tc_cli_others, test_cli_readint32, 0, 16);
tcase_add_loop_test(tc_cli_others, test_cli_readint16, 0, 16);
tcase_add_loop_test(tc_cli_others, test_cli_writeint32, 0, 16);
- suite_add_tcase (s, tc_cli_dsig);
+ suite_add_tcase(s, tc_cli_dsig);
tcase_add_loop_test(tc_cli_dsig, test_cli_dsig, 0, dsig_tests_cnt);
tcase_add_test(tc_cli_dsig, test_sha256);
+ suite_add_tcase(s, tc_cli_assorted);
+ tcase_add_test(tc_cli_assorted, test_sanitize_path);
+
return s;
}
#endif /* CHECK_HAVE_LOOPS */
void errmsg_expected(void)
{
- fputs("cli_errmsg() expected here\n", stderr);
+ fputs("cli_errmsg() expected here\n", stderr);
}
-int open_testfile(const char *name)
+int open_testfile(const char* name)
{
- int fd;
- const char * srcdir = getenv("srcdir");
- char *str;
-
- if(!srcdir) {
- /* when run from automake srcdir is set, but if run manually then not */
- srcdir = SRCDIR;
- }
-
- str = cli_malloc(strlen(name)+strlen(srcdir)+2);
- fail_unless(!!str, "cli_malloc");
- sprintf(str, "%s/%s", srcdir, name);
-
- fd = open(str, O_RDONLY);
- fail_unless_fmt(fd >= 0, "open() failed: %s", str);
- free(str);
- return fd;
-}
-
-void diff_file_mem(int fd, const char *ref, size_t len)
-{
- char c1,c2;
- size_t p, reflen = len;
- char *buf = cli_malloc(len);
-
- fail_unless_fmt(!!buf, "unable to malloc buffer: %d", len);
- p = read(fd, buf, len);
- fail_unless_fmt(p == len, "file is smaller: %lu, expected: %lu", p, len);
- p = 0;
- while(len > 0) {
- c1 = ref[p];
- c2 = buf[p];
- if(c1 != c2)
- break;
- p++;
- len--;
- }
- if (len > 0)
- fail_unless_fmt(c1 == c2, "file contents mismatch at byte: %lu, was: %c, expected: %c", p, c2, c1);
- free(buf);
- p = lseek(fd, 0, SEEK_END);
- fail_unless_fmt(p == reflen, "trailing garbage, file size: %ld, expected: %ld", p, reflen);
- close(fd);
+ int fd;
+ const char* srcdir = getenv("srcdir");
+ char* str;
+
+ if(!srcdir) {
+ /* when run from automake srcdir is set, but if run manually then not */
+ srcdir = SRCDIR;
+ }
+
+ str = cli_malloc(strlen(name) + strlen(srcdir) + 2);
+ fail_unless(!!str, "cli_malloc");
+ sprintf(str, "%s/%s", srcdir, name);
+
+ fd = open(str, O_RDONLY);
+ fail_unless_fmt(fd >= 0, "open() failed: %s", str);
+ free(str);
+ return fd;
+}
+
+void diff_file_mem(int fd, const char* ref, size_t len)
+{
+ char c1, c2;
+ size_t p, reflen = len;
+ char* buf = cli_malloc(len);
+
+ fail_unless_fmt(!!buf, "unable to malloc buffer: %d", len);
+ p = read(fd, buf, len);
+ fail_unless_fmt(p == len, "file is smaller: %lu, expected: %lu", p, len);
+ p = 0;
+ while(len > 0) {
+ c1 = ref[p];
+ c2 = buf[p];
+ if(c1 != c2)
+ break;
+ p++;
+ len--;
+ }
+ if(len > 0)
+ fail_unless_fmt(c1 == c2, "file contents mismatch at byte: %lu, was: %c, expected: %c", p, c2, c1);
+ free(buf);
+ p = lseek(fd, 0, SEEK_END);
+ fail_unless_fmt(p == reflen, "trailing garbage, file size: %ld, expected: %ld", p, reflen);
+ close(fd);
}
void diff_files(int fd, int ref_fd)
{
- char *ref;
- ssize_t nread;
- off_t siz = lseek(ref_fd, 0, SEEK_END);
- fail_unless_fmt(siz != -1, "lseek failed");
-
- ref = cli_malloc(siz);
- fail_unless_fmt(!!ref, "unable to malloc buffer: %d", siz);
-
- fail_unless_fmt(lseek(ref_fd, 0, SEEK_SET) == 0,"lseek failed");
- nread = read(ref_fd, ref, siz);
- fail_unless_fmt(nread == siz, "short read, expected: %ld, was: %ld", siz, nread);
- close(ref_fd);
- diff_file_mem(fd, ref, siz);
- free(ref);
+ char* ref;
+ ssize_t nread;
+ off_t siz = lseek(ref_fd, 0, SEEK_END);
+ fail_unless_fmt(siz != -1, "lseek failed");
+
+ ref = cli_malloc(siz);
+ fail_unless_fmt(!!ref, "unable to malloc buffer: %d", siz);
+
+ fail_unless_fmt(lseek(ref_fd, 0, SEEK_SET) == 0, "lseek failed");
+ nread = read(ref_fd, ref, siz);
+ fail_unless_fmt(nread == siz, "short read, expected: %ld, was: %ld", siz, nread);
+ close(ref_fd);
+ diff_file_mem(fd, ref, siz);
+ free(ref);
}
#ifdef USE_MPOOL
-static mpool_t *pool;
+static mpool_t* pool;
#else
-static void *pool;
+static void* pool;
#endif
-struct cli_dconf *dconf;
+struct cli_dconf* dconf;
void dconf_setup(void)
{
- pool = NULL;
- dconf = NULL;
+ pool = NULL;
+ dconf = NULL;
#ifdef USE_MPOOL
- pool = mpool_create();
- fail_unless(!!pool, "unable to create pool");
+ pool = mpool_create();
+ fail_unless(!!pool, "unable to create pool");
#endif
- dconf = cli_mpool_dconf_init(pool);
- fail_unless(!!dconf, "failed to init dconf");
+ dconf = cli_mpool_dconf_init(pool);
+ fail_unless(!!dconf, "failed to init dconf");
}
void dconf_teardown(void)
{
- mpool_free(pool, dconf);
+ mpool_free(pool, dconf);
#ifdef USE_MPOOL
- if (pool)
- mpool_destroy(pool);
+ if(pool)
+ mpool_destroy(pool);
#endif
}
@@ -1009,35 +1105,35 @@
/* check 0.9.8 is not ABI compatible with 0.9.6,
* if by accident you compile with check 0.9.6 header
* and link with 0.9.8 then check will hang/crash. */
- if ((check_major_version != CHECK_MAJOR_VERSION) ||
- (check_minor_version != CHECK_MINOR_VERSION) ||
- (check_micro_version != CHECK_MICRO_VERSION)) {
- fprintf(stderr, "ERROR: check version mismatch!\n"
- "\tVersion from header: %u.%u.%u\n"
- "\tVersion from library: %u.%u.%u\n"
- "\tMake sure check.h and -lcheck are same version!\n",
- CHECK_MAJOR_VERSION,
- CHECK_MINOR_VERSION,
- CHECK_MICRO_VERSION,
- check_major_version,
- check_minor_version,
- check_micro_version);
- exit(EXIT_FAILURE);
+ if((check_major_version != CHECK_MAJOR_VERSION) ||
+ (check_minor_version != CHECK_MINOR_VERSION) ||
+ (check_micro_version != CHECK_MICRO_VERSION)) {
+ fprintf(stderr, "ERROR: check version mismatch!\n"
+ "\tVersion from header: %u.%u.%u\n"
+ "\tVersion from library: %u.%u.%u\n"
+ "\tMake sure check.h and -lcheck are same version!\n",
+ CHECK_MAJOR_VERSION,
+ CHECK_MINOR_VERSION,
+ CHECK_MICRO_VERSION,
+ check_major_version,
+ check_minor_version,
+ check_micro_version);
+ exit(EXIT_FAILURE);
}
}
int main(void)
{
int nf;
- Suite *s;
- SRunner *sr;
+ Suite* s;
+ SRunner* sr;
cl_initialize_crypto();
- fpu_words = get_fpu_endian();
-
+ fpu_words = get_fpu_endian();
+
check_version_compatible();
- s = test_cl_suite();
+ s = test_cl_suite();
sr = srunner_create(s);
#ifdef CHECK_HAVE_LOOPS
srunner_add_suite(sr, test_cli_suite());
@@ -1053,17 +1149,16 @@
srunner_add_suite(sr, test_htmlnorm_suite());
srunner_add_suite(sr, test_bytecode_suite());
-
srunner_set_log(sr, "test.log");
- if(freopen("test-stderr.log","w+",stderr) == NULL) {
- fputs("Unable to redirect stderr!\n",stderr);
+ if(freopen("test-stderr.log", "w+", stderr) == NULL) {
+ fputs("Unable to redirect stderr!\n", stderr);
}
cl_debug();
srunner_run_all(sr, CK_NORMAL);
nf = srunner_ntests_failed(sr);
- if (nf)
- printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
+ if(nf)
+ printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
srunner_free(sr);
#if HAVE_LIBXML2
diff -Nru clamav-0.101.1+dfsg/unit_tests/check_uniq.c clamav-0.101.2+dfsg/unit_tests/check_uniq.c
--- clamav-0.101.1+dfsg/unit_tests/check_uniq.c 2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/unit_tests/check_uniq.c 2019-03-13 22:13:01.000000000 +0100
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
+#include "../libclamav/clamav.h"
#include "../libclamav/uniq.h"
#include "checks.h"
@@ -59,12 +60,16 @@
fail_unless(U!=0, "uniq_init");
for(i=0; tests[i].expected; i++) {
- u = uniq_add(U, tests[i].key, tests[i].key_len, &hash);
- fail_unless_fmt(u==0 && strcmp(hash, tests[i].expected)==0, "uniq_add(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
+ if (CL_SUCCESS != uniq_add(U, tests[i].key, tests[i].key_len, &hash, &u)) {
+ fail("uniq_add(%s) failed.", tests[i].key);
+ }
+ fail_unless_fmt(u == 1 && strcmp(hash, tests[i].expected) == 0, "uniq_add(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
}
for(i=0; tests[i].expected; i++) {
- u = uniq_get(U, tests[i].key, tests[i].key_len, &hash);
+ if (CL_SUCCESS != uniq_get(U, tests[i].key, tests[i].key_len, &hash, &u)) {
+ fail("uniq_get(%s) failed.", tests[i].key);
+ }
fail_unless_fmt(u==1 && strcmp(hash, tests[i].expected)==0, "uniq_get(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
}
@@ -82,11 +87,16 @@
fail_unless(U!=0, "uniq_init");
for(j=4; j>0; j--)
- for (i=0; i<j; i++)
- u = uniq_add(U, tests[i], strlen(tests[i]), NULL);
+ for (i = 0; i < j; i++) {
+ if (CL_SUCCESS != uniq_add(U, tests[i], strlen(tests[i]), NULL, &u)) {
+ fail("uniq_add(%s) failed.", tests[i]);
+ }
+ }
for (i=0; i<4; i++) {
- u = uniq_add(U, tests[i], strlen(tests[i]), NULL);
+ if (CL_SUCCESS != uniq_get(U, tests[i], strlen(tests[i]), NULL, &u)) {
+ fail("uniq_get(%s) failed.", tests[i]);
+ }
fail_unless_fmt(u+i==4, "uniq_get(%s) = %u - expected %u", tests[i], u, 4-i);
}
More information about the Pkg-clamav-devel
mailing list